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