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