AlarmManagerService.java revision 897798225d9c48bd3424757059318ed1eb3207de
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 long oldId = Binder.clearCallingIdentity(); 247 try { 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) { 257 Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID()); 258 } 259 timeZoneWasChanged = true; 260 SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); 261 } 262 263 // Update the kernel timezone information 264 // Kernel tracks time offsets as 'minutes west of GMT' 265 int gmtOffset = zone.getOffset(System.currentTimeMillis()); 266 setKernelTimezone(mDescriptor, -(gmtOffset / 60000)); 267 } 268 269 TimeZone.setDefault(null); 270 271 if (timeZoneWasChanged) { 272 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); 273 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 274 intent.putExtra("time-zone", zone.getID()); 275 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 276 } 277 } finally { 278 Binder.restoreCallingIdentity(oldId); 279 } 280 } 281 282 public void remove(PendingIntent operation) { 283 if (operation == null) { 284 return; 285 } 286 synchronized (mLock) { 287 removeLocked(operation); 288 } 289 } 290 291 public void removeLocked(PendingIntent operation) { 292 removeLocked(mRtcWakeupAlarms, operation); 293 removeLocked(mRtcAlarms, operation); 294 removeLocked(mElapsedRealtimeWakeupAlarms, operation); 295 removeLocked(mElapsedRealtimeAlarms, operation); 296 } 297 298 private void removeLocked(ArrayList<Alarm> alarmList, 299 PendingIntent operation) { 300 if (alarmList.size() <= 0) { 301 return; 302 } 303 304 // iterator over the list removing any it where the intent match 305 Iterator<Alarm> it = alarmList.iterator(); 306 307 while (it.hasNext()) { 308 Alarm alarm = it.next(); 309 if (alarm.operation.equals(operation)) { 310 it.remove(); 311 } 312 } 313 } 314 315 public void removeLocked(String packageName) { 316 removeLocked(mRtcWakeupAlarms, packageName); 317 removeLocked(mRtcAlarms, packageName); 318 removeLocked(mElapsedRealtimeWakeupAlarms, packageName); 319 removeLocked(mElapsedRealtimeAlarms, packageName); 320 } 321 322 private void removeLocked(ArrayList<Alarm> alarmList, 323 String packageName) { 324 if (alarmList.size() <= 0) { 325 return; 326 } 327 328 // iterator over the list removing any it where the intent match 329 Iterator<Alarm> it = alarmList.iterator(); 330 331 while (it.hasNext()) { 332 Alarm alarm = it.next(); 333 if (alarm.operation.getTargetPackage().equals(packageName)) { 334 it.remove(); 335 } 336 } 337 } 338 339 public void removeUserLocked(int userHandle) { 340 removeUserLocked(mRtcWakeupAlarms, userHandle); 341 removeUserLocked(mRtcAlarms, userHandle); 342 removeUserLocked(mElapsedRealtimeWakeupAlarms, userHandle); 343 removeUserLocked(mElapsedRealtimeAlarms, userHandle); 344 } 345 346 private void removeUserLocked(ArrayList<Alarm> alarmList, int userHandle) { 347 if (alarmList.size() <= 0) { 348 return; 349 } 350 351 // iterator over the list removing any it where the intent match 352 Iterator<Alarm> it = alarmList.iterator(); 353 354 while (it.hasNext()) { 355 Alarm alarm = it.next(); 356 if (UserHandle.getUserId(alarm.operation.getTargetUid()) == userHandle) { 357 it.remove(); 358 } 359 } 360 } 361 362 public boolean lookForPackageLocked(String packageName) { 363 return lookForPackageLocked(mRtcWakeupAlarms, packageName) 364 || lookForPackageLocked(mRtcAlarms, packageName) 365 || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName) 366 || lookForPackageLocked(mElapsedRealtimeAlarms, packageName); 367 } 368 369 private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) { 370 for (int i=alarmList.size()-1; i>=0; i--) { 371 if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) { 372 return true; 373 } 374 } 375 return false; 376 } 377 378 private ArrayList<Alarm> getAlarmList(int type) { 379 switch (type) { 380 case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms; 381 case AlarmManager.RTC: return mRtcAlarms; 382 case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms; 383 case AlarmManager.ELAPSED_REALTIME: return mElapsedRealtimeAlarms; 384 } 385 386 return null; 387 } 388 389 private int addAlarmLocked(Alarm alarm) { 390 ArrayList<Alarm> alarmList = getAlarmList(alarm.type); 391 392 int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder); 393 if (index < 0) { 394 index = 0 - index - 1; 395 } 396 if (localLOGV) Slog.v(TAG, "Adding alarm " + alarm + " at " + index); 397 alarmList.add(index, alarm); 398 399 if (localLOGV) { 400 // Display the list of alarms for this alarm type 401 Slog.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type); 402 int position = 0; 403 for (Alarm a : alarmList) { 404 Time time = new Time(); 405 time.set(a.when); 406 String timeStr = time.format("%b %d %I:%M:%S %p"); 407 Slog.v(TAG, position + ": " + timeStr 408 + " " + a.operation.getTargetPackage()); 409 position += 1; 410 } 411 } 412 413 return index; 414 } 415 416 public long timeToNextAlarm() { 417 long nextAlarm = Long.MAX_VALUE; 418 synchronized (mLock) { 419 for (int i=AlarmManager.RTC_WAKEUP; 420 i<=AlarmManager.ELAPSED_REALTIME; i++) { 421 ArrayList<Alarm> alarmList = getAlarmList(i); 422 if (alarmList.size() > 0) { 423 Alarm a = alarmList.get(0); 424 if (a.when < nextAlarm) { 425 nextAlarm = a.when; 426 } 427 } 428 } 429 } 430 return nextAlarm; 431 } 432 433 private void setLocked(Alarm alarm) 434 { 435 if (mDescriptor != -1) 436 { 437 // The kernel never triggers alarms with negative wakeup times 438 // so we ensure they are positive. 439 long alarmSeconds, alarmNanoseconds; 440 if (alarm.when < 0) { 441 alarmSeconds = 0; 442 alarmNanoseconds = 0; 443 } else { 444 alarmSeconds = alarm.when / 1000; 445 alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000; 446 } 447 448 set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds); 449 } 450 else 451 { 452 Message msg = Message.obtain(); 453 msg.what = ALARM_EVENT; 454 455 mHandler.removeMessages(ALARM_EVENT); 456 mHandler.sendMessageAtTime(msg, alarm.when); 457 } 458 } 459 460 @Override 461 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 462 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 463 != PackageManager.PERMISSION_GRANTED) { 464 pw.println("Permission Denial: can't dump AlarmManager from from pid=" 465 + Binder.getCallingPid() 466 + ", uid=" + Binder.getCallingUid()); 467 return; 468 } 469 470 synchronized (mLock) { 471 pw.println("Current Alarm Manager state:"); 472 if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) { 473 final long now = System.currentTimeMillis(); 474 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 475 pw.println(" "); 476 pw.print(" Realtime wakeup (now="); 477 pw.print(sdf.format(new Date(now))); pw.println("):"); 478 if (mRtcWakeupAlarms.size() > 0) { 479 dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP", now); 480 } 481 if (mRtcAlarms.size() > 0) { 482 dumpAlarmList(pw, mRtcAlarms, " ", "RTC", now); 483 } 484 } 485 if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) { 486 final long now = SystemClock.elapsedRealtime(); 487 pw.println(" "); 488 pw.print(" Elapsed realtime wakeup (now="); 489 TimeUtils.formatDuration(now, pw); pw.println("):"); 490 if (mElapsedRealtimeWakeupAlarms.size() > 0) { 491 dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP", now); 492 } 493 if (mElapsedRealtimeAlarms.size() > 0) { 494 dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now); 495 } 496 } 497 498 pw.println(" "); 499 pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount); 500 501 pw.println(" "); 502 pw.println(" Alarm Stats:"); 503 for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) { 504 BroadcastStats bs = be.getValue(); 505 pw.print(" "); pw.println(be.getKey()); 506 pw.print(" "); pw.print(bs.aggregateTime); 507 pw.print("ms running, "); pw.print(bs.numWakeup); 508 pw.println(" wakeups"); 509 for (Map.Entry<Intent.FilterComparison, FilterStats> fe 510 : bs.filterStats.entrySet()) { 511 pw.print(" "); pw.print(fe.getValue().count); 512 pw.print(" alarms: "); 513 pw.println(fe.getKey().getIntent().toShortString( 514 false, true, false, true)); 515 } 516 } 517 } 518 } 519 520 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, 521 String prefix, String label, long now) { 522 for (int i=list.size()-1; i>=0; i--) { 523 Alarm a = list.get(i); 524 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); 525 pw.print(": "); pw.println(a); 526 a.dump(pw, prefix + " ", now); 527 } 528 } 529 530 private native int init(); 531 private native void close(int fd); 532 private native void set(int fd, int type, long seconds, long nanoseconds); 533 private native int waitForAlarm(int fd); 534 private native int setKernelTimezone(int fd, int minuteswest); 535 536 private void triggerAlarmsLocked(ArrayList<Alarm> alarmList, 537 ArrayList<Alarm> triggerList, 538 long now) 539 { 540 Iterator<Alarm> it = alarmList.iterator(); 541 ArrayList<Alarm> repeats = new ArrayList<Alarm>(); 542 543 while (it.hasNext()) 544 { 545 Alarm alarm = it.next(); 546 547 if (localLOGV) Slog.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm); 548 549 if (alarm.when > now) { 550 // don't fire alarms in the future 551 break; 552 } 553 554 // If the alarm is late, then print a warning message. 555 // Note that this can happen if the user creates a new event on 556 // the Calendar app with a reminder that is in the past. In that 557 // case, the reminder alarm will fire immediately. 558 if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) { 559 Slog.v(TAG, "alarm is late! alarm time: " + alarm.when 560 + " now: " + now + " delay (in seconds): " 561 + (now - alarm.when) / 1000); 562 } 563 564 // Recurring alarms may have passed several alarm intervals while the 565 // phone was asleep or off, so pass a trigger count when sending them. 566 if (localLOGV) Slog.v(TAG, "Alarm triggering: " + alarm); 567 alarm.count = 1; 568 if (alarm.repeatInterval > 0) { 569 // this adjustment will be zero if we're late by 570 // less than one full repeat interval 571 alarm.count += (now - alarm.when) / alarm.repeatInterval; 572 } 573 triggerList.add(alarm); 574 575 // remove the alarm from the list 576 it.remove(); 577 578 // if it repeats queue it up to be read-added to the list 579 if (alarm.repeatInterval > 0) { 580 repeats.add(alarm); 581 } 582 } 583 584 // reset any repeating alarms. 585 it = repeats.iterator(); 586 while (it.hasNext()) { 587 Alarm alarm = it.next(); 588 alarm.when += alarm.count * alarm.repeatInterval; 589 addAlarmLocked(alarm); 590 } 591 592 if (alarmList.size() > 0) { 593 setLocked(alarmList.get(0)); 594 } 595 } 596 597 /** 598 * This Comparator sorts Alarms into increasing time order. 599 */ 600 public static class IncreasingTimeOrder implements Comparator<Alarm> { 601 public int compare(Alarm a1, Alarm a2) { 602 long when1 = a1.when; 603 long when2 = a2.when; 604 if (when1 - when2 > 0) { 605 return 1; 606 } 607 if (when1 - when2 < 0) { 608 return -1; 609 } 610 return 0; 611 } 612 } 613 614 private static class Alarm { 615 public int type; 616 public int count; 617 public long when; 618 public long repeatInterval; 619 public PendingIntent operation; 620 621 public Alarm() { 622 when = 0; 623 repeatInterval = 0; 624 operation = null; 625 } 626 627 @Override 628 public String toString() 629 { 630 StringBuilder sb = new StringBuilder(128); 631 sb.append("Alarm{"); 632 sb.append(Integer.toHexString(System.identityHashCode(this))); 633 sb.append(" type "); 634 sb.append(type); 635 sb.append(" "); 636 sb.append(operation.getTargetPackage()); 637 sb.append('}'); 638 return sb.toString(); 639 } 640 641 public void dump(PrintWriter pw, String prefix, long now) { 642 pw.print(prefix); pw.print("type="); pw.print(type); 643 pw.print(" when="); TimeUtils.formatDuration(when, now, pw); 644 pw.print(" repeatInterval="); pw.print(repeatInterval); 645 pw.print(" count="); pw.println(count); 646 pw.print(prefix); pw.print("operation="); pw.println(operation); 647 } 648 } 649 650 private class AlarmThread extends Thread 651 { 652 public AlarmThread() 653 { 654 super("AlarmManager"); 655 } 656 657 public void run() 658 { 659 while (true) 660 { 661 int result = waitForAlarm(mDescriptor); 662 663 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); 664 665 if ((result & TIME_CHANGED_MASK) != 0) { 666 remove(mTimeTickSender); 667 mClockReceiver.scheduleTimeTickEvent(); 668 Intent intent = new Intent(Intent.ACTION_TIME_CHANGED); 669 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING 670 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 671 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 672 } 673 674 synchronized (mLock) { 675 final long nowRTC = System.currentTimeMillis(); 676 final long nowELAPSED = SystemClock.elapsedRealtime(); 677 if (localLOGV) Slog.v( 678 TAG, "Checking for alarms... rtc=" + nowRTC 679 + ", elapsed=" + nowELAPSED); 680 681 if ((result & RTC_WAKEUP_MASK) != 0) 682 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); 683 684 if ((result & RTC_MASK) != 0) 685 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); 686 687 if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0) 688 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED); 689 690 if ((result & ELAPSED_REALTIME_MASK) != 0) 691 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED); 692 693 // now trigger the alarms 694 Iterator<Alarm> it = triggerList.iterator(); 695 while (it.hasNext()) { 696 Alarm alarm = it.next(); 697 try { 698 if (localLOGV) Slog.v(TAG, "sending alarm " + alarm); 699 alarm.operation.send(mContext, 0, 700 mBackgroundIntent.putExtra( 701 Intent.EXTRA_ALARM_COUNT, alarm.count), 702 mResultReceiver, mHandler); 703 704 // we have an active broadcast so stay awake. 705 if (mBroadcastRefCount == 0) { 706 setWakelockWorkSource(alarm.operation); 707 mWakeLock.acquire(); 708 } 709 mInFlight.add(alarm.operation); 710 mBroadcastRefCount++; 711 712 BroadcastStats bs = getStatsLocked(alarm.operation); 713 if (bs.nesting == 0) { 714 bs.startTime = nowELAPSED; 715 } else { 716 bs.nesting++; 717 } 718 if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP 719 || alarm.type == AlarmManager.RTC_WAKEUP) { 720 bs.numWakeup++; 721 ActivityManagerNative.noteWakeupAlarm( 722 alarm.operation); 723 } 724 } catch (PendingIntent.CanceledException e) { 725 if (alarm.repeatInterval > 0) { 726 // This IntentSender is no longer valid, but this 727 // is a repeating alarm, so toss the hoser. 728 remove(alarm.operation); 729 } 730 } catch (RuntimeException e) { 731 Slog.w(TAG, "Failure sending alarm.", e); 732 } 733 } 734 } 735 } 736 } 737 } 738 739 void setWakelockWorkSource(PendingIntent pi) { 740 try { 741 final int uid = ActivityManagerNative.getDefault() 742 .getUidForIntentSender(pi.getTarget()); 743 if (uid >= 0) { 744 mWakeLock.setWorkSource(new WorkSource(uid)); 745 return; 746 } 747 } catch (Exception e) { 748 } 749 750 // Something went wrong; fall back to attributing the lock to the OS 751 mWakeLock.setWorkSource(null); 752 } 753 754 private class AlarmHandler extends Handler { 755 public static final int ALARM_EVENT = 1; 756 public static final int MINUTE_CHANGE_EVENT = 2; 757 public static final int DATE_CHANGE_EVENT = 3; 758 759 public AlarmHandler() { 760 } 761 762 public void handleMessage(Message msg) { 763 if (msg.what == ALARM_EVENT) { 764 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); 765 synchronized (mLock) { 766 final long nowRTC = System.currentTimeMillis(); 767 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); 768 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); 769 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC); 770 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC); 771 } 772 773 // now trigger the alarms without the lock held 774 Iterator<Alarm> it = triggerList.iterator(); 775 while (it.hasNext()) 776 { 777 Alarm alarm = it.next(); 778 try { 779 alarm.operation.send(); 780 } catch (PendingIntent.CanceledException e) { 781 if (alarm.repeatInterval > 0) { 782 // This IntentSender is no longer valid, but this 783 // is a repeating alarm, so toss the hoser. 784 remove(alarm.operation); 785 } 786 } 787 } 788 } 789 } 790 } 791 792 class ClockReceiver extends BroadcastReceiver { 793 public ClockReceiver() { 794 IntentFilter filter = new IntentFilter(); 795 filter.addAction(Intent.ACTION_TIME_TICK); 796 filter.addAction(Intent.ACTION_DATE_CHANGED); 797 mContext.registerReceiver(this, filter); 798 } 799 800 @Override 801 public void onReceive(Context context, Intent intent) { 802 if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) { 803 scheduleTimeTickEvent(); 804 } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) { 805 // Since the kernel does not keep track of DST, we need to 806 // reset the TZ information at the beginning of each day 807 // based off of the current Zone gmt offset + userspace tracked 808 // daylight savings information. 809 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY)); 810 int gmtOffset = zone.getOffset(System.currentTimeMillis()); 811 setKernelTimezone(mDescriptor, -(gmtOffset / 60000)); 812 scheduleDateChangedEvent(); 813 } 814 } 815 816 public void scheduleTimeTickEvent() { 817 Calendar calendar = Calendar.getInstance(); 818 final long currentTime = System.currentTimeMillis(); 819 calendar.setTimeInMillis(currentTime); 820 calendar.add(Calendar.MINUTE, 1); 821 calendar.set(Calendar.SECOND, 0); 822 calendar.set(Calendar.MILLISECOND, 0); 823 824 // Schedule this event for the amount of time that it would take to get to 825 // the top of the next minute. 826 final long tickEventDelay = calendar.getTimeInMillis() - currentTime; 827 828 set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 829 mTimeTickSender); 830 } 831 832 public void scheduleDateChangedEvent() { 833 Calendar calendar = Calendar.getInstance(); 834 calendar.setTimeInMillis(System.currentTimeMillis()); 835 calendar.set(Calendar.HOUR, 0); 836 calendar.set(Calendar.MINUTE, 0); 837 calendar.set(Calendar.SECOND, 0); 838 calendar.set(Calendar.MILLISECOND, 0); 839 calendar.add(Calendar.DAY_OF_MONTH, 1); 840 841 set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender); 842 } 843 } 844 845 class UninstallReceiver extends BroadcastReceiver { 846 public UninstallReceiver() { 847 IntentFilter filter = new IntentFilter(); 848 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 849 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 850 filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 851 filter.addDataScheme("package"); 852 mContext.registerReceiver(this, filter); 853 // Register for events related to sdcard installation. 854 IntentFilter sdFilter = new IntentFilter(); 855 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 856 sdFilter.addAction(Intent.ACTION_USER_STOPPED); 857 mContext.registerReceiver(this, sdFilter); 858 } 859 860 @Override 861 public void onReceive(Context context, Intent intent) { 862 synchronized (mLock) { 863 String action = intent.getAction(); 864 String pkgList[] = null; 865 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { 866 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 867 for (String packageName : pkgList) { 868 if (lookForPackageLocked(packageName)) { 869 setResultCode(Activity.RESULT_OK); 870 return; 871 } 872 } 873 return; 874 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 875 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 876 } else if (Intent.ACTION_USER_STOPPED.equals(action)) { 877 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 878 if (userHandle >= 0) { 879 removeUserLocked(userHandle); 880 } 881 } else { 882 if (Intent.ACTION_PACKAGE_REMOVED.equals(action) 883 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 884 // This package is being updated; don't kill its alarms. 885 return; 886 } 887 Uri data = intent.getData(); 888 if (data != null) { 889 String pkg = data.getSchemeSpecificPart(); 890 if (pkg != null) { 891 pkgList = new String[]{pkg}; 892 } 893 } 894 } 895 if (pkgList != null && (pkgList.length > 0)) { 896 for (String pkg : pkgList) { 897 removeLocked(pkg); 898 mBroadcastStats.remove(pkg); 899 } 900 } 901 } 902 } 903 } 904 905 private final BroadcastStats getStatsLocked(PendingIntent pi) { 906 String pkg = pi.getTargetPackage(); 907 BroadcastStats bs = mBroadcastStats.get(pkg); 908 if (bs == null) { 909 bs = new BroadcastStats(); 910 mBroadcastStats.put(pkg, bs); 911 } 912 return bs; 913 } 914 915 class ResultReceiver implements PendingIntent.OnFinished { 916 public void onSendFinished(PendingIntent pi, Intent intent, int resultCode, 917 String resultData, Bundle resultExtras) { 918 synchronized (mLock) { 919 BroadcastStats bs = getStatsLocked(pi); 920 if (bs != null) { 921 bs.nesting--; 922 if (bs.nesting <= 0) { 923 bs.nesting = 0; 924 bs.aggregateTime += SystemClock.elapsedRealtime() 925 - bs.startTime; 926 Intent.FilterComparison fc = new Intent.FilterComparison(intent); 927 FilterStats fs = bs.filterStats.get(fc); 928 if (fs == null) { 929 fs = new FilterStats(); 930 bs.filterStats.put(fc, fs); 931 } 932 fs.count++; 933 } 934 } 935 mInFlight.removeFirst(); 936 mBroadcastRefCount--; 937 if (mBroadcastRefCount == 0) { 938 mWakeLock.release(); 939 } else { 940 // the next of our alarms is now in flight. reattribute the wakelock. 941 final PendingIntent nowInFlight = mInFlight.peekFirst(); 942 if (nowInFlight != null) { 943 setWakelockWorkSource(nowInFlight); 944 } else { 945 // should never happen 946 Slog.e(TAG, "Alarm wakelock still held but sent queue empty"); 947 mWakeLock.setWorkSource(null); 948 } 949 } 950 } 951 } 952 } 953} 954