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