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