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