1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server; 18 19 import android.app.ActivityManagerNative; 20 import android.app.AlarmManager; 21 import android.app.IAlarmManager; 22 import android.app.PendingIntent; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.pm.PackageManager; 28 import android.net.Uri; 29 import android.os.Binder; 30 import android.os.Bundle; 31 import android.os.Handler; 32 import android.os.Message; 33 import android.os.PowerManager; 34 import android.os.SystemClock; 35 import android.os.SystemProperties; 36 import android.text.TextUtils; 37 import android.text.format.Time; 38 import android.util.EventLog; 39 import android.util.Log; 40 41 import java.io.FileDescriptor; 42 import java.io.PrintWriter; 43 import java.util.ArrayList; 44 import java.util.Calendar; 45 import java.util.Collections; 46 import java.util.Comparator; 47 import java.util.HashMap; 48 import java.util.Iterator; 49 import java.util.Map; 50 import java.util.TimeZone; 51 52 class AlarmManagerService extends IAlarmManager.Stub { 53 // The threshold for how long an alarm can be late before we print a 54 // warning message. The time duration is in milliseconds. 55 private static final long LATE_ALARM_THRESHOLD = 10 * 1000; 56 57 private static final int RTC_WAKEUP_MASK = 1 << AlarmManager.RTC_WAKEUP; 58 private static final int RTC_MASK = 1 << AlarmManager.RTC; 59 private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << AlarmManager.ELAPSED_REALTIME_WAKEUP; 60 private static final int ELAPSED_REALTIME_MASK = 1 << AlarmManager.ELAPSED_REALTIME; 61 private static final int TIME_CHANGED_MASK = 1 << 16; 62 63 private static final String TAG = "AlarmManager"; 64 private static final String ClockReceiver_TAG = "ClockReceiver"; 65 private static final boolean localLOGV = false; 66 private static final int ALARM_EVENT = 1; 67 private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; 68 69 private static final Intent mBackgroundIntent 70 = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND); 71 72 private final Context mContext; 73 74 private Object mLock = new Object(); 75 76 private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>(); 77 private final ArrayList<Alarm> mRtcAlarms = new ArrayList<Alarm>(); 78 private final ArrayList<Alarm> mElapsedRealtimeWakeupAlarms = new ArrayList<Alarm>(); 79 private final ArrayList<Alarm> mElapsedRealtimeAlarms = new ArrayList<Alarm>(); 80 private final IncreasingTimeOrder mIncreasingTimeOrder = new IncreasingTimeOrder(); 81 82 // slots corresponding with the inexact-repeat interval buckets, 83 // ordered from shortest to longest 84 private static final long sInexactSlotIntervals[] = { 85 AlarmManager.INTERVAL_FIFTEEN_MINUTES, 86 AlarmManager.INTERVAL_HALF_HOUR, 87 AlarmManager.INTERVAL_HOUR, 88 AlarmManager.INTERVAL_HALF_DAY, 89 AlarmManager.INTERVAL_DAY 90 }; 91 private long mInexactDeliveryTimes[] = { 0, 0, 0, 0, 0}; 92 93 private int mDescriptor; 94 private int mBroadcastRefCount = 0; 95 private PowerManager.WakeLock mWakeLock; 96 private final AlarmThread mWaitThread = new AlarmThread(); 97 private final AlarmHandler mHandler = new AlarmHandler(); 98 private ClockReceiver mClockReceiver; 99 private UninstallReceiver mUninstallReceiver; 100 private final ResultReceiver mResultReceiver = new ResultReceiver(); 101 private final PendingIntent mTimeTickSender; 102 private final PendingIntent mDateChangeSender; 103 104 private static final class FilterStats { 105 int count; 106 } 107 108 private static final class BroadcastStats { 109 long aggregateTime; 110 int numWakeup; 111 long startTime; 112 int nesting; 113 HashMap<Intent.FilterComparison, FilterStats> filterStats 114 = new HashMap<Intent.FilterComparison, FilterStats>(); 115 } 116 117 private final HashMap<String, BroadcastStats> mBroadcastStats 118 = new HashMap<String, BroadcastStats>(); 119 AlarmManagerService(Context context)120 public AlarmManagerService(Context context) { 121 mContext = context; 122 mDescriptor = init(); 123 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 124 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 125 126 mTimeTickSender = PendingIntent.getBroadcast(context, 0, 127 new Intent(Intent.ACTION_TIME_TICK).addFlags( 128 Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0); 129 mDateChangeSender = PendingIntent.getBroadcast(context, 0, 130 new Intent(Intent.ACTION_DATE_CHANGED), 0); 131 132 // now that we have initied the driver schedule the alarm 133 mClockReceiver= new ClockReceiver(); 134 mClockReceiver.scheduleTimeTickEvent(); 135 mClockReceiver.scheduleDateChangedEvent(); 136 mUninstallReceiver = new UninstallReceiver(); 137 138 if (mDescriptor != -1) { 139 mWaitThread.start(); 140 } else { 141 Log.w(TAG, "Failed to open alarm driver. Falling back to a handler."); 142 } 143 } 144 finalize()145 protected void finalize() throws Throwable { 146 try { 147 close(mDescriptor); 148 } finally { 149 super.finalize(); 150 } 151 } 152 set(int type, long triggerAtTime, PendingIntent operation)153 public void set(int type, long triggerAtTime, PendingIntent operation) { 154 setRepeating(type, triggerAtTime, 0, operation); 155 } 156 setRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)157 public void setRepeating(int type, long triggerAtTime, long interval, 158 PendingIntent operation) { 159 if (operation == null) { 160 Log.w(TAG, "set/setRepeating ignored because there is no intent"); 161 return; 162 } 163 synchronized (mLock) { 164 Alarm alarm = new Alarm(); 165 alarm.type = type; 166 alarm.when = triggerAtTime; 167 alarm.repeatInterval = interval; 168 alarm.operation = operation; 169 170 // Remove this alarm if already scheduled. 171 removeLocked(operation); 172 173 if (localLOGV) Log.v(TAG, "set: " + alarm); 174 175 int index = addAlarmLocked(alarm); 176 if (index == 0) { 177 setLocked(alarm); 178 } 179 } 180 } 181 setInexactRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)182 public void setInexactRepeating(int type, long triggerAtTime, long interval, 183 PendingIntent operation) { 184 if (operation == null) { 185 Log.w(TAG, "setInexactRepeating ignored because there is no intent"); 186 return; 187 } 188 189 // find the slot in the delivery-times array that we will use 190 int intervalSlot; 191 for (intervalSlot = 0; intervalSlot < sInexactSlotIntervals.length; intervalSlot++) { 192 if (sInexactSlotIntervals[intervalSlot] == interval) { 193 break; 194 } 195 } 196 197 // Non-bucket intervals just fall back to the less-efficient 198 // unbucketed recurring alarm implementation 199 if (intervalSlot >= sInexactSlotIntervals.length) { 200 setRepeating(type, triggerAtTime, interval, operation); 201 return; 202 } 203 204 // Align bucketed alarm deliveries by trying to match 205 // the shortest-interval bucket already scheduled 206 long bucketTime = 0; 207 for (int slot = 0; slot < mInexactDeliveryTimes.length; slot++) { 208 if (mInexactDeliveryTimes[slot] > 0) { 209 bucketTime = mInexactDeliveryTimes[slot]; 210 break; 211 } 212 } 213 214 if (bucketTime == 0) { 215 // If nothing is scheduled yet, just start at the requested time 216 bucketTime = triggerAtTime; 217 } else { 218 // Align the new alarm with the existing bucketed sequence. To achieve 219 // alignment, we slide the start time around by min{interval, slot interval} 220 long adjustment = (interval <= sInexactSlotIntervals[intervalSlot]) 221 ? interval : sInexactSlotIntervals[intervalSlot]; 222 223 // The bucket may have started in the past; adjust 224 while (bucketTime < triggerAtTime) { 225 bucketTime += adjustment; 226 } 227 228 // Or the bucket may be set to start more than an interval beyond 229 // our requested trigger time; pull it back to meet our needs 230 while (bucketTime > triggerAtTime + adjustment) { 231 bucketTime -= adjustment; 232 } 233 } 234 235 // Remember where this bucket started (reducing the amount of later 236 // fixup required) and set the alarm with the new, bucketed start time. 237 if (localLOGV) Log.v(TAG, "setInexactRepeating: interval=" + interval 238 + " bucketTime=" + bucketTime); 239 mInexactDeliveryTimes[intervalSlot] = bucketTime; 240 setRepeating(type, bucketTime, interval, operation); 241 } 242 setTimeZone(String tz)243 public void setTimeZone(String tz) { 244 mContext.enforceCallingOrSelfPermission( 245 "android.permission.SET_TIME_ZONE", 246 "setTimeZone"); 247 248 if (TextUtils.isEmpty(tz)) return; 249 TimeZone zone = TimeZone.getTimeZone(tz); 250 // Prevent reentrant calls from stepping on each other when writing 251 // the time zone property 252 boolean timeZoneWasChanged = false; 253 synchronized (this) { 254 String current = SystemProperties.get(TIMEZONE_PROPERTY); 255 if (current == null || !current.equals(zone.getID())) { 256 if (localLOGV) Log.v(TAG, "timezone changed: " + current + ", new=" + zone.getID()); 257 timeZoneWasChanged = true; 258 SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); 259 } 260 261 // Update the kernel timezone information 262 // Kernel tracks time offsets as 'minutes west of GMT' 263 int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000; 264 setKernelTimezone(mDescriptor, -(gmtOffset)); 265 } 266 267 TimeZone.setDefault(null); 268 269 if (timeZoneWasChanged) { 270 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); 271 intent.putExtra("time-zone", zone.getID()); 272 mContext.sendBroadcast(intent); 273 } 274 } 275 remove(PendingIntent operation)276 public void remove(PendingIntent operation) { 277 if (operation == null) { 278 return; 279 } 280 synchronized (mLock) { 281 removeLocked(operation); 282 } 283 } 284 removeLocked(PendingIntent operation)285 public void removeLocked(PendingIntent operation) { 286 removeLocked(mRtcWakeupAlarms, operation); 287 removeLocked(mRtcAlarms, operation); 288 removeLocked(mElapsedRealtimeWakeupAlarms, operation); 289 removeLocked(mElapsedRealtimeAlarms, operation); 290 } 291 removeLocked(ArrayList<Alarm> alarmList, PendingIntent operation)292 private void removeLocked(ArrayList<Alarm> alarmList, 293 PendingIntent operation) { 294 if (alarmList.size() <= 0) { 295 return; 296 } 297 298 // iterator over the list removing any it where the intent match 299 Iterator<Alarm> it = alarmList.iterator(); 300 301 while (it.hasNext()) { 302 Alarm alarm = it.next(); 303 if (alarm.operation.equals(operation)) { 304 it.remove(); 305 } 306 } 307 } 308 removeLocked(String packageName)309 public void removeLocked(String packageName) { 310 removeLocked(mRtcWakeupAlarms, packageName); 311 removeLocked(mRtcAlarms, packageName); 312 removeLocked(mElapsedRealtimeWakeupAlarms, packageName); 313 removeLocked(mElapsedRealtimeAlarms, packageName); 314 } 315 removeLocked(ArrayList<Alarm> alarmList, String packageName)316 private void removeLocked(ArrayList<Alarm> alarmList, 317 String packageName) { 318 if (alarmList.size() <= 0) { 319 return; 320 } 321 322 // iterator over the list removing any it where the intent match 323 Iterator<Alarm> it = alarmList.iterator(); 324 325 while (it.hasNext()) { 326 Alarm alarm = it.next(); 327 if (alarm.operation.getTargetPackage().equals(packageName)) { 328 it.remove(); 329 } 330 } 331 } 332 getAlarmList(int type)333 private ArrayList<Alarm> getAlarmList(int type) { 334 switch (type) { 335 case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms; 336 case AlarmManager.RTC: return mRtcAlarms; 337 case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms; 338 case AlarmManager.ELAPSED_REALTIME: return mElapsedRealtimeAlarms; 339 } 340 341 return null; 342 } 343 addAlarmLocked(Alarm alarm)344 private int addAlarmLocked(Alarm alarm) { 345 ArrayList<Alarm> alarmList = getAlarmList(alarm.type); 346 347 int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder); 348 if (index < 0) { 349 index = 0 - index - 1; 350 } 351 if (localLOGV) Log.v(TAG, "Adding alarm " + alarm + " at " + index); 352 alarmList.add(index, alarm); 353 354 if (localLOGV) { 355 // Display the list of alarms for this alarm type 356 Log.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type); 357 int position = 0; 358 for (Alarm a : alarmList) { 359 Time time = new Time(); 360 time.set(a.when); 361 String timeStr = time.format("%b %d %I:%M:%S %p"); 362 Log.v(TAG, position + ": " + timeStr 363 + " " + a.operation.getTargetPackage()); 364 position += 1; 365 } 366 } 367 368 return index; 369 } 370 timeToNextAlarm()371 public long timeToNextAlarm() { 372 long nextAlarm = 0xfffffffffffffffl; 373 synchronized (mLock) { 374 for (int i=AlarmManager.RTC_WAKEUP; 375 i<=AlarmManager.ELAPSED_REALTIME; i++) { 376 ArrayList<Alarm> alarmList = getAlarmList(i); 377 if (alarmList.size() > 0) { 378 Alarm a = alarmList.get(0); 379 if (a.when < nextAlarm) { 380 nextAlarm = a.when; 381 } 382 } 383 } 384 } 385 return nextAlarm; 386 } 387 setLocked(Alarm alarm)388 private void setLocked(Alarm alarm) 389 { 390 if (mDescriptor != -1) 391 { 392 set(mDescriptor, alarm.type, (alarm.when * 1000 * 1000)); 393 } 394 else 395 { 396 Message msg = Message.obtain(); 397 msg.what = ALARM_EVENT; 398 399 mHandler.removeMessages(ALARM_EVENT); 400 mHandler.sendMessageAtTime(msg, alarm.when); 401 } 402 } 403 404 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)405 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 406 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 407 != PackageManager.PERMISSION_GRANTED) { 408 pw.println("Permission Denial: can't dump AlarmManager from from pid=" 409 + Binder.getCallingPid() 410 + ", uid=" + Binder.getCallingUid()); 411 return; 412 } 413 414 synchronized (mLock) { 415 pw.println("Current Alarm Manager state:"); 416 if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) { 417 pw.println(" "); 418 pw.print(" Realtime wakeup (now="); 419 pw.print(System.currentTimeMillis()); pw.println("):"); 420 if (mRtcWakeupAlarms.size() > 0) { 421 dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP"); 422 } 423 if (mRtcAlarms.size() > 0) { 424 dumpAlarmList(pw, mRtcAlarms, " ", "RTC"); 425 } 426 } 427 if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) { 428 pw.println(" "); 429 pw.print(" Elapsed realtime wakeup (now="); 430 pw.print(SystemClock.elapsedRealtime()); pw.println("):"); 431 if (mElapsedRealtimeWakeupAlarms.size() > 0) { 432 dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP"); 433 } 434 if (mElapsedRealtimeAlarms.size() > 0) { 435 dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED"); 436 } 437 } 438 439 pw.println(" "); 440 pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount); 441 442 pw.println(" "); 443 pw.println(" Alarm Stats:"); 444 for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) { 445 BroadcastStats bs = be.getValue(); 446 pw.print(" "); pw.println(be.getKey()); 447 pw.print(" "); pw.print(bs.aggregateTime); 448 pw.print("ms running, "); pw.print(bs.numWakeup); 449 pw.println(" wakeups"); 450 for (Map.Entry<Intent.FilterComparison, FilterStats> fe 451 : bs.filterStats.entrySet()) { 452 pw.print(" "); pw.print(fe.getValue().count); 453 pw.print(" alarms: "); 454 pw.println(fe.getKey().getIntent().toShortString(true, false)); 455 } 456 } 457 } 458 } 459 dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, String prefix, String label)460 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, String prefix, String label) { 461 for (int i=list.size()-1; i>=0; i--) { 462 Alarm a = list.get(i); 463 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); 464 pw.print(": "); pw.println(a); 465 a.dump(pw, prefix + " "); 466 } 467 } 468 init()469 private native int init(); close(int fd)470 private native void close(int fd); set(int fd, int type, long nanoseconds)471 private native void set(int fd, int type, long nanoseconds); waitForAlarm(int fd)472 private native int waitForAlarm(int fd); setKernelTimezone(int fd, int minuteswest)473 private native int setKernelTimezone(int fd, int minuteswest); 474 triggerAlarmsLocked(ArrayList<Alarm> alarmList, ArrayList<Alarm> triggerList, long now)475 private void triggerAlarmsLocked(ArrayList<Alarm> alarmList, 476 ArrayList<Alarm> triggerList, 477 long now) 478 { 479 Iterator<Alarm> it = alarmList.iterator(); 480 ArrayList<Alarm> repeats = new ArrayList<Alarm>(); 481 482 while (it.hasNext()) 483 { 484 Alarm alarm = it.next(); 485 486 if (localLOGV) Log.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm); 487 488 if (alarm.when > now) { 489 // don't fire alarms in the future 490 break; 491 } 492 493 // If the alarm is late, then print a warning message. 494 // Note that this can happen if the user creates a new event on 495 // the Calendar app with a reminder that is in the past. In that 496 // case, the reminder alarm will fire immediately. 497 if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) { 498 Log.v(TAG, "alarm is late! alarm time: " + alarm.when 499 + " now: " + now + " delay (in seconds): " 500 + (now - alarm.when) / 1000); 501 } 502 503 // Recurring alarms may have passed several alarm intervals while the 504 // phone was asleep or off, so pass a trigger count when sending them. 505 if (localLOGV) Log.v(TAG, "Alarm triggering: " + alarm); 506 alarm.count = 1; 507 if (alarm.repeatInterval > 0) { 508 // this adjustment will be zero if we're late by 509 // less than one full repeat interval 510 alarm.count += (now - alarm.when) / alarm.repeatInterval; 511 } 512 triggerList.add(alarm); 513 514 // remove the alarm from the list 515 it.remove(); 516 517 // if it repeats queue it up to be read-added to the list 518 if (alarm.repeatInterval > 0) { 519 repeats.add(alarm); 520 } 521 } 522 523 // reset any repeating alarms. 524 it = repeats.iterator(); 525 while (it.hasNext()) { 526 Alarm alarm = it.next(); 527 alarm.when += alarm.count * alarm.repeatInterval; 528 addAlarmLocked(alarm); 529 } 530 531 if (alarmList.size() > 0) { 532 setLocked(alarmList.get(0)); 533 } 534 } 535 536 /** 537 * This Comparator sorts Alarms into increasing time order. 538 */ 539 public static class IncreasingTimeOrder implements Comparator<Alarm> { compare(Alarm a1, Alarm a2)540 public int compare(Alarm a1, Alarm a2) { 541 long when1 = a1.when; 542 long when2 = a2.when; 543 if (when1 - when2 > 0) { 544 return 1; 545 } 546 if (when1 - when2 < 0) { 547 return -1; 548 } 549 return 0; 550 } 551 } 552 553 private static class Alarm { 554 public int type; 555 public int count; 556 public long when; 557 public long repeatInterval; 558 public PendingIntent operation; 559 Alarm()560 public Alarm() { 561 when = 0; 562 repeatInterval = 0; 563 operation = null; 564 } 565 566 @Override toString()567 public String toString() 568 { 569 StringBuilder sb = new StringBuilder(128); 570 sb.append("Alarm{"); 571 sb.append(Integer.toHexString(System.identityHashCode(this))); 572 sb.append(" type "); 573 sb.append(type); 574 sb.append(" "); 575 sb.append(operation.getTargetPackage()); 576 sb.append('}'); 577 return sb.toString(); 578 } 579 dump(PrintWriter pw, String prefix)580 public void dump(PrintWriter pw, String prefix) 581 { 582 pw.print(prefix); pw.print("type="); pw.print(type); 583 pw.print(" when="); pw.print(when); 584 pw.print(" repeatInterval="); pw.print(repeatInterval); 585 pw.print(" count="); pw.println(count); 586 pw.print(prefix); pw.print("operation="); pw.println(operation); 587 } 588 } 589 590 private class AlarmThread extends Thread 591 { AlarmThread()592 public AlarmThread() 593 { 594 super("AlarmManager"); 595 } 596 run()597 public void run() 598 { 599 while (true) 600 { 601 int result = waitForAlarm(mDescriptor); 602 603 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); 604 605 if ((result & TIME_CHANGED_MASK) != 0) { 606 remove(mTimeTickSender); 607 mClockReceiver.scheduleTimeTickEvent(); 608 mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_CHANGED)); 609 } 610 611 synchronized (mLock) { 612 final long nowRTC = System.currentTimeMillis(); 613 final long nowELAPSED = SystemClock.elapsedRealtime(); 614 if (localLOGV) Log.v( 615 TAG, "Checking for alarms... rtc=" + nowRTC 616 + ", elapsed=" + nowELAPSED); 617 618 if ((result & RTC_WAKEUP_MASK) != 0) 619 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); 620 621 if ((result & RTC_MASK) != 0) 622 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); 623 624 if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0) 625 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED); 626 627 if ((result & ELAPSED_REALTIME_MASK) != 0) 628 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED); 629 630 // now trigger the alarms 631 Iterator<Alarm> it = triggerList.iterator(); 632 while (it.hasNext()) { 633 Alarm alarm = it.next(); 634 try { 635 if (localLOGV) Log.v(TAG, "sending alarm " + alarm); 636 alarm.operation.send(mContext, 0, 637 mBackgroundIntent.putExtra( 638 Intent.EXTRA_ALARM_COUNT, alarm.count), 639 mResultReceiver, mHandler); 640 641 // we have an active broadcast so stay awake. 642 if (mBroadcastRefCount == 0) { 643 mWakeLock.acquire(); 644 } 645 mBroadcastRefCount++; 646 647 BroadcastStats bs = getStatsLocked(alarm.operation); 648 if (bs.nesting == 0) { 649 bs.startTime = nowELAPSED; 650 } else { 651 bs.nesting++; 652 } 653 if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP 654 || alarm.type == AlarmManager.RTC_WAKEUP) { 655 bs.numWakeup++; 656 ActivityManagerNative.noteWakeupAlarm( 657 alarm.operation); 658 } 659 } catch (PendingIntent.CanceledException e) { 660 if (alarm.repeatInterval > 0) { 661 // This IntentSender is no longer valid, but this 662 // is a repeating alarm, so toss the hoser. 663 remove(alarm.operation); 664 } 665 } catch (RuntimeException e) { 666 Log.w(TAG, "Failure sending alarm.", e); 667 } 668 } 669 } 670 } 671 } 672 } 673 674 private class AlarmHandler extends Handler { 675 public static final int ALARM_EVENT = 1; 676 public static final int MINUTE_CHANGE_EVENT = 2; 677 public static final int DATE_CHANGE_EVENT = 3; 678 AlarmHandler()679 public AlarmHandler() { 680 } 681 handleMessage(Message msg)682 public void handleMessage(Message msg) { 683 if (msg.what == ALARM_EVENT) { 684 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); 685 synchronized (mLock) { 686 final long nowRTC = System.currentTimeMillis(); 687 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); 688 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); 689 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC); 690 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC); 691 } 692 693 // now trigger the alarms without the lock held 694 Iterator<Alarm> it = triggerList.iterator(); 695 while (it.hasNext()) 696 { 697 Alarm alarm = it.next(); 698 try { 699 alarm.operation.send(); 700 } catch (PendingIntent.CanceledException e) { 701 if (alarm.repeatInterval > 0) { 702 // This IntentSender is no longer valid, but this 703 // is a repeating alarm, so toss the hoser. 704 remove(alarm.operation); 705 } 706 } 707 } 708 } 709 } 710 } 711 712 class ClockReceiver extends BroadcastReceiver { ClockReceiver()713 public ClockReceiver() { 714 IntentFilter filter = new IntentFilter(); 715 filter.addAction(Intent.ACTION_TIME_TICK); 716 filter.addAction(Intent.ACTION_DATE_CHANGED); 717 mContext.registerReceiver(this, filter); 718 } 719 720 @Override onReceive(Context context, Intent intent)721 public void onReceive(Context context, Intent intent) { 722 if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) { 723 scheduleTimeTickEvent(); 724 } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) { 725 // Since the kernel does not keep track of DST, we need to 726 // reset the TZ information at the beginning of each day 727 // based off of the current Zone gmt offset + userspace tracked 728 // daylight savings information. 729 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY)); 730 int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000; 731 732 setKernelTimezone(mDescriptor, -(gmtOffset)); 733 scheduleDateChangedEvent(); 734 } 735 } 736 scheduleTimeTickEvent()737 public void scheduleTimeTickEvent() { 738 Calendar calendar = Calendar.getInstance(); 739 calendar.setTimeInMillis(System.currentTimeMillis()); 740 calendar.add(Calendar.MINUTE, 1); 741 calendar.set(Calendar.SECOND, 0); 742 calendar.set(Calendar.MILLISECOND, 0); 743 744 set(AlarmManager.RTC, calendar.getTimeInMillis(), mTimeTickSender); 745 } 746 scheduleDateChangedEvent()747 public void scheduleDateChangedEvent() { 748 Calendar calendar = Calendar.getInstance(); 749 calendar.setTimeInMillis(System.currentTimeMillis()); 750 calendar.set(Calendar.HOUR, 0); 751 calendar.set(Calendar.MINUTE, 0); 752 calendar.set(Calendar.SECOND, 0); 753 calendar.set(Calendar.MILLISECOND, 0); 754 calendar.add(Calendar.DAY_OF_MONTH, 1); 755 756 set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender); 757 } 758 } 759 760 class UninstallReceiver extends BroadcastReceiver { UninstallReceiver()761 public UninstallReceiver() { 762 IntentFilter filter = new IntentFilter(); 763 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 764 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 765 filter.addDataScheme("package"); 766 mContext.registerReceiver(this, filter); 767 } 768 769 @Override onReceive(Context context, Intent intent)770 public void onReceive(Context context, Intent intent) { 771 synchronized (mLock) { 772 Uri data = intent.getData(); 773 if (data != null) { 774 String pkg = data.getSchemeSpecificPart(); 775 removeLocked(pkg); 776 mBroadcastStats.remove(pkg); 777 } 778 } 779 } 780 } 781 getStatsLocked(PendingIntent pi)782 private final BroadcastStats getStatsLocked(PendingIntent pi) { 783 String pkg = pi.getTargetPackage(); 784 BroadcastStats bs = mBroadcastStats.get(pkg); 785 if (bs == null) { 786 bs = new BroadcastStats(); 787 mBroadcastStats.put(pkg, bs); 788 } 789 return bs; 790 } 791 792 class ResultReceiver implements PendingIntent.OnFinished { onSendFinished(PendingIntent pi, Intent intent, int resultCode, String resultData, Bundle resultExtras)793 public void onSendFinished(PendingIntent pi, Intent intent, int resultCode, 794 String resultData, Bundle resultExtras) { 795 synchronized (mLock) { 796 BroadcastStats bs = getStatsLocked(pi); 797 if (bs != null) { 798 bs.nesting--; 799 if (bs.nesting <= 0) { 800 bs.nesting = 0; 801 bs.aggregateTime += SystemClock.elapsedRealtime() 802 - bs.startTime; 803 Intent.FilterComparison fc = new Intent.FilterComparison(intent); 804 FilterStats fs = bs.filterStats.get(fc); 805 if (fs == null) { 806 fs = new FilterStats(); 807 bs.filterStats.put(fc, fs); 808 } 809 fs.count++; 810 } 811 } 812 mBroadcastRefCount--; 813 if (mBroadcastRefCount == 0) { 814 mWakeLock.release(); 815 } 816 } 817 } 818 } 819 } 820