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 // Alignment quantum for inexact repeating alarms 68 private static final long QUANTUM = AlarmManager.INTERVAL_FIFTEEN_MINUTES; 69 70 private static final String TAG = "AlarmManager"; 71 private static final String ClockReceiver_TAG = "ClockReceiver"; 72 private static final boolean localLOGV = false; 73 private static final int ALARM_EVENT = 1; 74 private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; 75 76 private static final Intent mBackgroundIntent 77 = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND); 78 79 private final Context mContext; 80 81 private Object mLock = new Object(); 82 83 private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>(); 84 private final ArrayList<Alarm> mRtcAlarms = new ArrayList<Alarm>(); 85 private final ArrayList<Alarm> mElapsedRealtimeWakeupAlarms = new ArrayList<Alarm>(); 86 private final ArrayList<Alarm> mElapsedRealtimeAlarms = new ArrayList<Alarm>(); 87 private final IncreasingTimeOrder mIncreasingTimeOrder = new IncreasingTimeOrder(); 88 89 private int mDescriptor; 90 private int mBroadcastRefCount = 0; 91 private PowerManager.WakeLock mWakeLock; 92 private final AlarmThread mWaitThread = new AlarmThread(); 93 private final AlarmHandler mHandler = new AlarmHandler(); 94 private ClockReceiver mClockReceiver; 95 private UninstallReceiver mUninstallReceiver; 96 private final ResultReceiver mResultReceiver = new ResultReceiver(); 97 private final PendingIntent mTimeTickSender; 98 private final PendingIntent mDateChangeSender; 99 100 private static final class FilterStats { 101 int count; 102 } 103 104 private static final class BroadcastStats { 105 long aggregateTime; 106 int numWakeup; 107 long startTime; 108 int nesting; 109 HashMap<Intent.FilterComparison, FilterStats> filterStats 110 = new HashMap<Intent.FilterComparison, FilterStats>(); 111 } 112 113 private final HashMap<String, BroadcastStats> mBroadcastStats 114 = new HashMap<String, BroadcastStats>(); 115 116 public AlarmManagerService(Context context) { 117 mContext = context; 118 mDescriptor = init(); 119 120 // We have to set current TimeZone info to kernel 121 // because kernel doesn't keep this after reboot 122 String tz = SystemProperties.get(TIMEZONE_PROPERTY); 123 if (tz != null) { 124 setTimeZone(tz); 125 } 126 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 if (interval <= 0) { 195 Slog.w(TAG, "setInexactRepeating ignored because interval " + interval 196 + " is invalid"); 197 return; 198 } 199 200 // If the requested interval isn't a multiple of 15 minutes, just treat it as exact 201 if (interval % QUANTUM != 0) { 202 if (localLOGV) Slog.v(TAG, "Interval " + interval + " not a quantum multiple"); 203 setRepeating(type, triggerAtTime, interval, operation); 204 return; 205 } 206 207 // Translate times into the ELAPSED timebase for alignment purposes so that 208 // alignment never tries to match against wall clock times. 209 final boolean isRtc = (type == AlarmManager.RTC || type == AlarmManager.RTC_WAKEUP); 210 final long skew = (isRtc) 211 ? System.currentTimeMillis() - SystemClock.elapsedRealtime() 212 : 0; 213 214 // Slip forward to the next ELAPSED-timebase quantum after the stated time. If 215 // we're *at* a quantum point, leave it alone. 216 final long adjustedTriggerTime; 217 long offset = (triggerAtTime - skew) % QUANTUM; 218 if (offset != 0) { 219 adjustedTriggerTime = triggerAtTime - offset + QUANTUM; 220 } else { 221 adjustedTriggerTime = triggerAtTime; 222 } 223 224 // Set the alarm based on the quantum-aligned start time 225 if (localLOGV) Slog.v(TAG, "setInexactRepeating: type=" + type + " interval=" + interval 226 + " trigger=" + adjustedTriggerTime + " orig=" + triggerAtTime); 227 setRepeating(type, adjustedTriggerTime, interval, operation); 228 } 229 230 public void setTime(long millis) { 231 mContext.enforceCallingOrSelfPermission( 232 "android.permission.SET_TIME", 233 "setTime"); 234 235 SystemClock.setCurrentTimeMillis(millis); 236 } 237 238 public void setTimeZone(String tz) { 239 mContext.enforceCallingOrSelfPermission( 240 "android.permission.SET_TIME_ZONE", 241 "setTimeZone"); 242 243 if (TextUtils.isEmpty(tz)) return; 244 TimeZone zone = TimeZone.getTimeZone(tz); 245 // Prevent reentrant calls from stepping on each other when writing 246 // the time zone property 247 boolean timeZoneWasChanged = false; 248 synchronized (this) { 249 String current = SystemProperties.get(TIMEZONE_PROPERTY); 250 if (current == null || !current.equals(zone.getID())) { 251 if (localLOGV) Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID()); 252 timeZoneWasChanged = true; 253 SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); 254 } 255 256 // Update the kernel timezone information 257 // Kernel tracks time offsets as 'minutes west of GMT' 258 int gmtOffset = zone.getOffset(System.currentTimeMillis()); 259 setKernelTimezone(mDescriptor, -(gmtOffset / 60000)); 260 } 261 262 TimeZone.setDefault(null); 263 264 if (timeZoneWasChanged) { 265 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); 266 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 267 intent.putExtra("time-zone", zone.getID()); 268 mContext.sendBroadcast(intent); 269 } 270 } 271 272 public void remove(PendingIntent operation) { 273 if (operation == null) { 274 return; 275 } 276 synchronized (mLock) { 277 removeLocked(operation); 278 } 279 } 280 281 public void removeLocked(PendingIntent operation) { 282 removeLocked(mRtcWakeupAlarms, operation); 283 removeLocked(mRtcAlarms, operation); 284 removeLocked(mElapsedRealtimeWakeupAlarms, operation); 285 removeLocked(mElapsedRealtimeAlarms, operation); 286 } 287 288 private void removeLocked(ArrayList<Alarm> alarmList, 289 PendingIntent operation) { 290 if (alarmList.size() <= 0) { 291 return; 292 } 293 294 // iterator over the list removing any it where the intent match 295 Iterator<Alarm> it = alarmList.iterator(); 296 297 while (it.hasNext()) { 298 Alarm alarm = it.next(); 299 if (alarm.operation.equals(operation)) { 300 it.remove(); 301 } 302 } 303 } 304 305 public void removeLocked(String packageName) { 306 removeLocked(mRtcWakeupAlarms, packageName); 307 removeLocked(mRtcAlarms, packageName); 308 removeLocked(mElapsedRealtimeWakeupAlarms, packageName); 309 removeLocked(mElapsedRealtimeAlarms, packageName); 310 } 311 312 private void removeLocked(ArrayList<Alarm> alarmList, 313 String packageName) { 314 if (alarmList.size() <= 0) { 315 return; 316 } 317 318 // iterator over the list removing any it where the intent match 319 Iterator<Alarm> it = alarmList.iterator(); 320 321 while (it.hasNext()) { 322 Alarm alarm = it.next(); 323 if (alarm.operation.getTargetPackage().equals(packageName)) { 324 it.remove(); 325 } 326 } 327 } 328 329 public boolean lookForPackageLocked(String packageName) { 330 return lookForPackageLocked(mRtcWakeupAlarms, packageName) 331 || lookForPackageLocked(mRtcAlarms, packageName) 332 || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName) 333 || lookForPackageLocked(mElapsedRealtimeAlarms, packageName); 334 } 335 336 private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) { 337 for (int i=alarmList.size()-1; i>=0; i--) { 338 if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) { 339 return true; 340 } 341 } 342 return false; 343 } 344 345 private ArrayList<Alarm> getAlarmList(int type) { 346 switch (type) { 347 case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms; 348 case AlarmManager.RTC: return mRtcAlarms; 349 case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms; 350 case AlarmManager.ELAPSED_REALTIME: return mElapsedRealtimeAlarms; 351 } 352 353 return null; 354 } 355 356 private int addAlarmLocked(Alarm alarm) { 357 ArrayList<Alarm> alarmList = getAlarmList(alarm.type); 358 359 int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder); 360 if (index < 0) { 361 index = 0 - index - 1; 362 } 363 if (localLOGV) Slog.v(TAG, "Adding alarm " + alarm + " at " + index); 364 alarmList.add(index, alarm); 365 366 if (localLOGV) { 367 // Display the list of alarms for this alarm type 368 Slog.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type); 369 int position = 0; 370 for (Alarm a : alarmList) { 371 Time time = new Time(); 372 time.set(a.when); 373 String timeStr = time.format("%b %d %I:%M:%S %p"); 374 Slog.v(TAG, position + ": " + timeStr 375 + " " + a.operation.getTargetPackage()); 376 position += 1; 377 } 378 } 379 380 return index; 381 } 382 383 public long timeToNextAlarm() { 384 long nextAlarm = Long.MAX_VALUE; 385 synchronized (mLock) { 386 for (int i=AlarmManager.RTC_WAKEUP; 387 i<=AlarmManager.ELAPSED_REALTIME; i++) { 388 ArrayList<Alarm> alarmList = getAlarmList(i); 389 if (alarmList.size() > 0) { 390 Alarm a = alarmList.get(0); 391 if (a.when < nextAlarm) { 392 nextAlarm = a.when; 393 } 394 } 395 } 396 } 397 return nextAlarm; 398 } 399 400 private void setLocked(Alarm alarm) 401 { 402 if (mDescriptor != -1) 403 { 404 // The kernel never triggers alarms with negative wakeup times 405 // so we ensure they are positive. 406 long alarmSeconds, alarmNanoseconds; 407 if (alarm.when < 0) { 408 alarmSeconds = 0; 409 alarmNanoseconds = 0; 410 } else { 411 alarmSeconds = alarm.when / 1000; 412 alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000; 413 } 414 415 set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds); 416 } 417 else 418 { 419 Message msg = Message.obtain(); 420 msg.what = ALARM_EVENT; 421 422 mHandler.removeMessages(ALARM_EVENT); 423 mHandler.sendMessageAtTime(msg, alarm.when); 424 } 425 } 426 427 @Override 428 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 429 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 430 != PackageManager.PERMISSION_GRANTED) { 431 pw.println("Permission Denial: can't dump AlarmManager from from pid=" 432 + Binder.getCallingPid() 433 + ", uid=" + Binder.getCallingUid()); 434 return; 435 } 436 437 synchronized (mLock) { 438 pw.println("Current Alarm Manager state:"); 439 if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) { 440 final long now = System.currentTimeMillis(); 441 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 442 pw.println(" "); 443 pw.print(" Realtime wakeup (now="); 444 pw.print(sdf.format(new Date(now))); pw.println("):"); 445 if (mRtcWakeupAlarms.size() > 0) { 446 dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP", now); 447 } 448 if (mRtcAlarms.size() > 0) { 449 dumpAlarmList(pw, mRtcAlarms, " ", "RTC", now); 450 } 451 } 452 if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) { 453 final long now = SystemClock.elapsedRealtime(); 454 pw.println(" "); 455 pw.print(" Elapsed realtime wakeup (now="); 456 TimeUtils.formatDuration(now, pw); pw.println("):"); 457 if (mElapsedRealtimeWakeupAlarms.size() > 0) { 458 dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP", now); 459 } 460 if (mElapsedRealtimeAlarms.size() > 0) { 461 dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now); 462 } 463 } 464 465 pw.println(" "); 466 pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount); 467 468 pw.println(" "); 469 pw.println(" Alarm Stats:"); 470 for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) { 471 BroadcastStats bs = be.getValue(); 472 pw.print(" "); pw.println(be.getKey()); 473 pw.print(" "); pw.print(bs.aggregateTime); 474 pw.print("ms running, "); pw.print(bs.numWakeup); 475 pw.println(" wakeups"); 476 for (Map.Entry<Intent.FilterComparison, FilterStats> fe 477 : bs.filterStats.entrySet()) { 478 pw.print(" "); pw.print(fe.getValue().count); 479 pw.print(" alarms: "); 480 pw.println(fe.getKey().getIntent().toShortString(false, true, false)); 481 } 482 } 483 } 484 } 485 486 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, 487 String prefix, String label, long now) { 488 for (int i=list.size()-1; i>=0; i--) { 489 Alarm a = list.get(i); 490 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); 491 pw.print(": "); pw.println(a); 492 a.dump(pw, prefix + " ", now); 493 } 494 } 495 496 private native int init(); 497 private native void close(int fd); 498 private native void set(int fd, int type, long seconds, long nanoseconds); 499 private native int waitForAlarm(int fd); 500 private native int setKernelTimezone(int fd, int minuteswest); 501 502 private void triggerAlarmsLocked(ArrayList<Alarm> alarmList, 503 ArrayList<Alarm> triggerList, 504 long now) 505 { 506 Iterator<Alarm> it = alarmList.iterator(); 507 ArrayList<Alarm> repeats = new ArrayList<Alarm>(); 508 509 while (it.hasNext()) 510 { 511 Alarm alarm = it.next(); 512 513 if (localLOGV) Slog.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm); 514 515 if (alarm.when > now) { 516 // don't fire alarms in the future 517 break; 518 } 519 520 // If the alarm is late, then print a warning message. 521 // Note that this can happen if the user creates a new event on 522 // the Calendar app with a reminder that is in the past. In that 523 // case, the reminder alarm will fire immediately. 524 if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) { 525 Slog.v(TAG, "alarm is late! alarm time: " + alarm.when 526 + " now: " + now + " delay (in seconds): " 527 + (now - alarm.when) / 1000); 528 } 529 530 // Recurring alarms may have passed several alarm intervals while the 531 // phone was asleep or off, so pass a trigger count when sending them. 532 if (localLOGV) Slog.v(TAG, "Alarm triggering: " + alarm); 533 alarm.count = 1; 534 if (alarm.repeatInterval > 0) { 535 // this adjustment will be zero if we're late by 536 // less than one full repeat interval 537 alarm.count += (now - alarm.when) / alarm.repeatInterval; 538 } 539 triggerList.add(alarm); 540 541 // remove the alarm from the list 542 it.remove(); 543 544 // if it repeats queue it up to be read-added to the list 545 if (alarm.repeatInterval > 0) { 546 repeats.add(alarm); 547 } 548 } 549 550 // reset any repeating alarms. 551 it = repeats.iterator(); 552 while (it.hasNext()) { 553 Alarm alarm = it.next(); 554 alarm.when += alarm.count * alarm.repeatInterval; 555 addAlarmLocked(alarm); 556 } 557 558 if (alarmList.size() > 0) { 559 setLocked(alarmList.get(0)); 560 } 561 } 562 563 /** 564 * This Comparator sorts Alarms into increasing time order. 565 */ 566 public static class IncreasingTimeOrder implements Comparator<Alarm> { 567 public int compare(Alarm a1, Alarm a2) { 568 long when1 = a1.when; 569 long when2 = a2.when; 570 if (when1 - when2 > 0) { 571 return 1; 572 } 573 if (when1 - when2 < 0) { 574 return -1; 575 } 576 return 0; 577 } 578 } 579 580 private static class Alarm { 581 public int type; 582 public int count; 583 public long when; 584 public long repeatInterval; 585 public PendingIntent operation; 586 587 public Alarm() { 588 when = 0; 589 repeatInterval = 0; 590 operation = null; 591 } 592 593 @Override 594 public String toString() 595 { 596 StringBuilder sb = new StringBuilder(128); 597 sb.append("Alarm{"); 598 sb.append(Integer.toHexString(System.identityHashCode(this))); 599 sb.append(" type "); 600 sb.append(type); 601 sb.append(" "); 602 sb.append(operation.getTargetPackage()); 603 sb.append('}'); 604 return sb.toString(); 605 } 606 607 public void dump(PrintWriter pw, String prefix, long now) { 608 pw.print(prefix); pw.print("type="); pw.print(type); 609 pw.print(" when="); TimeUtils.formatDuration(when, now, pw); 610 pw.print(" repeatInterval="); pw.print(repeatInterval); 611 pw.print(" count="); pw.println(count); 612 pw.print(prefix); pw.print("operation="); pw.println(operation); 613 } 614 } 615 616 private class AlarmThread extends Thread 617 { 618 public AlarmThread() 619 { 620 super("AlarmManager"); 621 } 622 623 public void run() 624 { 625 while (true) 626 { 627 int result = waitForAlarm(mDescriptor); 628 629 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); 630 631 if ((result & TIME_CHANGED_MASK) != 0) { 632 remove(mTimeTickSender); 633 mClockReceiver.scheduleTimeTickEvent(); 634 Intent intent = new Intent(Intent.ACTION_TIME_CHANGED); 635 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING 636 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 637 mContext.sendBroadcast(intent); 638 } 639 640 synchronized (mLock) { 641 final long nowRTC = System.currentTimeMillis(); 642 final long nowELAPSED = SystemClock.elapsedRealtime(); 643 if (localLOGV) Slog.v( 644 TAG, "Checking for alarms... rtc=" + nowRTC 645 + ", elapsed=" + nowELAPSED); 646 647 if ((result & RTC_WAKEUP_MASK) != 0) 648 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); 649 650 if ((result & RTC_MASK) != 0) 651 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); 652 653 if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0) 654 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED); 655 656 if ((result & ELAPSED_REALTIME_MASK) != 0) 657 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED); 658 659 // now trigger the alarms 660 Iterator<Alarm> it = triggerList.iterator(); 661 while (it.hasNext()) { 662 Alarm alarm = it.next(); 663 try { 664 if (localLOGV) Slog.v(TAG, "sending alarm " + alarm); 665 alarm.operation.send(mContext, 0, 666 mBackgroundIntent.putExtra( 667 Intent.EXTRA_ALARM_COUNT, alarm.count), 668 mResultReceiver, mHandler); 669 670 // we have an active broadcast so stay awake. 671 if (mBroadcastRefCount == 0) { 672 mWakeLock.acquire(); 673 } 674 mBroadcastRefCount++; 675 676 BroadcastStats bs = getStatsLocked(alarm.operation); 677 if (bs.nesting == 0) { 678 bs.startTime = nowELAPSED; 679 } else { 680 bs.nesting++; 681 } 682 if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP 683 || alarm.type == AlarmManager.RTC_WAKEUP) { 684 bs.numWakeup++; 685 ActivityManagerNative.noteWakeupAlarm( 686 alarm.operation); 687 } 688 } catch (PendingIntent.CanceledException e) { 689 if (alarm.repeatInterval > 0) { 690 // This IntentSender is no longer valid, but this 691 // is a repeating alarm, so toss the hoser. 692 remove(alarm.operation); 693 } 694 } catch (RuntimeException e) { 695 Slog.w(TAG, "Failure sending alarm.", e); 696 } 697 } 698 } 699 } 700 } 701 } 702 703 private class AlarmHandler extends Handler { 704 public static final int ALARM_EVENT = 1; 705 public static final int MINUTE_CHANGE_EVENT = 2; 706 public static final int DATE_CHANGE_EVENT = 3; 707 708 public AlarmHandler() { 709 } 710 711 public void handleMessage(Message msg) { 712 if (msg.what == ALARM_EVENT) { 713 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); 714 synchronized (mLock) { 715 final long nowRTC = System.currentTimeMillis(); 716 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); 717 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); 718 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC); 719 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC); 720 } 721 722 // now trigger the alarms without the lock held 723 Iterator<Alarm> it = triggerList.iterator(); 724 while (it.hasNext()) 725 { 726 Alarm alarm = it.next(); 727 try { 728 alarm.operation.send(); 729 } catch (PendingIntent.CanceledException e) { 730 if (alarm.repeatInterval > 0) { 731 // This IntentSender is no longer valid, but this 732 // is a repeating alarm, so toss the hoser. 733 remove(alarm.operation); 734 } 735 } 736 } 737 } 738 } 739 } 740 741 class ClockReceiver extends BroadcastReceiver { 742 public ClockReceiver() { 743 IntentFilter filter = new IntentFilter(); 744 filter.addAction(Intent.ACTION_TIME_TICK); 745 filter.addAction(Intent.ACTION_DATE_CHANGED); 746 mContext.registerReceiver(this, filter); 747 } 748 749 @Override 750 public void onReceive(Context context, Intent intent) { 751 if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) { 752 scheduleTimeTickEvent(); 753 } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) { 754 // Since the kernel does not keep track of DST, we need to 755 // reset the TZ information at the beginning of each day 756 // based off of the current Zone gmt offset + userspace tracked 757 // daylight savings information. 758 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY)); 759 int gmtOffset = zone.getOffset(System.currentTimeMillis()); 760 setKernelTimezone(mDescriptor, -(gmtOffset / 60000)); 761 scheduleDateChangedEvent(); 762 } 763 } 764 765 public void scheduleTimeTickEvent() { 766 Calendar calendar = Calendar.getInstance(); 767 final long currentTime = System.currentTimeMillis(); 768 calendar.setTimeInMillis(currentTime); 769 calendar.add(Calendar.MINUTE, 1); 770 calendar.set(Calendar.SECOND, 0); 771 calendar.set(Calendar.MILLISECOND, 0); 772 773 // Schedule this event for the amount of time that it would take to get to 774 // the top of the next minute. 775 final long tickEventDelay = calendar.getTimeInMillis() - currentTime; 776 777 set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 778 mTimeTickSender); 779 } 780 781 public void scheduleDateChangedEvent() { 782 Calendar calendar = Calendar.getInstance(); 783 calendar.setTimeInMillis(System.currentTimeMillis()); 784 calendar.set(Calendar.HOUR, 0); 785 calendar.set(Calendar.MINUTE, 0); 786 calendar.set(Calendar.SECOND, 0); 787 calendar.set(Calendar.MILLISECOND, 0); 788 calendar.add(Calendar.DAY_OF_MONTH, 1); 789 790 set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender); 791 } 792 } 793 794 class UninstallReceiver extends BroadcastReceiver { 795 public UninstallReceiver() { 796 IntentFilter filter = new IntentFilter(); 797 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 798 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 799 filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 800 filter.addDataScheme("package"); 801 mContext.registerReceiver(this, filter); 802 // Register for events related to sdcard installation. 803 IntentFilter sdFilter = new IntentFilter(); 804 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 805 mContext.registerReceiver(this, sdFilter); 806 } 807 808 @Override 809 public void onReceive(Context context, Intent intent) { 810 synchronized (mLock) { 811 String action = intent.getAction(); 812 String pkgList[] = null; 813 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { 814 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 815 for (String packageName : pkgList) { 816 if (lookForPackageLocked(packageName)) { 817 setResultCode(Activity.RESULT_OK); 818 return; 819 } 820 } 821 return; 822 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 823 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 824 } else { 825 if (Intent.ACTION_PACKAGE_REMOVED.equals(action) 826 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 827 // This package is being updated; don't kill its alarms. 828 return; 829 } 830 Uri data = intent.getData(); 831 if (data != null) { 832 String pkg = data.getSchemeSpecificPart(); 833 if (pkg != null) { 834 pkgList = new String[]{pkg}; 835 } 836 } 837 } 838 if (pkgList != null && (pkgList.length > 0)) { 839 for (String pkg : pkgList) { 840 removeLocked(pkg); 841 mBroadcastStats.remove(pkg); 842 } 843 } 844 } 845 } 846 } 847 848 private final BroadcastStats getStatsLocked(PendingIntent pi) { 849 String pkg = pi.getTargetPackage(); 850 BroadcastStats bs = mBroadcastStats.get(pkg); 851 if (bs == null) { 852 bs = new BroadcastStats(); 853 mBroadcastStats.put(pkg, bs); 854 } 855 return bs; 856 } 857 858 class ResultReceiver implements PendingIntent.OnFinished { 859 public void onSendFinished(PendingIntent pi, Intent intent, int resultCode, 860 String resultData, Bundle resultExtras) { 861 synchronized (mLock) { 862 BroadcastStats bs = getStatsLocked(pi); 863 if (bs != null) { 864 bs.nesting--; 865 if (bs.nesting <= 0) { 866 bs.nesting = 0; 867 bs.aggregateTime += SystemClock.elapsedRealtime() 868 - bs.startTime; 869 Intent.FilterComparison fc = new Intent.FilterComparison(intent); 870 FilterStats fs = bs.filterStats.get(fc); 871 if (fs == null) { 872 fs = new FilterStats(); 873 bs.filterStats.put(fc, fs); 874 } 875 fs.count++; 876 } 877 } 878 mBroadcastRefCount--; 879 if (mBroadcastRefCount == 0) { 880 mWakeLock.release(); 881 } 882 } 883 } 884 } 885 } 886