AlarmManagerService.java revision 2ff5a73c3c39d144ef4195928000d5666d04c947
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.ActivityManager; 21import android.app.ActivityManagerNative; 22import android.app.AlarmManager; 23import android.app.IAlarmManager; 24import android.app.PendingIntent; 25import android.content.BroadcastReceiver; 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.provider.Settings; 42import android.text.TextUtils; 43import android.text.format.DateFormat; 44import android.util.ArrayMap; 45import android.util.Log; 46import android.util.Slog; 47import android.util.SparseArray; 48import android.util.SparseBooleanArray; 49import android.util.TimeUtils; 50 51import java.io.ByteArrayOutputStream; 52import java.io.FileDescriptor; 53import java.io.PrintWriter; 54import java.text.SimpleDateFormat; 55import java.util.ArrayList; 56import java.util.Arrays; 57import java.util.Calendar; 58import java.util.Collections; 59import java.util.Comparator; 60import java.util.Date; 61import java.util.LinkedList; 62import java.util.Locale; 63import java.util.TimeZone; 64 65import static android.app.AlarmManager.RTC_WAKEUP; 66import static android.app.AlarmManager.RTC; 67import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP; 68import static android.app.AlarmManager.ELAPSED_REALTIME; 69 70import com.android.internal.util.LocalLog; 71 72class AlarmManagerService extends SystemService { 73 // The threshold for how long an alarm can be late before we print a 74 // warning message. The time duration is in milliseconds. 75 private static final long LATE_ALARM_THRESHOLD = 10 * 1000; 76 77 private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP; 78 private static final int RTC_MASK = 1 << RTC; 79 private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; 80 private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME; 81 static final int TIME_CHANGED_MASK = 1 << 16; 82 static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK; 83 84 // Mask for testing whether a given alarm type is wakeup vs non-wakeup 85 static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup 86 87 static final String TAG = "AlarmManager"; 88 static final String ClockReceiver_TAG = "ClockReceiver"; 89 static final boolean localLOGV = false; 90 static final boolean DEBUG_BATCH = localLOGV || false; 91 static final boolean DEBUG_VALIDATE = localLOGV || false; 92 static final boolean DEBUG_ALARM_CLOCK = localLOGV || false; 93 static final int ALARM_EVENT = 1; 94 static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; 95 96 static final Intent mBackgroundIntent 97 = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND); 98 static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder(); 99 100 static final boolean WAKEUP_STATS = false; 101 102 private static final Intent NEXT_ALARM_CLOCK_CHANGED_INTENT = new Intent( 103 AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); 104 105 final LocalLog mLog = new LocalLog(TAG); 106 107 final Object mLock = new Object(); 108 109 long mNativeData; 110 private long mNextWakeup; 111 private long mNextNonWakeup; 112 int mBroadcastRefCount = 0; 113 PowerManager.WakeLock mWakeLock; 114 boolean mLastWakeLockUnimportantForLogging; 115 ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<Alarm>(); 116 ArrayList<InFlight> mInFlight = new ArrayList<InFlight>(); 117 final AlarmHandler mHandler = new AlarmHandler(); 118 ClockReceiver mClockReceiver; 119 InteractiveStateReceiver mInteractiveStateReceiver; 120 private UninstallReceiver mUninstallReceiver; 121 final ResultReceiver mResultReceiver = new ResultReceiver(); 122 PendingIntent mTimeTickSender; 123 PendingIntent mDateChangeSender; 124 boolean mInteractive = true; 125 long mNonInteractiveStartTime; 126 long mNonInteractiveTime; 127 long mLastAlarmDeliveryTime; 128 long mStartCurrentDelayTime; 129 long mNextNonWakeupDeliveryTime; 130 int mNumTimeChanged; 131 132 private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser = 133 new SparseArray<>(); 134 private final SparseArray<AlarmManager.AlarmClockInfo> mTmpSparseAlarmClockArray = 135 new SparseArray<>(); 136 private final SparseBooleanArray mPendingSendNextAlarmClockChangedForUser = 137 new SparseBooleanArray(); 138 private boolean mNextAlarmClockMayChange; 139 140 // May only use on mHandler's thread, locking not required. 141 private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray = 142 new SparseArray<>(); 143 144 class WakeupEvent { 145 public long when; 146 public int uid; 147 public String action; 148 149 public WakeupEvent(long theTime, int theUid, String theAction) { 150 when = theTime; 151 uid = theUid; 152 action = theAction; 153 } 154 } 155 156 final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>(); 157 final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day 158 159 final class Batch { 160 long start; // These endpoints are always in ELAPSED 161 long end; 162 boolean standalone; // certain "batches" don't participate in coalescing 163 164 final ArrayList<Alarm> alarms = new ArrayList<Alarm>(); 165 166 Batch() { 167 start = 0; 168 end = Long.MAX_VALUE; 169 } 170 171 Batch(Alarm seed) { 172 start = seed.whenElapsed; 173 end = seed.maxWhen; 174 alarms.add(seed); 175 } 176 177 int size() { 178 return alarms.size(); 179 } 180 181 Alarm get(int index) { 182 return alarms.get(index); 183 } 184 185 boolean canHold(long whenElapsed, long maxWhen) { 186 return (end >= whenElapsed) && (start <= maxWhen); 187 } 188 189 boolean add(Alarm alarm) { 190 boolean newStart = false; 191 // narrows the batch if necessary; presumes that canHold(alarm) is true 192 int index = Collections.binarySearch(alarms, alarm, sIncreasingTimeOrder); 193 if (index < 0) { 194 index = 0 - index - 1; 195 } 196 alarms.add(index, alarm); 197 if (DEBUG_BATCH) { 198 Slog.v(TAG, "Adding " + alarm + " to " + this); 199 } 200 if (alarm.whenElapsed > start) { 201 start = alarm.whenElapsed; 202 newStart = true; 203 } 204 if (alarm.maxWhen < end) { 205 end = alarm.maxWhen; 206 } 207 208 if (DEBUG_BATCH) { 209 Slog.v(TAG, " => now " + this); 210 } 211 return newStart; 212 } 213 214 boolean remove(final PendingIntent operation) { 215 boolean didRemove = false; 216 long newStart = 0; // recalculate endpoints as we go 217 long newEnd = Long.MAX_VALUE; 218 for (int i = 0; i < alarms.size(); ) { 219 Alarm alarm = alarms.get(i); 220 if (alarm.operation.equals(operation)) { 221 alarms.remove(i); 222 didRemove = true; 223 if (alarm.alarmClock != null) { 224 mNextAlarmClockMayChange = true; 225 } 226 } else { 227 if (alarm.whenElapsed > newStart) { 228 newStart = alarm.whenElapsed; 229 } 230 if (alarm.maxWhen < newEnd) { 231 newEnd = alarm.maxWhen; 232 } 233 i++; 234 } 235 } 236 if (didRemove) { 237 // commit the new batch bounds 238 start = newStart; 239 end = newEnd; 240 } 241 return didRemove; 242 } 243 244 boolean remove(final String packageName) { 245 boolean didRemove = false; 246 long newStart = 0; // recalculate endpoints as we go 247 long newEnd = Long.MAX_VALUE; 248 for (int i = 0; i < alarms.size(); ) { 249 Alarm alarm = alarms.get(i); 250 if (alarm.operation.getTargetPackage().equals(packageName)) { 251 alarms.remove(i); 252 didRemove = true; 253 if (alarm.alarmClock != null) { 254 mNextAlarmClockMayChange = true; 255 } 256 } else { 257 if (alarm.whenElapsed > newStart) { 258 newStart = alarm.whenElapsed; 259 } 260 if (alarm.maxWhen < newEnd) { 261 newEnd = alarm.maxWhen; 262 } 263 i++; 264 } 265 } 266 if (didRemove) { 267 // commit the new batch bounds 268 start = newStart; 269 end = newEnd; 270 } 271 return didRemove; 272 } 273 274 boolean remove(final int userHandle) { 275 boolean didRemove = false; 276 long newStart = 0; // recalculate endpoints as we go 277 long newEnd = Long.MAX_VALUE; 278 for (int i = 0; i < alarms.size(); ) { 279 Alarm alarm = alarms.get(i); 280 if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) { 281 alarms.remove(i); 282 didRemove = true; 283 if (alarm.alarmClock != null) { 284 mNextAlarmClockMayChange = true; 285 } 286 } else { 287 if (alarm.whenElapsed > newStart) { 288 newStart = alarm.whenElapsed; 289 } 290 if (alarm.maxWhen < newEnd) { 291 newEnd = alarm.maxWhen; 292 } 293 i++; 294 } 295 } 296 if (didRemove) { 297 // commit the new batch bounds 298 start = newStart; 299 end = newEnd; 300 } 301 return didRemove; 302 } 303 304 boolean hasPackage(final String packageName) { 305 final int N = alarms.size(); 306 for (int i = 0; i < N; i++) { 307 Alarm a = alarms.get(i); 308 if (a.operation.getTargetPackage().equals(packageName)) { 309 return true; 310 } 311 } 312 return false; 313 } 314 315 boolean hasWakeups() { 316 final int N = alarms.size(); 317 for (int i = 0; i < N; i++) { 318 Alarm a = alarms.get(i); 319 // non-wakeup alarms are types 1 and 3, i.e. have the low bit set 320 if ((a.type & TYPE_NONWAKEUP_MASK) == 0) { 321 return true; 322 } 323 } 324 return false; 325 } 326 327 @Override 328 public String toString() { 329 StringBuilder b = new StringBuilder(40); 330 b.append("Batch{"); b.append(Integer.toHexString(this.hashCode())); 331 b.append(" num="); b.append(size()); 332 b.append(" start="); b.append(start); 333 b.append(" end="); b.append(end); 334 if (standalone) { 335 b.append(" STANDALONE"); 336 } 337 b.append('}'); 338 return b.toString(); 339 } 340 } 341 342 static class BatchTimeOrder implements Comparator<Batch> { 343 public int compare(Batch b1, Batch b2) { 344 long when1 = b1.start; 345 long when2 = b2.start; 346 if (when1 - when2 > 0) { 347 return 1; 348 } 349 if (when1 - when2 < 0) { 350 return -1; 351 } 352 return 0; 353 } 354 } 355 356 final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() { 357 @Override 358 public int compare(Alarm lhs, Alarm rhs) { 359 if ((!lhs.operation.getCreatorPackage().equals(rhs.operation.getCreatorPackage())) 360 && lhs.wakeup != rhs.wakeup) { 361 // We want to put wakeup alarms before non-wakeup alarms, since they are 362 // the things that drive most activity in the alarm manager. However, 363 // alarms from the same package should always be ordered strictly by time. 364 return lhs.wakeup ? -1 : 1; 365 } 366 if (lhs.whenElapsed < rhs.whenElapsed) { 367 return -1; 368 } else if (lhs.whenElapsed > rhs.whenElapsed) { 369 return 1; 370 } 371 return 0; 372 } 373 }; 374 375 // minimum recurrence period or alarm futurity for us to be able to fuzz it 376 static final long MIN_FUZZABLE_INTERVAL = 10000; 377 static final BatchTimeOrder sBatchOrder = new BatchTimeOrder(); 378 final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>(); 379 380 public AlarmManagerService(Context context) { 381 super(context); 382 } 383 384 static long convertToElapsed(long when, int type) { 385 final boolean isRtc = (type == RTC || type == RTC_WAKEUP); 386 if (isRtc) { 387 when -= System.currentTimeMillis() - SystemClock.elapsedRealtime(); 388 } 389 return when; 390 } 391 392 // Apply a heuristic to { recurrence interval, futurity of the trigger time } to 393 // calculate the end of our nominal delivery window for the alarm. 394 static long maxTriggerTime(long now, long triggerAtTime, long interval) { 395 // Current heuristic: batchable window is 75% of either the recurrence interval 396 // [for a periodic alarm] or of the time from now to the desired delivery time, 397 // with a minimum delay/interval of 10 seconds, under which we will simply not 398 // defer the alarm. 399 long futurity = (interval == 0) 400 ? (triggerAtTime - now) 401 : interval; 402 if (futurity < MIN_FUZZABLE_INTERVAL) { 403 futurity = 0; 404 } 405 return triggerAtTime + (long)(.75 * futurity); 406 } 407 408 // returns true if the batch was added at the head 409 static boolean addBatchLocked(ArrayList<Batch> list, Batch newBatch) { 410 int index = Collections.binarySearch(list, newBatch, sBatchOrder); 411 if (index < 0) { 412 index = 0 - index - 1; 413 } 414 list.add(index, newBatch); 415 return (index == 0); 416 } 417 418 // Return the index of the matching batch, or -1 if none found. 419 int attemptCoalesceLocked(long whenElapsed, long maxWhen) { 420 final int N = mAlarmBatches.size(); 421 for (int i = 0; i < N; i++) { 422 Batch b = mAlarmBatches.get(i); 423 if (!b.standalone && b.canHold(whenElapsed, maxWhen)) { 424 return i; 425 } 426 } 427 return -1; 428 } 429 430 // The RTC clock has moved arbitrarily, so we need to recalculate all the batching 431 void rebatchAllAlarms() { 432 synchronized (mLock) { 433 rebatchAllAlarmsLocked(true); 434 } 435 } 436 437 void rebatchAllAlarmsLocked(boolean doValidate) { 438 ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone(); 439 mAlarmBatches.clear(); 440 final long nowElapsed = SystemClock.elapsedRealtime(); 441 final int oldBatches = oldSet.size(); 442 for (int batchNum = 0; batchNum < oldBatches; batchNum++) { 443 Batch batch = oldSet.get(batchNum); 444 final int N = batch.size(); 445 for (int i = 0; i < N; i++) { 446 Alarm a = batch.get(i); 447 long whenElapsed = convertToElapsed(a.when, a.type); 448 final long maxElapsed; 449 if (a.whenElapsed == a.maxWhen) { 450 // Exact 451 maxElapsed = whenElapsed; 452 } else { 453 // Not exact. Preserve any explicit window, otherwise recalculate 454 // the window based on the alarm's new futurity. Note that this 455 // reflects a policy of preferring timely to deferred delivery. 456 maxElapsed = (a.windowLength > 0) 457 ? (whenElapsed + a.windowLength) 458 : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval); 459 } 460 setImplLocked(a.type, a.when, whenElapsed, a.windowLength, maxElapsed, 461 a.repeatInterval, a.operation, batch.standalone, doValidate, a.workSource, 462 a.alarmClock, a.userId); 463 } 464 } 465 } 466 467 static final class InFlight extends Intent { 468 final PendingIntent mPendingIntent; 469 final WorkSource mWorkSource; 470 final String mTag; 471 final BroadcastStats mBroadcastStats; 472 final FilterStats mFilterStats; 473 final int mAlarmType; 474 475 InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource, 476 int alarmType, String tag) { 477 mPendingIntent = pendingIntent; 478 mWorkSource = workSource; 479 mTag = tag; 480 mBroadcastStats = service.getStatsLocked(pendingIntent); 481 FilterStats fs = mBroadcastStats.filterStats.get(mTag); 482 if (fs == null) { 483 fs = new FilterStats(mBroadcastStats, mTag); 484 mBroadcastStats.filterStats.put(mTag, fs); 485 } 486 mFilterStats = fs; 487 mAlarmType = alarmType; 488 } 489 } 490 491 static final class FilterStats { 492 final BroadcastStats mBroadcastStats; 493 final String mTag; 494 495 long aggregateTime; 496 int count; 497 int numWakeup; 498 long startTime; 499 int nesting; 500 501 FilterStats(BroadcastStats broadcastStats, String tag) { 502 mBroadcastStats = broadcastStats; 503 mTag = tag; 504 } 505 } 506 507 static final class BroadcastStats { 508 final int mUid; 509 final String mPackageName; 510 511 long aggregateTime; 512 int count; 513 int numWakeup; 514 long startTime; 515 int nesting; 516 final ArrayMap<String, FilterStats> filterStats = new ArrayMap<String, FilterStats>(); 517 518 BroadcastStats(int uid, String packageName) { 519 mUid = uid; 520 mPackageName = packageName; 521 } 522 } 523 524 final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats 525 = new SparseArray<ArrayMap<String, BroadcastStats>>(); 526 527 int mNumDelayedAlarms = 0; 528 long mTotalDelayTime = 0; 529 long mMaxDelayTime = 0; 530 531 @Override 532 public void onStart() { 533 mNativeData = init(); 534 mNextWakeup = mNextNonWakeup = 0; 535 536 // We have to set current TimeZone info to kernel 537 // because kernel doesn't keep this after reboot 538 setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY)); 539 540 PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 541 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*"); 542 543 mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0, 544 new Intent(Intent.ACTION_TIME_TICK).addFlags( 545 Intent.FLAG_RECEIVER_REGISTERED_ONLY 546 | Intent.FLAG_RECEIVER_FOREGROUND), 0, 547 UserHandle.ALL); 548 Intent intent = new Intent(Intent.ACTION_DATE_CHANGED); 549 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 550 mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent, 551 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL); 552 553 // now that we have initied the driver schedule the alarm 554 mClockReceiver = new ClockReceiver(); 555 mClockReceiver.scheduleTimeTickEvent(); 556 mClockReceiver.scheduleDateChangedEvent(); 557 mInteractiveStateReceiver = new InteractiveStateReceiver(); 558 mUninstallReceiver = new UninstallReceiver(); 559 560 if (mNativeData != 0) { 561 AlarmThread waitThread = new AlarmThread(); 562 waitThread.start(); 563 } else { 564 Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler."); 565 } 566 567 publishBinderService(Context.ALARM_SERVICE, mService); 568 } 569 570 @Override 571 protected void finalize() throws Throwable { 572 try { 573 close(mNativeData); 574 } finally { 575 super.finalize(); 576 } 577 } 578 579 void setTimeZoneImpl(String tz) { 580 if (TextUtils.isEmpty(tz)) { 581 return; 582 } 583 584 TimeZone zone = TimeZone.getTimeZone(tz); 585 // Prevent reentrant calls from stepping on each other when writing 586 // the time zone property 587 boolean timeZoneWasChanged = false; 588 synchronized (this) { 589 String current = SystemProperties.get(TIMEZONE_PROPERTY); 590 if (current == null || !current.equals(zone.getID())) { 591 if (localLOGV) { 592 Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID()); 593 } 594 timeZoneWasChanged = true; 595 SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); 596 } 597 598 // Update the kernel timezone information 599 // Kernel tracks time offsets as 'minutes west of GMT' 600 int gmtOffset = zone.getOffset(System.currentTimeMillis()); 601 setKernelTimezone(mNativeData, -(gmtOffset / 60000)); 602 } 603 604 TimeZone.setDefault(null); 605 606 if (timeZoneWasChanged) { 607 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); 608 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 609 intent.putExtra("time-zone", zone.getID()); 610 getContext().sendBroadcastAsUser(intent, UserHandle.ALL); 611 } 612 } 613 614 void removeImpl(PendingIntent operation) { 615 if (operation == null) { 616 return; 617 } 618 synchronized (mLock) { 619 removeLocked(operation); 620 } 621 } 622 623 void setImpl(int type, long triggerAtTime, long windowLength, long interval, 624 PendingIntent operation, boolean isStandalone, WorkSource workSource, 625 AlarmManager.AlarmClockInfo alarmClock) { 626 if (operation == null) { 627 Slog.w(TAG, "set/setRepeating ignored because there is no intent"); 628 return; 629 } 630 631 // Sanity check the window length. This will catch people mistakenly 632 // trying to pass an end-of-window timestamp rather than a duration. 633 if (windowLength > AlarmManager.INTERVAL_HALF_DAY) { 634 Slog.w(TAG, "Window length " + windowLength 635 + "ms suspiciously long; limiting to 1 hour"); 636 windowLength = AlarmManager.INTERVAL_HOUR; 637 } 638 639 if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) { 640 throw new IllegalArgumentException("Invalid alarm type " + type); 641 } 642 643 if (triggerAtTime < 0) { 644 final long who = Binder.getCallingUid(); 645 final long what = Binder.getCallingPid(); 646 Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who 647 + " pid=" + what); 648 triggerAtTime = 0; 649 } 650 651 final long nowElapsed = SystemClock.elapsedRealtime(); 652 final long triggerElapsed = convertToElapsed(triggerAtTime, type); 653 final long maxElapsed; 654 if (windowLength == AlarmManager.WINDOW_EXACT) { 655 maxElapsed = triggerElapsed; 656 } else if (windowLength < 0) { 657 maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval); 658 } else { 659 maxElapsed = triggerElapsed + windowLength; 660 } 661 662 final int userId = UserHandle.getCallingUserId(); 663 664 synchronized (mLock) { 665 if (DEBUG_BATCH) { 666 Slog.v(TAG, "set(" + operation + ") : type=" + type 667 + " triggerAtTime=" + triggerAtTime + " win=" + windowLength 668 + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed 669 + " interval=" + interval + " standalone=" + isStandalone); 670 } 671 setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed, 672 interval, operation, isStandalone, true, workSource, alarmClock, userId); 673 } 674 } 675 676 private void setImplLocked(int type, long when, long whenElapsed, long windowLength, 677 long maxWhen, long interval, PendingIntent operation, boolean isStandalone, 678 boolean doValidate, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock, 679 int userId) { 680 Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval, 681 operation, workSource, alarmClock, userId); 682 removeLocked(operation); 683 684 int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen); 685 if (whichBatch < 0) { 686 Batch batch = new Batch(a); 687 batch.standalone = isStandalone; 688 addBatchLocked(mAlarmBatches, batch); 689 } else { 690 Batch batch = mAlarmBatches.get(whichBatch); 691 if (batch.add(a)) { 692 // The start time of this batch advanced, so batch ordering may 693 // have just been broken. Move it to where it now belongs. 694 mAlarmBatches.remove(whichBatch); 695 addBatchLocked(mAlarmBatches, batch); 696 } 697 } 698 699 if (alarmClock != null) { 700 mNextAlarmClockMayChange = true; 701 updateNextAlarmClockLocked(); 702 } 703 704 if (DEBUG_VALIDATE) { 705 if (doValidate && !validateConsistencyLocked()) { 706 Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when 707 + " when(hex)=" + Long.toHexString(when) 708 + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen 709 + " interval=" + interval + " op=" + operation 710 + " standalone=" + isStandalone); 711 rebatchAllAlarmsLocked(false); 712 } 713 } 714 715 rescheduleKernelAlarmsLocked(); 716 } 717 718 private final IBinder mService = new IAlarmManager.Stub() { 719 @Override 720 public void set(int type, long triggerAtTime, long windowLength, long interval, 721 PendingIntent operation, WorkSource workSource, 722 AlarmManager.AlarmClockInfo alarmClock) { 723 if (workSource != null) { 724 getContext().enforceCallingPermission( 725 android.Manifest.permission.UPDATE_DEVICE_STATS, 726 "AlarmManager.set"); 727 } 728 729 setImpl(type, triggerAtTime, windowLength, interval, operation, 730 false, workSource, alarmClock); 731 } 732 733 @Override 734 public boolean setTime(long millis) { 735 getContext().enforceCallingOrSelfPermission( 736 "android.permission.SET_TIME", 737 "setTime"); 738 739 if (mNativeData == 0) { 740 Slog.w(TAG, "Not setting time since no alarm driver is available."); 741 return false; 742 } 743 744 synchronized (mLock) { 745 return setKernelTime(mNativeData, millis) == 0; 746 } 747 } 748 749 @Override 750 public void setTimeZone(String tz) { 751 getContext().enforceCallingOrSelfPermission( 752 "android.permission.SET_TIME_ZONE", 753 "setTimeZone"); 754 755 final long oldId = Binder.clearCallingIdentity(); 756 try { 757 setTimeZoneImpl(tz); 758 } finally { 759 Binder.restoreCallingIdentity(oldId); 760 } 761 } 762 763 @Override 764 public void remove(PendingIntent operation) { 765 removeImpl(operation); 766 767 } 768 769 @Override 770 public AlarmManager.AlarmClockInfo getNextAlarmClock(int userId) { 771 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 772 Binder.getCallingUid(), userId, false /* allowAll */, false /* requireFull */, 773 "getNextAlarmClock", null); 774 775 return getNextAlarmClockImpl(userId); 776 } 777 778 @Override 779 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 780 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 781 != PackageManager.PERMISSION_GRANTED) { 782 pw.println("Permission Denial: can't dump AlarmManager from from pid=" 783 + Binder.getCallingPid() 784 + ", uid=" + Binder.getCallingUid()); 785 return; 786 } 787 788 dumpImpl(pw); 789 } 790 }; 791 792 void dumpImpl(PrintWriter pw) { 793 synchronized (mLock) { 794 pw.println("Current Alarm Manager state:"); 795 final long nowRTC = System.currentTimeMillis(); 796 final long nowELAPSED = SystemClock.elapsedRealtime(); 797 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 798 799 pw.print("nowRTC="); pw.print(nowRTC); 800 pw.print("="); pw.print(sdf.format(new Date(nowRTC))); 801 pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw); 802 pw.println(); 803 if (!mInteractive) { 804 pw.print("Time since non-interactive: "); 805 TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw); 806 pw.println(); 807 pw.print("Max wakeup delay: "); 808 TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw); 809 pw.println(); 810 pw.print("Time since last dispatch: "); 811 TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw); 812 pw.println(); 813 pw.print("Next non-wakeup delivery time: "); 814 TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw); 815 pw.println(); 816 } 817 818 long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED); 819 long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED); 820 pw.print("Next non-wakeup alarm: "); 821 TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw); 822 pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC))); 823 pw.print("Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw); 824 pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC))); 825 pw.print("Num time change events: "); pw.println(mNumTimeChanged); 826 827 if (mAlarmBatches.size() > 0) { 828 pw.println(); 829 pw.print("Pending alarm batches: "); 830 pw.println(mAlarmBatches.size()); 831 for (Batch b : mAlarmBatches) { 832 pw.print(b); pw.println(':'); 833 dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf); 834 } 835 } 836 837 pw.println(); 838 pw.print("Past-due non-wakeup alarms: "); 839 if (mPendingNonWakeupAlarms.size() > 0) { 840 pw.println(mPendingNonWakeupAlarms.size()); 841 dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf); 842 } else { 843 pw.println("(none)"); 844 } 845 pw.print(" Number of delayed alarms: "); pw.print(mNumDelayedAlarms); 846 pw.print(", total delay time: "); TimeUtils.formatDuration(mTotalDelayTime, pw); 847 pw.println(); 848 pw.print(" Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw); 849 pw.print(", max non-interactive time: "); 850 TimeUtils.formatDuration(mNonInteractiveTime, pw); 851 pw.println(); 852 853 pw.println(); 854 pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount); 855 pw.println(); 856 857 if (mLog.dump(pw, " Recent problems", " ")) { 858 pw.println(); 859 } 860 861 final FilterStats[] topFilters = new FilterStats[10]; 862 final Comparator<FilterStats> comparator = new Comparator<FilterStats>() { 863 @Override 864 public int compare(FilterStats lhs, FilterStats rhs) { 865 if (lhs.aggregateTime < rhs.aggregateTime) { 866 return 1; 867 } else if (lhs.aggregateTime > rhs.aggregateTime) { 868 return -1; 869 } 870 return 0; 871 } 872 }; 873 int len = 0; 874 for (int iu=0; iu<mBroadcastStats.size(); iu++) { 875 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu); 876 for (int ip=0; ip<uidStats.size(); ip++) { 877 BroadcastStats bs = uidStats.valueAt(ip); 878 for (int is=0; is<bs.filterStats.size(); is++) { 879 FilterStats fs = bs.filterStats.valueAt(is); 880 int pos = len > 0 881 ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0; 882 if (pos < 0) { 883 pos = -pos - 1; 884 } 885 if (pos < topFilters.length) { 886 int copylen = topFilters.length - pos - 1; 887 if (copylen > 0) { 888 System.arraycopy(topFilters, pos, topFilters, pos+1, copylen); 889 } 890 topFilters[pos] = fs; 891 if (len < topFilters.length) { 892 len++; 893 } 894 } 895 } 896 } 897 } 898 if (len > 0) { 899 pw.println(" Top Alarms:"); 900 for (int i=0; i<len; i++) { 901 FilterStats fs = topFilters[i]; 902 pw.print(" "); 903 if (fs.nesting > 0) pw.print("*ACTIVE* "); 904 TimeUtils.formatDuration(fs.aggregateTime, pw); 905 pw.print(" running, "); pw.print(fs.numWakeup); 906 pw.print(" wakeups, "); pw.print(fs.count); 907 pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid); 908 pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName); 909 pw.println(); 910 pw.print(" "); pw.print(fs.mTag); 911 pw.println(); 912 } 913 } 914 915 pw.println(" "); 916 pw.println(" Alarm Stats:"); 917 final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>(); 918 for (int iu=0; iu<mBroadcastStats.size(); iu++) { 919 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu); 920 for (int ip=0; ip<uidStats.size(); ip++) { 921 BroadcastStats bs = uidStats.valueAt(ip); 922 pw.print(" "); 923 if (bs.nesting > 0) pw.print("*ACTIVE* "); 924 UserHandle.formatUid(pw, bs.mUid); 925 pw.print(":"); 926 pw.print(bs.mPackageName); 927 pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw); 928 pw.print(" running, "); pw.print(bs.numWakeup); 929 pw.println(" wakeups:"); 930 tmpFilters.clear(); 931 for (int is=0; is<bs.filterStats.size(); is++) { 932 tmpFilters.add(bs.filterStats.valueAt(is)); 933 } 934 Collections.sort(tmpFilters, comparator); 935 for (int i=0; i<tmpFilters.size(); i++) { 936 FilterStats fs = tmpFilters.get(i); 937 pw.print(" "); 938 if (fs.nesting > 0) pw.print("*ACTIVE* "); 939 TimeUtils.formatDuration(fs.aggregateTime, pw); 940 pw.print(" "); pw.print(fs.numWakeup); 941 pw.print(" wakes " ); pw.print(fs.count); 942 pw.print(" alarms: "); 943 pw.print(fs.mTag); 944 pw.println(); 945 } 946 } 947 } 948 949 if (WAKEUP_STATS) { 950 pw.println(); 951 pw.println(" Recent Wakeup History:"); 952 long last = -1; 953 for (WakeupEvent event : mRecentWakeups) { 954 pw.print(" "); pw.print(sdf.format(new Date(event.when))); 955 pw.print('|'); 956 if (last < 0) { 957 pw.print('0'); 958 } else { 959 pw.print(event.when - last); 960 } 961 last = event.when; 962 pw.print('|'); pw.print(event.uid); 963 pw.print('|'); pw.print(event.action); 964 pw.println(); 965 } 966 pw.println(); 967 } 968 } 969 } 970 971 private void logBatchesLocked(SimpleDateFormat sdf) { 972 ByteArrayOutputStream bs = new ByteArrayOutputStream(2048); 973 PrintWriter pw = new PrintWriter(bs); 974 final long nowRTC = System.currentTimeMillis(); 975 final long nowELAPSED = SystemClock.elapsedRealtime(); 976 final int NZ = mAlarmBatches.size(); 977 for (int iz = 0; iz < NZ; iz++) { 978 Batch bz = mAlarmBatches.get(iz); 979 pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz); 980 dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC, sdf); 981 pw.flush(); 982 Slog.v(TAG, bs.toString()); 983 bs.reset(); 984 } 985 } 986 987 private boolean validateConsistencyLocked() { 988 if (DEBUG_VALIDATE) { 989 long lastTime = Long.MIN_VALUE; 990 final int N = mAlarmBatches.size(); 991 for (int i = 0; i < N; i++) { 992 Batch b = mAlarmBatches.get(i); 993 if (b.start >= lastTime) { 994 // duplicate start times are okay because of standalone batches 995 lastTime = b.start; 996 } else { 997 Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order"); 998 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 999 logBatchesLocked(sdf); 1000 return false; 1001 } 1002 } 1003 } 1004 return true; 1005 } 1006 1007 private Batch findFirstWakeupBatchLocked() { 1008 final int N = mAlarmBatches.size(); 1009 for (int i = 0; i < N; i++) { 1010 Batch b = mAlarmBatches.get(i); 1011 if (b.hasWakeups()) { 1012 return b; 1013 } 1014 } 1015 return null; 1016 } 1017 1018 private AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) { 1019 synchronized (mLock) { 1020 return mNextAlarmClockForUser.get(userId); 1021 } 1022 } 1023 1024 /** 1025 * Recomputes the next alarm clock for all users. 1026 */ 1027 private void updateNextAlarmClockLocked() { 1028 if (!mNextAlarmClockMayChange) { 1029 return; 1030 } 1031 mNextAlarmClockMayChange = false; 1032 1033 SparseArray<AlarmManager.AlarmClockInfo> nextForUser = mTmpSparseAlarmClockArray; 1034 nextForUser.clear(); 1035 1036 final int N = mAlarmBatches.size(); 1037 for (int i = 0; i < N; i++) { 1038 ArrayList<Alarm> alarms = mAlarmBatches.get(i).alarms; 1039 final int M = alarms.size(); 1040 1041 for (int j = 0; j < M; j++) { 1042 Alarm a = alarms.get(j); 1043 if (a.alarmClock != null) { 1044 final int userId = a.userId; 1045 1046 if (DEBUG_ALARM_CLOCK) { 1047 Log.v(TAG, "Found AlarmClockInfo at " + 1048 formatNextAlarm(getContext(), a.alarmClock) + 1049 " for user " + userId); 1050 } 1051 1052 // Alarms and batches are sorted by time, no need to compare times here. 1053 if (nextForUser.get(userId) == null) { 1054 nextForUser.put(userId, a.alarmClock); 1055 } 1056 } 1057 } 1058 } 1059 1060 // Update mNextAlarmForUser with new values. 1061 final int NN = nextForUser.size(); 1062 for (int i = 0; i < NN; i++) { 1063 AlarmManager.AlarmClockInfo newAlarm = nextForUser.valueAt(i); 1064 int userId = nextForUser.keyAt(i); 1065 AlarmManager.AlarmClockInfo currentAlarm = mNextAlarmClockForUser.get(userId); 1066 if (!newAlarm.equals(currentAlarm)) { 1067 updateNextAlarmInfoForUserLocked(userId, newAlarm); 1068 } 1069 } 1070 1071 // Remove users without any alarm clocks scheduled. 1072 final int NNN = mNextAlarmClockForUser.size(); 1073 for (int i = NNN - 1; i >= 0; i--) { 1074 int userId = mNextAlarmClockForUser.keyAt(i); 1075 if (nextForUser.get(userId) == null) { 1076 updateNextAlarmInfoForUserLocked(userId, null); 1077 } 1078 } 1079 } 1080 1081 private void updateNextAlarmInfoForUserLocked(int userId, 1082 AlarmManager.AlarmClockInfo alarmClock) { 1083 if (alarmClock != null) { 1084 if (DEBUG_ALARM_CLOCK) { 1085 Log.v(TAG, "Next AlarmClockInfoForUser(" + userId + "): " + 1086 formatNextAlarm(getContext(), alarmClock)); 1087 } 1088 mNextAlarmClockForUser.put(userId, alarmClock); 1089 } else { 1090 if (DEBUG_ALARM_CLOCK) { 1091 Log.v(TAG, "Next AlarmClockInfoForUser(" + userId + "): None"); 1092 } 1093 mNextAlarmClockForUser.remove(userId); 1094 } 1095 1096 mPendingSendNextAlarmClockChangedForUser.put(userId, true); 1097 mHandler.removeMessages(AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED); 1098 mHandler.sendEmptyMessage(AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED); 1099 } 1100 1101 /** 1102 * Updates NEXT_ALARM_FORMATTED and sends NEXT_ALARM_CLOCK_CHANGED_INTENT for all users 1103 * for which alarm clocks have changed since the last call to this. 1104 * 1105 * Do not call with a lock held. Only call from mHandler's thread. 1106 * 1107 * @see AlarmHandler#SEND_NEXT_ALARM_CLOCK_CHANGED 1108 */ 1109 private void sendNextAlarmClockChanged() { 1110 SparseArray<AlarmManager.AlarmClockInfo> pendingUsers = mHandlerSparseAlarmClockArray; 1111 pendingUsers.clear(); 1112 1113 synchronized (mLock) { 1114 final int N = mPendingSendNextAlarmClockChangedForUser.size(); 1115 for (int i = 0; i < N; i++) { 1116 int userId = mPendingSendNextAlarmClockChangedForUser.keyAt(i); 1117 pendingUsers.append(userId, mNextAlarmClockForUser.get(userId)); 1118 } 1119 mPendingSendNextAlarmClockChangedForUser.clear(); 1120 } 1121 1122 final int N = pendingUsers.size(); 1123 for (int i = 0; i < N; i++) { 1124 int userId = pendingUsers.keyAt(i); 1125 AlarmManager.AlarmClockInfo alarmClock = pendingUsers.valueAt(i); 1126 Settings.System.putStringForUser(getContext().getContentResolver(), 1127 Settings.System.NEXT_ALARM_FORMATTED, 1128 formatNextAlarm(getContext(), alarmClock), 1129 userId); 1130 1131 getContext().sendBroadcastAsUser(NEXT_ALARM_CLOCK_CHANGED_INTENT, 1132 new UserHandle(userId)); 1133 } 1134 } 1135 1136 /** 1137 * Formats an alarm like platform/packages/apps/DeskClock used to. 1138 */ 1139 private static String formatNextAlarm(final Context context, AlarmManager.AlarmClockInfo info) { 1140 String skeleton = DateFormat.is24HourFormat(context) ? "EHm" : "Ehma"; 1141 String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); 1142 return (info == null) ? "" : 1143 DateFormat.format(pattern, info.getTriggerTime()).toString(); 1144 } 1145 1146 void rescheduleKernelAlarmsLocked() { 1147 // Schedule the next upcoming wakeup alarm. If there is a deliverable batch 1148 // prior to that which contains no wakeups, we schedule that as well. 1149 long nextNonWakeup = 0; 1150 if (mAlarmBatches.size() > 0) { 1151 final Batch firstWakeup = findFirstWakeupBatchLocked(); 1152 final Batch firstBatch = mAlarmBatches.get(0); 1153 if (firstWakeup != null && mNextWakeup != firstWakeup.start) { 1154 mNextWakeup = firstWakeup.start; 1155 setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start); 1156 } 1157 if (firstBatch != firstWakeup) { 1158 nextNonWakeup = firstBatch.start; 1159 } 1160 } 1161 if (mPendingNonWakeupAlarms.size() > 0) { 1162 if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) { 1163 nextNonWakeup = mNextNonWakeupDeliveryTime; 1164 } 1165 } 1166 if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) { 1167 mNextNonWakeup = nextNonWakeup; 1168 setLocked(ELAPSED_REALTIME, nextNonWakeup); 1169 } 1170 } 1171 1172 private void removeLocked(PendingIntent operation) { 1173 boolean didRemove = false; 1174 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { 1175 Batch b = mAlarmBatches.get(i); 1176 didRemove |= b.remove(operation); 1177 if (b.size() == 0) { 1178 mAlarmBatches.remove(i); 1179 } 1180 } 1181 1182 if (didRemove) { 1183 if (DEBUG_BATCH) { 1184 Slog.v(TAG, "remove(operation) changed bounds; rebatching"); 1185 } 1186 rebatchAllAlarmsLocked(true); 1187 rescheduleKernelAlarmsLocked(); 1188 updateNextAlarmClockLocked(); 1189 } 1190 } 1191 1192 void removeLocked(String packageName) { 1193 boolean didRemove = false; 1194 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { 1195 Batch b = mAlarmBatches.get(i); 1196 didRemove |= b.remove(packageName); 1197 if (b.size() == 0) { 1198 mAlarmBatches.remove(i); 1199 } 1200 } 1201 1202 if (didRemove) { 1203 if (DEBUG_BATCH) { 1204 Slog.v(TAG, "remove(package) changed bounds; rebatching"); 1205 } 1206 rebatchAllAlarmsLocked(true); 1207 rescheduleKernelAlarmsLocked(); 1208 updateNextAlarmClockLocked(); 1209 } 1210 } 1211 1212 void removeUserLocked(int userHandle) { 1213 boolean didRemove = false; 1214 for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { 1215 Batch b = mAlarmBatches.get(i); 1216 didRemove |= b.remove(userHandle); 1217 if (b.size() == 0) { 1218 mAlarmBatches.remove(i); 1219 } 1220 } 1221 1222 if (didRemove) { 1223 if (DEBUG_BATCH) { 1224 Slog.v(TAG, "remove(user) changed bounds; rebatching"); 1225 } 1226 rebatchAllAlarmsLocked(true); 1227 rescheduleKernelAlarmsLocked(); 1228 updateNextAlarmClockLocked(); 1229 } 1230 } 1231 1232 void interactiveStateChangedLocked(boolean interactive) { 1233 if (mInteractive != interactive) { 1234 mInteractive = interactive; 1235 final long nowELAPSED = SystemClock.elapsedRealtime(); 1236 if (interactive) { 1237 if (mPendingNonWakeupAlarms.size() > 0) { 1238 final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime; 1239 mTotalDelayTime += thisDelayTime; 1240 if (mMaxDelayTime < thisDelayTime) { 1241 mMaxDelayTime = thisDelayTime; 1242 } 1243 deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED); 1244 mPendingNonWakeupAlarms.clear(); 1245 } 1246 if (mNonInteractiveStartTime > 0) { 1247 long dur = nowELAPSED - mNonInteractiveStartTime; 1248 if (dur > mNonInteractiveTime) { 1249 mNonInteractiveTime = dur; 1250 } 1251 } 1252 } else { 1253 mNonInteractiveStartTime = nowELAPSED; 1254 } 1255 } 1256 } 1257 1258 boolean lookForPackageLocked(String packageName) { 1259 for (int i = 0; i < mAlarmBatches.size(); i++) { 1260 Batch b = mAlarmBatches.get(i); 1261 if (b.hasPackage(packageName)) { 1262 return true; 1263 } 1264 } 1265 return false; 1266 } 1267 1268 private void setLocked(int type, long when) { 1269 if (mNativeData != 0) { 1270 // The kernel never triggers alarms with negative wakeup times 1271 // so we ensure they are positive. 1272 long alarmSeconds, alarmNanoseconds; 1273 if (when < 0) { 1274 alarmSeconds = 0; 1275 alarmNanoseconds = 0; 1276 } else { 1277 alarmSeconds = when / 1000; 1278 alarmNanoseconds = (when % 1000) * 1000 * 1000; 1279 } 1280 1281 set(mNativeData, type, alarmSeconds, alarmNanoseconds); 1282 } else { 1283 Message msg = Message.obtain(); 1284 msg.what = ALARM_EVENT; 1285 1286 mHandler.removeMessages(ALARM_EVENT); 1287 mHandler.sendMessageAtTime(msg, when); 1288 } 1289 } 1290 1291 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, 1292 String prefix, String label, long nowRTC, long nowELAPSED, SimpleDateFormat sdf) { 1293 for (int i=list.size()-1; i>=0; i--) { 1294 Alarm a = list.get(i); 1295 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); 1296 pw.print(": "); pw.println(a); 1297 a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf); 1298 } 1299 } 1300 1301 private static final String labelForType(int type) { 1302 switch (type) { 1303 case RTC: return "RTC"; 1304 case RTC_WAKEUP : return "RTC_WAKEUP"; 1305 case ELAPSED_REALTIME : return "ELAPSED"; 1306 case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP"; 1307 default: 1308 break; 1309 } 1310 return "--unknown--"; 1311 } 1312 1313 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, 1314 String prefix, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) { 1315 for (int i=list.size()-1; i>=0; i--) { 1316 Alarm a = list.get(i); 1317 final String label = labelForType(a.type); 1318 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); 1319 pw.print(": "); pw.println(a); 1320 a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf); 1321 } 1322 } 1323 1324 private native long init(); 1325 private native void close(long nativeData); 1326 private native void set(long nativeData, int type, long seconds, long nanoseconds); 1327 private native int waitForAlarm(long nativeData); 1328 private native int setKernelTime(long nativeData, long millis); 1329 private native int setKernelTimezone(long nativeData, int minuteswest); 1330 1331 boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED, 1332 final long nowRTC) { 1333 boolean hasWakeup = false; 1334 // batches are temporally sorted, so we need only pull from the 1335 // start of the list until we either empty it or hit a batch 1336 // that is not yet deliverable 1337 while (mAlarmBatches.size() > 0) { 1338 Batch batch = mAlarmBatches.get(0); 1339 if (batch.start > nowELAPSED) { 1340 // Everything else is scheduled for the future 1341 break; 1342 } 1343 1344 // We will (re)schedule some alarms now; don't let that interfere 1345 // with delivery of this current batch 1346 mAlarmBatches.remove(0); 1347 1348 final int N = batch.size(); 1349 for (int i = 0; i < N; i++) { 1350 Alarm alarm = batch.get(i); 1351 alarm.count = 1; 1352 triggerList.add(alarm); 1353 1354 // Recurring alarms may have passed several alarm intervals while the 1355 // phone was asleep or off, so pass a trigger count when sending them. 1356 if (alarm.repeatInterval > 0) { 1357 // this adjustment will be zero if we're late by 1358 // less than one full repeat interval 1359 alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval; 1360 1361 // Also schedule its next recurrence 1362 final long delta = alarm.count * alarm.repeatInterval; 1363 final long nextElapsed = alarm.whenElapsed + delta; 1364 setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength, 1365 maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval), 1366 alarm.repeatInterval, alarm.operation, batch.standalone, true, 1367 alarm.workSource, alarm.alarmClock, alarm.userId); 1368 1369 // For now we count this as a wakeup alarm, meaning it needs to be 1370 // delivered immediately. In the future we should change this, but 1371 // that required delaying when we reschedule the repeat...! 1372 hasWakeup = false; 1373 } else if (alarm.wakeup) { 1374 hasWakeup = true; 1375 } 1376 1377 // We removed an alarm clock. Let the caller recompute the next alarm clock. 1378 if (alarm.alarmClock != null) { 1379 mNextAlarmClockMayChange = true; 1380 } 1381 } 1382 } 1383 1384 Collections.sort(triggerList, mAlarmDispatchComparator); 1385 1386 if (localLOGV) { 1387 for (int i=0; i<triggerList.size(); i++) { 1388 Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i)); 1389 } 1390 } 1391 1392 return hasWakeup; 1393 } 1394 1395 /** 1396 * This Comparator sorts Alarms into increasing time order. 1397 */ 1398 public static class IncreasingTimeOrder implements Comparator<Alarm> { 1399 public int compare(Alarm a1, Alarm a2) { 1400 long when1 = a1.when; 1401 long when2 = a2.when; 1402 if (when1 - when2 > 0) { 1403 return 1; 1404 } 1405 if (when1 - when2 < 0) { 1406 return -1; 1407 } 1408 return 0; 1409 } 1410 } 1411 1412 private static class Alarm { 1413 public final int type; 1414 public final boolean wakeup; 1415 public final PendingIntent operation; 1416 public final String tag; 1417 public final WorkSource workSource; 1418 public int count; 1419 public long when; 1420 public long windowLength; 1421 public long whenElapsed; // 'when' in the elapsed time base 1422 public long maxWhen; // also in the elapsed time base 1423 public long repeatInterval; 1424 public final AlarmManager.AlarmClockInfo alarmClock; 1425 public final int userId; 1426 1427 public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen, 1428 long _interval, PendingIntent _op, WorkSource _ws, 1429 AlarmManager.AlarmClockInfo _info, int _userId) { 1430 type = _type; 1431 wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP 1432 || _type == AlarmManager.RTC_WAKEUP; 1433 when = _when; 1434 whenElapsed = _whenElapsed; 1435 windowLength = _windowLength; 1436 maxWhen = _maxWhen; 1437 repeatInterval = _interval; 1438 operation = _op; 1439 tag = makeTag(_op, _type); 1440 workSource = _ws; 1441 alarmClock = _info; 1442 userId = _userId; 1443 } 1444 1445 public static String makeTag(PendingIntent pi, int type) { 1446 return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP 1447 ? "*walarm*:" : "*alarm*:"); 1448 } 1449 1450 @Override 1451 public String toString() { 1452 StringBuilder sb = new StringBuilder(128); 1453 sb.append("Alarm{"); 1454 sb.append(Integer.toHexString(System.identityHashCode(this))); 1455 sb.append(" type "); 1456 sb.append(type); 1457 sb.append(" when "); 1458 sb.append(when); 1459 sb.append(" "); 1460 sb.append(operation.getTargetPackage()); 1461 sb.append('}'); 1462 return sb.toString(); 1463 } 1464 1465 public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED, 1466 SimpleDateFormat sdf) { 1467 final boolean isRtc = (type == RTC || type == RTC_WAKEUP); 1468 pw.print(prefix); pw.print("tag="); pw.println(tag); 1469 pw.print(prefix); pw.print("type="); pw.print(type); 1470 pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed, 1471 nowELAPSED, pw); 1472 if (isRtc) { 1473 pw.print(" when="); pw.print(sdf.format(new Date(when))); 1474 } else { 1475 pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw); 1476 } 1477 pw.println(); 1478 pw.print(prefix); pw.print("window="); pw.print(windowLength); 1479 pw.print(" repeatInterval="); pw.print(repeatInterval); 1480 pw.print(" count="); pw.println(count); 1481 pw.print(prefix); pw.print("operation="); pw.println(operation); 1482 } 1483 } 1484 1485 void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) { 1486 final int numBatches = batches.size(); 1487 for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) { 1488 Batch b = batches.get(nextBatch); 1489 if (b.start > nowELAPSED) { 1490 break; 1491 } 1492 1493 final int numAlarms = b.alarms.size(); 1494 for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) { 1495 Alarm a = b.alarms.get(nextAlarm); 1496 WakeupEvent e = new WakeupEvent(nowRTC, 1497 a.operation.getCreatorUid(), 1498 a.operation.getIntent().getAction()); 1499 mRecentWakeups.add(e); 1500 } 1501 } 1502 } 1503 1504 long currentNonWakeupFuzzLocked(long nowELAPSED) { 1505 long timeSinceOn = nowELAPSED - mNonInteractiveStartTime; 1506 if (timeSinceOn < 5*60*1000) { 1507 // If the screen has been off for 5 minutes, only delay by at most two minutes. 1508 return 2*60*1000; 1509 } else if (timeSinceOn < 30*60*1000) { 1510 // If the screen has been off for 30 minutes, only delay by at most 15 minutes. 1511 return 15*60*1000; 1512 } else { 1513 // Otherwise, we will delay by at most an hour. 1514 return 60*60*1000; 1515 } 1516 } 1517 1518 boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) { 1519 if (mInteractive) { 1520 return false; 1521 } 1522 if (mLastAlarmDeliveryTime <= 0) { 1523 return false; 1524 } 1525 if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime > nowELAPSED) { 1526 // This is just a little paranoia, if somehow we have pending non-wakeup alarms 1527 // and the next delivery time is in the past, then just deliver them all. This 1528 // avoids bugs where we get stuck in a loop trying to poll for alarms. 1529 return false; 1530 } 1531 long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime; 1532 return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED); 1533 } 1534 1535 void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) { 1536 mLastAlarmDeliveryTime = nowELAPSED; 1537 for (int i=0; i<triggerList.size(); i++) { 1538 Alarm alarm = triggerList.get(i); 1539 try { 1540 if (localLOGV) { 1541 Slog.v(TAG, "sending alarm " + alarm); 1542 } 1543 alarm.operation.send(getContext(), 0, 1544 mBackgroundIntent.putExtra( 1545 Intent.EXTRA_ALARM_COUNT, alarm.count), 1546 mResultReceiver, mHandler); 1547 1548 // we have an active broadcast so stay awake. 1549 if (mBroadcastRefCount == 0) { 1550 setWakelockWorkSource(alarm.operation, alarm.workSource, 1551 alarm.type, alarm.tag, true); 1552 mWakeLock.acquire(); 1553 } 1554 final InFlight inflight = new InFlight(AlarmManagerService.this, 1555 alarm.operation, alarm.workSource, alarm.type, alarm.tag); 1556 mInFlight.add(inflight); 1557 mBroadcastRefCount++; 1558 1559 final BroadcastStats bs = inflight.mBroadcastStats; 1560 bs.count++; 1561 if (bs.nesting == 0) { 1562 bs.nesting = 1; 1563 bs.startTime = nowELAPSED; 1564 } else { 1565 bs.nesting++; 1566 } 1567 final FilterStats fs = inflight.mFilterStats; 1568 fs.count++; 1569 if (fs.nesting == 0) { 1570 fs.nesting = 1; 1571 fs.startTime = nowELAPSED; 1572 } else { 1573 fs.nesting++; 1574 } 1575 if (alarm.type == ELAPSED_REALTIME_WAKEUP 1576 || alarm.type == RTC_WAKEUP) { 1577 bs.numWakeup++; 1578 fs.numWakeup++; 1579 if (alarm.workSource != null && alarm.workSource.size() > 0) { 1580 for (int wi=0; wi<alarm.workSource.size(); wi++) { 1581 ActivityManagerNative.noteWakeupAlarm( 1582 alarm.operation, alarm.workSource.get(wi), 1583 alarm.workSource.getName(wi)); 1584 } 1585 } else { 1586 ActivityManagerNative.noteWakeupAlarm( 1587 alarm.operation, -1, null); 1588 } 1589 } 1590 } catch (PendingIntent.CanceledException e) { 1591 if (alarm.repeatInterval > 0) { 1592 // This IntentSender is no longer valid, but this 1593 // is a repeating alarm, so toss the hoser. 1594 removeImpl(alarm.operation); 1595 } 1596 } catch (RuntimeException e) { 1597 Slog.w(TAG, "Failure sending alarm.", e); 1598 } 1599 } 1600 } 1601 1602 private class AlarmThread extends Thread 1603 { 1604 public AlarmThread() 1605 { 1606 super("AlarmManager"); 1607 } 1608 1609 public void run() 1610 { 1611 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); 1612 1613 while (true) 1614 { 1615 int result = waitForAlarm(mNativeData); 1616 1617 triggerList.clear(); 1618 1619 if ((result & TIME_CHANGED_MASK) != 0) { 1620 if (DEBUG_BATCH) { 1621 Slog.v(TAG, "Time changed notification from kernel; rebatching"); 1622 } 1623 removeImpl(mTimeTickSender); 1624 rebatchAllAlarms(); 1625 mClockReceiver.scheduleTimeTickEvent(); 1626 synchronized (mLock) { 1627 mNumTimeChanged++; 1628 } 1629 Intent intent = new Intent(Intent.ACTION_TIME_CHANGED); 1630 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING 1631 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1632 getContext().sendBroadcastAsUser(intent, UserHandle.ALL); 1633 } 1634 1635 synchronized (mLock) { 1636 final long nowRTC = System.currentTimeMillis(); 1637 final long nowELAPSED = SystemClock.elapsedRealtime(); 1638 if (localLOGV) Slog.v( 1639 TAG, "Checking for alarms... rtc=" + nowRTC 1640 + ", elapsed=" + nowELAPSED); 1641 1642 if (WAKEUP_STATS) { 1643 if ((result & IS_WAKEUP_MASK) != 0) { 1644 long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD; 1645 int n = 0; 1646 for (WakeupEvent event : mRecentWakeups) { 1647 if (event.when > newEarliest) break; 1648 n++; // number of now-stale entries at the list head 1649 } 1650 for (int i = 0; i < n; i++) { 1651 mRecentWakeups.remove(); 1652 } 1653 1654 recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC); 1655 } 1656 } 1657 1658 boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); 1659 if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) { 1660 // if there are no wakeup alarms and the screen is off, we can 1661 // delay what we have so far until the future. 1662 if (mPendingNonWakeupAlarms.size() == 0) { 1663 mStartCurrentDelayTime = nowELAPSED; 1664 mNextNonWakeupDeliveryTime = nowELAPSED 1665 + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2); 1666 } 1667 mPendingNonWakeupAlarms.addAll(triggerList); 1668 mNumDelayedAlarms += triggerList.size(); 1669 rescheduleKernelAlarmsLocked(); 1670 updateNextAlarmClockLocked(); 1671 } else { 1672 // now deliver the alarm intents; if there are pending non-wakeup 1673 // alarms, we need to merge them in to the list. note we don't 1674 // just deliver them first because we generally want non-wakeup 1675 // alarms delivered after wakeup alarms. 1676 rescheduleKernelAlarmsLocked(); 1677 updateNextAlarmClockLocked(); 1678 if (mPendingNonWakeupAlarms.size() > 0) { 1679 triggerList.addAll(mPendingNonWakeupAlarms); 1680 Collections.sort(triggerList, mAlarmDispatchComparator); 1681 final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime; 1682 mTotalDelayTime += thisDelayTime; 1683 if (mMaxDelayTime < thisDelayTime) { 1684 mMaxDelayTime = thisDelayTime; 1685 } 1686 mPendingNonWakeupAlarms.clear(); 1687 } 1688 deliverAlarmsLocked(triggerList, nowELAPSED); 1689 } 1690 } 1691 } 1692 } 1693 } 1694 1695 /** 1696 * Attribute blame for a WakeLock. 1697 * @param pi PendingIntent to attribute blame to if ws is null. 1698 * @param ws WorkSource to attribute blame. 1699 */ 1700 void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag, 1701 boolean first) { 1702 try { 1703 final boolean unimportant = pi == mTimeTickSender; 1704 mWakeLock.setUnimportantForLogging(unimportant); 1705 if (first || mLastWakeLockUnimportantForLogging) { 1706 mWakeLock.setHistoryTag(tag); 1707 } else { 1708 mWakeLock.setHistoryTag(null); 1709 } 1710 mLastWakeLockUnimportantForLogging = unimportant; 1711 if (ws != null) { 1712 mWakeLock.setWorkSource(ws); 1713 return; 1714 } 1715 1716 final int uid = ActivityManagerNative.getDefault() 1717 .getUidForIntentSender(pi.getTarget()); 1718 if (uid >= 0) { 1719 mWakeLock.setWorkSource(new WorkSource(uid)); 1720 return; 1721 } 1722 } catch (Exception e) { 1723 } 1724 1725 // Something went wrong; fall back to attributing the lock to the OS 1726 mWakeLock.setWorkSource(null); 1727 } 1728 1729 private class AlarmHandler extends Handler { 1730 public static final int ALARM_EVENT = 1; 1731 public static final int MINUTE_CHANGE_EVENT = 2; 1732 public static final int DATE_CHANGE_EVENT = 3; 1733 public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 4; 1734 1735 public AlarmHandler() { 1736 } 1737 1738 public void handleMessage(Message msg) { 1739 if (msg.what == ALARM_EVENT) { 1740 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); 1741 synchronized (mLock) { 1742 final long nowRTC = System.currentTimeMillis(); 1743 final long nowELAPSED = SystemClock.elapsedRealtime(); 1744 triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); 1745 updateNextAlarmClockLocked(); 1746 } 1747 1748 // now trigger the alarms without the lock held 1749 for (int i=0; i<triggerList.size(); i++) { 1750 Alarm alarm = triggerList.get(i); 1751 try { 1752 alarm.operation.send(); 1753 } catch (PendingIntent.CanceledException e) { 1754 if (alarm.repeatInterval > 0) { 1755 // This IntentSender is no longer valid, but this 1756 // is a repeating alarm, so toss the hoser. 1757 removeImpl(alarm.operation); 1758 } 1759 } 1760 } 1761 } else if (msg.what == SEND_NEXT_ALARM_CLOCK_CHANGED) { 1762 sendNextAlarmClockChanged(); 1763 } 1764 } 1765 } 1766 1767 class ClockReceiver extends BroadcastReceiver { 1768 public ClockReceiver() { 1769 IntentFilter filter = new IntentFilter(); 1770 filter.addAction(Intent.ACTION_TIME_TICK); 1771 filter.addAction(Intent.ACTION_DATE_CHANGED); 1772 getContext().registerReceiver(this, filter); 1773 } 1774 1775 @Override 1776 public void onReceive(Context context, Intent intent) { 1777 if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) { 1778 if (DEBUG_BATCH) { 1779 Slog.v(TAG, "Received TIME_TICK alarm; rescheduling"); 1780 } 1781 scheduleTimeTickEvent(); 1782 } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) { 1783 // Since the kernel does not keep track of DST, we need to 1784 // reset the TZ information at the beginning of each day 1785 // based off of the current Zone gmt offset + userspace tracked 1786 // daylight savings information. 1787 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY)); 1788 int gmtOffset = zone.getOffset(System.currentTimeMillis()); 1789 setKernelTimezone(mNativeData, -(gmtOffset / 60000)); 1790 scheduleDateChangedEvent(); 1791 } 1792 } 1793 1794 public void scheduleTimeTickEvent() { 1795 final long currentTime = System.currentTimeMillis(); 1796 final long nextTime = 60000 * ((currentTime / 60000) + 1); 1797 1798 // Schedule this event for the amount of time that it would take to get to 1799 // the top of the next minute. 1800 final long tickEventDelay = nextTime - currentTime; 1801 1802 final WorkSource workSource = null; // Let system take blame for time tick events. 1803 setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0, 1804 0, mTimeTickSender, true, workSource, null); 1805 } 1806 1807 public void scheduleDateChangedEvent() { 1808 Calendar calendar = Calendar.getInstance(); 1809 calendar.setTimeInMillis(System.currentTimeMillis()); 1810 calendar.set(Calendar.HOUR, 0); 1811 calendar.set(Calendar.MINUTE, 0); 1812 calendar.set(Calendar.SECOND, 0); 1813 calendar.set(Calendar.MILLISECOND, 0); 1814 calendar.add(Calendar.DAY_OF_MONTH, 1); 1815 1816 final WorkSource workSource = null; // Let system take blame for date change events. 1817 setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource, 1818 null); 1819 } 1820 } 1821 1822 class InteractiveStateReceiver extends BroadcastReceiver { 1823 public InteractiveStateReceiver() { 1824 IntentFilter filter = new IntentFilter(); 1825 filter.addAction(Intent.ACTION_SCREEN_OFF); 1826 filter.addAction(Intent.ACTION_SCREEN_ON); 1827 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 1828 getContext().registerReceiver(this, filter); 1829 } 1830 1831 @Override 1832 public void onReceive(Context context, Intent intent) { 1833 synchronized (mLock) { 1834 interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction())); 1835 } 1836 } 1837 } 1838 1839 class UninstallReceiver extends BroadcastReceiver { 1840 public UninstallReceiver() { 1841 IntentFilter filter = new IntentFilter(); 1842 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1843 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 1844 filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 1845 filter.addDataScheme("package"); 1846 getContext().registerReceiver(this, filter); 1847 // Register for events related to sdcard installation. 1848 IntentFilter sdFilter = new IntentFilter(); 1849 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 1850 sdFilter.addAction(Intent.ACTION_USER_STOPPED); 1851 getContext().registerReceiver(this, sdFilter); 1852 } 1853 1854 @Override 1855 public void onReceive(Context context, Intent intent) { 1856 synchronized (mLock) { 1857 String action = intent.getAction(); 1858 String pkgList[] = null; 1859 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { 1860 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 1861 for (String packageName : pkgList) { 1862 if (lookForPackageLocked(packageName)) { 1863 setResultCode(Activity.RESULT_OK); 1864 return; 1865 } 1866 } 1867 return; 1868 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 1869 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1870 } else if (Intent.ACTION_USER_STOPPED.equals(action)) { 1871 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 1872 if (userHandle >= 0) { 1873 removeUserLocked(userHandle); 1874 } 1875 } else { 1876 if (Intent.ACTION_PACKAGE_REMOVED.equals(action) 1877 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 1878 // This package is being updated; don't kill its alarms. 1879 return; 1880 } 1881 Uri data = intent.getData(); 1882 if (data != null) { 1883 String pkg = data.getSchemeSpecificPart(); 1884 if (pkg != null) { 1885 pkgList = new String[]{pkg}; 1886 } 1887 } 1888 } 1889 if (pkgList != null && (pkgList.length > 0)) { 1890 for (String pkg : pkgList) { 1891 removeLocked(pkg); 1892 for (int i=mBroadcastStats.size()-1; i>=0; i--) { 1893 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i); 1894 if (uidStats.remove(pkg) != null) { 1895 if (uidStats.size() <= 0) { 1896 mBroadcastStats.removeAt(i); 1897 } 1898 } 1899 } 1900 } 1901 } 1902 } 1903 } 1904 } 1905 1906 private final BroadcastStats getStatsLocked(PendingIntent pi) { 1907 String pkg = pi.getCreatorPackage(); 1908 int uid = pi.getCreatorUid(); 1909 ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid); 1910 if (uidStats == null) { 1911 uidStats = new ArrayMap<String, BroadcastStats>(); 1912 mBroadcastStats.put(uid, uidStats); 1913 } 1914 BroadcastStats bs = uidStats.get(pkg); 1915 if (bs == null) { 1916 bs = new BroadcastStats(uid, pkg); 1917 uidStats.put(pkg, bs); 1918 } 1919 return bs; 1920 } 1921 1922 class ResultReceiver implements PendingIntent.OnFinished { 1923 public void onSendFinished(PendingIntent pi, Intent intent, int resultCode, 1924 String resultData, Bundle resultExtras) { 1925 synchronized (mLock) { 1926 InFlight inflight = null; 1927 for (int i=0; i<mInFlight.size(); i++) { 1928 if (mInFlight.get(i).mPendingIntent == pi) { 1929 inflight = mInFlight.remove(i); 1930 break; 1931 } 1932 } 1933 if (inflight != null) { 1934 final long nowELAPSED = SystemClock.elapsedRealtime(); 1935 BroadcastStats bs = inflight.mBroadcastStats; 1936 bs.nesting--; 1937 if (bs.nesting <= 0) { 1938 bs.nesting = 0; 1939 bs.aggregateTime += nowELAPSED - bs.startTime; 1940 } 1941 FilterStats fs = inflight.mFilterStats; 1942 fs.nesting--; 1943 if (fs.nesting <= 0) { 1944 fs.nesting = 0; 1945 fs.aggregateTime += nowELAPSED - fs.startTime; 1946 } 1947 } else { 1948 mLog.w("No in-flight alarm for " + pi + " " + intent); 1949 } 1950 mBroadcastRefCount--; 1951 if (mBroadcastRefCount == 0) { 1952 mWakeLock.release(); 1953 if (mInFlight.size() > 0) { 1954 mLog.w("Finished all broadcasts with " + mInFlight.size() 1955 + " remaining inflights"); 1956 for (int i=0; i<mInFlight.size(); i++) { 1957 mLog.w(" Remaining #" + i + ": " + mInFlight.get(i)); 1958 } 1959 mInFlight.clear(); 1960 } 1961 } else { 1962 // the next of our alarms is now in flight. reattribute the wakelock. 1963 if (mInFlight.size() > 0) { 1964 InFlight inFlight = mInFlight.get(0); 1965 setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource, 1966 inFlight.mAlarmType, inFlight.mTag, false); 1967 } else { 1968 // should never happen 1969 mLog.w("Alarm wakelock still held but sent queue empty"); 1970 mWakeLock.setWorkSource(null); 1971 } 1972 } 1973 } 1974 } 1975 } 1976} 1977