blob: 9b7be028cfe1067bd8c91ab558ad5a74355f3785 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080019import android.app.Activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.app.ActivityManagerNative;
21import android.app.AlarmManager;
22import android.app.IAlarmManager;
23import android.app.PendingIntent;
24import android.content.BroadcastReceiver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.PackageManager;
29import android.net.Uri;
30import android.os.Binder;
31import android.os.Bundle;
32import android.os.Handler;
33import android.os.Message;
34import android.os.PowerManager;
35import android.os.SystemClock;
36import android.os.SystemProperties;
Dianne Hackborn80a4af22012-08-27 19:18:31 -070037import android.os.UserHandle;
Christopher Tatec4a07d12012-04-06 14:19:13 -070038import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.text.TextUtils;
40import android.text.format.Time;
Joe Onorato8a9b2202010-02-26 18:56:32 -080041import android.util.Slog;
Dianne Hackborn043fcd92010-10-06 14:27:34 -070042import android.util.TimeUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
44import java.io.FileDescriptor;
45import java.io.PrintWriter;
Dianne Hackborn043fcd92010-10-06 14:27:34 -070046import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import java.util.ArrayList;
48import java.util.Calendar;
49import java.util.Collections;
50import java.util.Comparator;
Mike Lockwood1f7b4132009-11-20 15:12:51 -050051import java.util.Date;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import java.util.HashMap;
53import java.util.Iterator;
Christopher Tatec4a07d12012-04-06 14:19:13 -070054import java.util.LinkedList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import java.util.Map;
56import java.util.TimeZone;
57
58class AlarmManagerService extends IAlarmManager.Stub {
59 // The threshold for how long an alarm can be late before we print a
60 // warning message. The time duration is in milliseconds.
61 private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
62
63 private static final int RTC_WAKEUP_MASK = 1 << AlarmManager.RTC_WAKEUP;
64 private static final int RTC_MASK = 1 << AlarmManager.RTC;
65 private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << AlarmManager.ELAPSED_REALTIME_WAKEUP;
66 private static final int ELAPSED_REALTIME_MASK = 1 << AlarmManager.ELAPSED_REALTIME;
67 private static final int TIME_CHANGED_MASK = 1 << 16;
Christopher Tateb8849c12011-02-08 13:39:01 -080068
69 // Alignment quantum for inexact repeating alarms
70 private static final long QUANTUM = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
71
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 private int mDescriptor;
92 private int mBroadcastRefCount = 0;
93 private PowerManager.WakeLock mWakeLock;
Christopher Tatec4a07d12012-04-06 14:19:13 -070094 private LinkedList<PendingIntent> mInFlight = new LinkedList<PendingIntent>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 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();
Robert CH Chou64ba8e42009-11-04 21:38:49 +0800122
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
131 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
132
133 mTimeTickSender = PendingIntent.getBroadcast(context, 0,
134 new Intent(Intent.ACTION_TIME_TICK).addFlags(
135 Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800136 Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
137 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
138 mDateChangeSender = PendingIntent.getBroadcast(context, 0, intent, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139
140 // now that we have initied the driver schedule the alarm
141 mClockReceiver= new ClockReceiver();
142 mClockReceiver.scheduleTimeTickEvent();
143 mClockReceiver.scheduleDateChangedEvent();
144 mUninstallReceiver = new UninstallReceiver();
145
146 if (mDescriptor != -1) {
147 mWaitThread.start();
148 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800149 Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 }
151 }
152
153 protected void finalize() throws Throwable {
154 try {
155 close(mDescriptor);
156 } finally {
157 super.finalize();
158 }
159 }
160
161 public void set(int type, long triggerAtTime, PendingIntent operation) {
162 setRepeating(type, triggerAtTime, 0, operation);
163 }
164
165 public void setRepeating(int type, long triggerAtTime, long interval,
166 PendingIntent operation) {
167 if (operation == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800168 Slog.w(TAG, "set/setRepeating ignored because there is no intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 return;
170 }
171 synchronized (mLock) {
172 Alarm alarm = new Alarm();
173 alarm.type = type;
174 alarm.when = triggerAtTime;
175 alarm.repeatInterval = interval;
176 alarm.operation = operation;
177
178 // Remove this alarm if already scheduled.
179 removeLocked(operation);
180
Joe Onorato8a9b2202010-02-26 18:56:32 -0800181 if (localLOGV) Slog.v(TAG, "set: " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182
183 int index = addAlarmLocked(alarm);
184 if (index == 0) {
185 setLocked(alarm);
186 }
187 }
188 }
189
190 public void setInexactRepeating(int type, long triggerAtTime, long interval,
191 PendingIntent operation) {
192 if (operation == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800193 Slog.w(TAG, "setInexactRepeating ignored because there is no intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 return;
195 }
196
Christopher Tateb8849c12011-02-08 13:39:01 -0800197 if (interval <= 0) {
198 Slog.w(TAG, "setInexactRepeating ignored because interval " + interval
199 + " is invalid");
200 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 }
Christopher Tateb8849c12011-02-08 13:39:01 -0800202
203 // If the requested interval isn't a multiple of 15 minutes, just treat it as exact
204 if (interval % QUANTUM != 0) {
205 if (localLOGV) Slog.v(TAG, "Interval " + interval + " not a quantum multiple");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 setRepeating(type, triggerAtTime, interval, operation);
207 return;
208 }
209
Christopher Tateb8849c12011-02-08 13:39:01 -0800210 // Translate times into the ELAPSED timebase for alignment purposes so that
211 // alignment never tries to match against wall clock times.
212 final boolean isRtc = (type == AlarmManager.RTC || type == AlarmManager.RTC_WAKEUP);
213 final long skew = (isRtc)
214 ? System.currentTimeMillis() - SystemClock.elapsedRealtime()
215 : 0;
216
217 // Slip forward to the next ELAPSED-timebase quantum after the stated time. If
218 // we're *at* a quantum point, leave it alone.
219 final long adjustedTriggerTime;
220 long offset = (triggerAtTime - skew) % QUANTUM;
221 if (offset != 0) {
222 adjustedTriggerTime = triggerAtTime - offset + QUANTUM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 } else {
Christopher Tateb8849c12011-02-08 13:39:01 -0800224 adjustedTriggerTime = triggerAtTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 }
226
Christopher Tateb8849c12011-02-08 13:39:01 -0800227 // Set the alarm based on the quantum-aligned start time
228 if (localLOGV) Slog.v(TAG, "setInexactRepeating: type=" + type + " interval=" + interval
229 + " trigger=" + adjustedTriggerTime + " orig=" + triggerAtTime);
230 setRepeating(type, adjustedTriggerTime, interval, operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 }
232
Dan Egnor97e44942010-02-04 20:27:47 -0800233 public void setTime(long millis) {
234 mContext.enforceCallingOrSelfPermission(
235 "android.permission.SET_TIME",
236 "setTime");
237
238 SystemClock.setCurrentTimeMillis(millis);
239 }
240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 public void setTimeZone(String tz) {
242 mContext.enforceCallingOrSelfPermission(
243 "android.permission.SET_TIME_ZONE",
244 "setTimeZone");
245
246 if (TextUtils.isEmpty(tz)) return;
247 TimeZone zone = TimeZone.getTimeZone(tz);
248 // Prevent reentrant calls from stepping on each other when writing
249 // the time zone property
250 boolean timeZoneWasChanged = false;
251 synchronized (this) {
252 String current = SystemProperties.get(TIMEZONE_PROPERTY);
253 if (current == null || !current.equals(zone.getID())) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800254 if (localLOGV) Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 timeZoneWasChanged = true;
256 SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
257 }
258
259 // Update the kernel timezone information
260 // Kernel tracks time offsets as 'minutes west of GMT'
Lavettacn Xiaoc84cc4f2010-08-30 12:47:23 +0200261 int gmtOffset = zone.getOffset(System.currentTimeMillis());
Mike Lockwood1f7b4132009-11-20 15:12:51 -0500262 setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 }
264
265 TimeZone.setDefault(null);
266
267 if (timeZoneWasChanged) {
268 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800269 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 intent.putExtra("time-zone", zone.getID());
271 mContext.sendBroadcast(intent);
272 }
273 }
274
275 public void remove(PendingIntent operation) {
276 if (operation == null) {
277 return;
278 }
279 synchronized (mLock) {
280 removeLocked(operation);
281 }
282 }
283
284 public void removeLocked(PendingIntent operation) {
285 removeLocked(mRtcWakeupAlarms, operation);
286 removeLocked(mRtcAlarms, operation);
287 removeLocked(mElapsedRealtimeWakeupAlarms, operation);
288 removeLocked(mElapsedRealtimeAlarms, operation);
289 }
290
291 private void removeLocked(ArrayList<Alarm> alarmList,
292 PendingIntent operation) {
293 if (alarmList.size() <= 0) {
294 return;
295 }
296
297 // iterator over the list removing any it where the intent match
298 Iterator<Alarm> it = alarmList.iterator();
299
300 while (it.hasNext()) {
301 Alarm alarm = it.next();
302 if (alarm.operation.equals(operation)) {
303 it.remove();
304 }
305 }
306 }
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 public void removeLocked(String packageName) {
309 removeLocked(mRtcWakeupAlarms, packageName);
310 removeLocked(mRtcAlarms, packageName);
311 removeLocked(mElapsedRealtimeWakeupAlarms, packageName);
312 removeLocked(mElapsedRealtimeAlarms, packageName);
313 }
314
315 private void removeLocked(ArrayList<Alarm> alarmList,
316 String packageName) {
317 if (alarmList.size() <= 0) {
318 return;
319 }
320
321 // iterator over the list removing any it where the intent match
322 Iterator<Alarm> it = alarmList.iterator();
323
324 while (it.hasNext()) {
325 Alarm alarm = it.next();
326 if (alarm.operation.getTargetPackage().equals(packageName)) {
327 it.remove();
328 }
329 }
330 }
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700331
332 public void removeUserLocked(int userHandle) {
333 removeUserLocked(mRtcWakeupAlarms, userHandle);
334 removeUserLocked(mRtcAlarms, userHandle);
335 removeUserLocked(mElapsedRealtimeWakeupAlarms, userHandle);
336 removeUserLocked(mElapsedRealtimeAlarms, userHandle);
337 }
338
339 private void removeUserLocked(ArrayList<Alarm> alarmList, int userHandle) {
340 if (alarmList.size() <= 0) {
341 return;
342 }
343
344 // iterator over the list removing any it where the intent match
345 Iterator<Alarm> it = alarmList.iterator();
346
347 while (it.hasNext()) {
348 Alarm alarm = it.next();
349 if (UserHandle.getUserId(alarm.operation.getTargetUid()) == userHandle) {
350 it.remove();
351 }
352 }
353 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800355 public boolean lookForPackageLocked(String packageName) {
356 return lookForPackageLocked(mRtcWakeupAlarms, packageName)
357 || lookForPackageLocked(mRtcAlarms, packageName)
358 || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName)
359 || lookForPackageLocked(mElapsedRealtimeAlarms, packageName);
360 }
361
362 private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) {
363 for (int i=alarmList.size()-1; i>=0; i--) {
364 if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) {
365 return true;
366 }
367 }
368 return false;
369 }
370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 private ArrayList<Alarm> getAlarmList(int type) {
372 switch (type) {
373 case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms;
374 case AlarmManager.RTC: return mRtcAlarms;
375 case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms;
376 case AlarmManager.ELAPSED_REALTIME: return mElapsedRealtimeAlarms;
377 }
378
379 return null;
380 }
381
382 private int addAlarmLocked(Alarm alarm) {
383 ArrayList<Alarm> alarmList = getAlarmList(alarm.type);
384
385 int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder);
386 if (index < 0) {
387 index = 0 - index - 1;
388 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800389 if (localLOGV) Slog.v(TAG, "Adding alarm " + alarm + " at " + index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 alarmList.add(index, alarm);
391
392 if (localLOGV) {
393 // Display the list of alarms for this alarm type
Joe Onorato8a9b2202010-02-26 18:56:32 -0800394 Slog.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 int position = 0;
396 for (Alarm a : alarmList) {
397 Time time = new Time();
398 time.set(a.when);
399 String timeStr = time.format("%b %d %I:%M:%S %p");
Joe Onorato8a9b2202010-02-26 18:56:32 -0800400 Slog.v(TAG, position + ": " + timeStr
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 + " " + a.operation.getTargetPackage());
402 position += 1;
403 }
404 }
405
406 return index;
407 }
408
409 public long timeToNextAlarm() {
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700410 long nextAlarm = Long.MAX_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 synchronized (mLock) {
412 for (int i=AlarmManager.RTC_WAKEUP;
413 i<=AlarmManager.ELAPSED_REALTIME; i++) {
414 ArrayList<Alarm> alarmList = getAlarmList(i);
415 if (alarmList.size() > 0) {
416 Alarm a = alarmList.get(0);
417 if (a.when < nextAlarm) {
418 nextAlarm = a.when;
419 }
420 }
421 }
422 }
423 return nextAlarm;
424 }
425
426 private void setLocked(Alarm alarm)
427 {
428 if (mDescriptor != -1)
429 {
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700430 // The kernel never triggers alarms with negative wakeup times
431 // so we ensure they are positive.
432 long alarmSeconds, alarmNanoseconds;
433 if (alarm.when < 0) {
434 alarmSeconds = 0;
435 alarmNanoseconds = 0;
436 } else {
437 alarmSeconds = alarm.when / 1000;
438 alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000;
439 }
440
441 set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 }
443 else
444 {
445 Message msg = Message.obtain();
446 msg.what = ALARM_EVENT;
447
448 mHandler.removeMessages(ALARM_EVENT);
449 mHandler.sendMessageAtTime(msg, alarm.when);
450 }
451 }
452
453 @Override
454 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
455 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
456 != PackageManager.PERMISSION_GRANTED) {
457 pw.println("Permission Denial: can't dump AlarmManager from from pid="
458 + Binder.getCallingPid()
459 + ", uid=" + Binder.getCallingUid());
460 return;
461 }
462
463 synchronized (mLock) {
464 pw.println("Current Alarm Manager state:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700465 if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700466 final long now = System.currentTimeMillis();
467 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700469 pw.print(" Realtime wakeup (now=");
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700470 pw.print(sdf.format(new Date(now))); pw.println("):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700471 if (mRtcWakeupAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700472 dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700473 }
474 if (mRtcAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700475 dumpAlarmList(pw, mRtcAlarms, " ", "RTC", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700476 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700478 if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700479 final long now = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700481 pw.print(" Elapsed realtime wakeup (now=");
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700482 TimeUtils.formatDuration(now, pw); pw.println("):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700483 if (mElapsedRealtimeWakeupAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700484 dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700485 }
486 if (mElapsedRealtimeAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700487 dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 }
490
491 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700492 pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493
494 pw.println(" ");
495 pw.println(" Alarm Stats:");
496 for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
497 BroadcastStats bs = be.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700498 pw.print(" "); pw.println(be.getKey());
499 pw.print(" "); pw.print(bs.aggregateTime);
500 pw.print("ms running, "); pw.print(bs.numWakeup);
501 pw.println(" wakeups");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 for (Map.Entry<Intent.FilterComparison, FilterStats> fe
503 : bs.filterStats.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700504 pw.print(" "); pw.print(fe.getValue().count);
505 pw.print(" alarms: ");
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800506 pw.println(fe.getKey().getIntent().toShortString(
507 false, true, false, true));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 }
509 }
510 }
511 }
512
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700513 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
514 String prefix, String label, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 for (int i=list.size()-1; i>=0; i--) {
516 Alarm a = list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700517 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
518 pw.print(": "); pw.println(a);
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700519 a.dump(pw, prefix + " ", now);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 }
521 }
522
523 private native int init();
524 private native void close(int fd);
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700525 private native void set(int fd, int type, long seconds, long nanoseconds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 private native int waitForAlarm(int fd);
527 private native int setKernelTimezone(int fd, int minuteswest);
528
529 private void triggerAlarmsLocked(ArrayList<Alarm> alarmList,
530 ArrayList<Alarm> triggerList,
531 long now)
532 {
533 Iterator<Alarm> it = alarmList.iterator();
534 ArrayList<Alarm> repeats = new ArrayList<Alarm>();
535
536 while (it.hasNext())
537 {
538 Alarm alarm = it.next();
539
Joe Onorato8a9b2202010-02-26 18:56:32 -0800540 if (localLOGV) Slog.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541
542 if (alarm.when > now) {
543 // don't fire alarms in the future
544 break;
545 }
546
547 // If the alarm is late, then print a warning message.
548 // Note that this can happen if the user creates a new event on
549 // the Calendar app with a reminder that is in the past. In that
550 // case, the reminder alarm will fire immediately.
551 if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800552 Slog.v(TAG, "alarm is late! alarm time: " + alarm.when
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 + " now: " + now + " delay (in seconds): "
554 + (now - alarm.when) / 1000);
555 }
556
557 // Recurring alarms may have passed several alarm intervals while the
558 // phone was asleep or off, so pass a trigger count when sending them.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800559 if (localLOGV) Slog.v(TAG, "Alarm triggering: " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 alarm.count = 1;
561 if (alarm.repeatInterval > 0) {
562 // this adjustment will be zero if we're late by
563 // less than one full repeat interval
564 alarm.count += (now - alarm.when) / alarm.repeatInterval;
565 }
566 triggerList.add(alarm);
567
568 // remove the alarm from the list
569 it.remove();
570
571 // if it repeats queue it up to be read-added to the list
572 if (alarm.repeatInterval > 0) {
573 repeats.add(alarm);
574 }
575 }
576
577 // reset any repeating alarms.
578 it = repeats.iterator();
579 while (it.hasNext()) {
580 Alarm alarm = it.next();
581 alarm.when += alarm.count * alarm.repeatInterval;
582 addAlarmLocked(alarm);
583 }
584
585 if (alarmList.size() > 0) {
586 setLocked(alarmList.get(0));
587 }
588 }
589
590 /**
591 * This Comparator sorts Alarms into increasing time order.
592 */
593 public static class IncreasingTimeOrder implements Comparator<Alarm> {
594 public int compare(Alarm a1, Alarm a2) {
595 long when1 = a1.when;
596 long when2 = a2.when;
597 if (when1 - when2 > 0) {
598 return 1;
599 }
600 if (when1 - when2 < 0) {
601 return -1;
602 }
603 return 0;
604 }
605 }
606
607 private static class Alarm {
608 public int type;
609 public int count;
610 public long when;
611 public long repeatInterval;
612 public PendingIntent operation;
613
614 public Alarm() {
615 when = 0;
616 repeatInterval = 0;
617 operation = null;
618 }
619
620 @Override
621 public String toString()
622 {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700623 StringBuilder sb = new StringBuilder(128);
624 sb.append("Alarm{");
625 sb.append(Integer.toHexString(System.identityHashCode(this)));
626 sb.append(" type ");
627 sb.append(type);
628 sb.append(" ");
629 sb.append(operation.getTargetPackage());
630 sb.append('}');
631 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 }
633
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700634 public void dump(PrintWriter pw, String prefix, long now) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700635 pw.print(prefix); pw.print("type="); pw.print(type);
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700636 pw.print(" when="); TimeUtils.formatDuration(when, now, pw);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700637 pw.print(" repeatInterval="); pw.print(repeatInterval);
638 pw.print(" count="); pw.println(count);
639 pw.print(prefix); pw.print("operation="); pw.println(operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 }
641 }
642
643 private class AlarmThread extends Thread
644 {
645 public AlarmThread()
646 {
647 super("AlarmManager");
648 }
649
650 public void run()
651 {
652 while (true)
653 {
654 int result = waitForAlarm(mDescriptor);
655
656 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
657
658 if ((result & TIME_CHANGED_MASK) != 0) {
659 remove(mTimeTickSender);
660 mClockReceiver.scheduleTimeTickEvent();
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800661 Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
Dianne Hackborn89ba6752011-01-23 16:51:16 -0800662 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
663 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800664 mContext.sendBroadcast(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 }
666
667 synchronized (mLock) {
668 final long nowRTC = System.currentTimeMillis();
669 final long nowELAPSED = SystemClock.elapsedRealtime();
Joe Onorato8a9b2202010-02-26 18:56:32 -0800670 if (localLOGV) Slog.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 TAG, "Checking for alarms... rtc=" + nowRTC
672 + ", elapsed=" + nowELAPSED);
673
674 if ((result & RTC_WAKEUP_MASK) != 0)
675 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
676
677 if ((result & RTC_MASK) != 0)
678 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
679
680 if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0)
681 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED);
682
683 if ((result & ELAPSED_REALTIME_MASK) != 0)
684 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED);
685
686 // now trigger the alarms
687 Iterator<Alarm> it = triggerList.iterator();
688 while (it.hasNext()) {
689 Alarm alarm = it.next();
690 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800691 if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 alarm.operation.send(mContext, 0,
693 mBackgroundIntent.putExtra(
694 Intent.EXTRA_ALARM_COUNT, alarm.count),
695 mResultReceiver, mHandler);
696
Christopher Tatec4a07d12012-04-06 14:19:13 -0700697 // we have an active broadcast so stay awake.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 if (mBroadcastRefCount == 0) {
Christopher Tatec4a07d12012-04-06 14:19:13 -0700699 setWakelockWorkSource(alarm.operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 mWakeLock.acquire();
701 }
Christopher Tatec4a07d12012-04-06 14:19:13 -0700702 mInFlight.add(alarm.operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 mBroadcastRefCount++;
704
705 BroadcastStats bs = getStatsLocked(alarm.operation);
706 if (bs.nesting == 0) {
707 bs.startTime = nowELAPSED;
708 } else {
709 bs.nesting++;
710 }
711 if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP
712 || alarm.type == AlarmManager.RTC_WAKEUP) {
713 bs.numWakeup++;
714 ActivityManagerNative.noteWakeupAlarm(
715 alarm.operation);
716 }
717 } catch (PendingIntent.CanceledException e) {
718 if (alarm.repeatInterval > 0) {
719 // This IntentSender is no longer valid, but this
720 // is a repeating alarm, so toss the hoser.
721 remove(alarm.operation);
722 }
723 } catch (RuntimeException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800724 Slog.w(TAG, "Failure sending alarm.", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 }
726 }
727 }
728 }
729 }
730 }
Christopher Tatec4a07d12012-04-06 14:19:13 -0700731
732 void setWakelockWorkSource(PendingIntent pi) {
733 try {
734 final int uid = ActivityManagerNative.getDefault()
735 .getUidForIntentSender(pi.getTarget());
736 if (uid >= 0) {
737 mWakeLock.setWorkSource(new WorkSource(uid));
738 return;
739 }
740 } catch (Exception e) {
741 }
742
743 // Something went wrong; fall back to attributing the lock to the OS
744 mWakeLock.setWorkSource(null);
745 }
746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 private class AlarmHandler extends Handler {
748 public static final int ALARM_EVENT = 1;
749 public static final int MINUTE_CHANGE_EVENT = 2;
750 public static final int DATE_CHANGE_EVENT = 3;
751
752 public AlarmHandler() {
753 }
754
755 public void handleMessage(Message msg) {
756 if (msg.what == ALARM_EVENT) {
757 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
758 synchronized (mLock) {
759 final long nowRTC = System.currentTimeMillis();
760 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
761 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
762 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC);
763 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC);
764 }
765
766 // now trigger the alarms without the lock held
767 Iterator<Alarm> it = triggerList.iterator();
768 while (it.hasNext())
769 {
770 Alarm alarm = it.next();
771 try {
772 alarm.operation.send();
773 } catch (PendingIntent.CanceledException e) {
774 if (alarm.repeatInterval > 0) {
775 // This IntentSender is no longer valid, but this
776 // is a repeating alarm, so toss the hoser.
777 remove(alarm.operation);
778 }
779 }
780 }
781 }
782 }
783 }
784
785 class ClockReceiver extends BroadcastReceiver {
786 public ClockReceiver() {
787 IntentFilter filter = new IntentFilter();
788 filter.addAction(Intent.ACTION_TIME_TICK);
789 filter.addAction(Intent.ACTION_DATE_CHANGED);
790 mContext.registerReceiver(this, filter);
791 }
792
793 @Override
794 public void onReceive(Context context, Intent intent) {
795 if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
796 scheduleTimeTickEvent();
797 } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
798 // Since the kernel does not keep track of DST, we need to
799 // reset the TZ information at the beginning of each day
800 // based off of the current Zone gmt offset + userspace tracked
801 // daylight savings information.
802 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
Lavettacn Xiaoc84cc4f2010-08-30 12:47:23 +0200803 int gmtOffset = zone.getOffset(System.currentTimeMillis());
804 setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 scheduleDateChangedEvent();
806 }
807 }
808
809 public void scheduleTimeTickEvent() {
810 Calendar calendar = Calendar.getInstance();
Paul Westbrook51608a52011-08-25 13:18:54 -0700811 final long currentTime = System.currentTimeMillis();
812 calendar.setTimeInMillis(currentTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 calendar.add(Calendar.MINUTE, 1);
814 calendar.set(Calendar.SECOND, 0);
815 calendar.set(Calendar.MILLISECOND, 0);
Paul Westbrook51608a52011-08-25 13:18:54 -0700816
817 // Schedule this event for the amount of time that it would take to get to
818 // the top of the next minute.
819 final long tickEventDelay = calendar.getTimeInMillis() - currentTime;
820
821 set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay,
822 mTimeTickSender);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 }
824
825 public void scheduleDateChangedEvent() {
826 Calendar calendar = Calendar.getInstance();
827 calendar.setTimeInMillis(System.currentTimeMillis());
828 calendar.set(Calendar.HOUR, 0);
829 calendar.set(Calendar.MINUTE, 0);
830 calendar.set(Calendar.SECOND, 0);
831 calendar.set(Calendar.MILLISECOND, 0);
832 calendar.add(Calendar.DAY_OF_MONTH, 1);
833
834 set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender);
835 }
836 }
837
838 class UninstallReceiver extends BroadcastReceiver {
839 public UninstallReceiver() {
840 IntentFilter filter = new IntentFilter();
841 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
842 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800843 filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 filter.addDataScheme("package");
845 mContext.registerReceiver(this, filter);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800846 // Register for events related to sdcard installation.
847 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800848 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700849 sdFilter.addAction(Intent.ACTION_USER_STOPPED);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800850 mContext.registerReceiver(this, sdFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 }
852
853 @Override
854 public void onReceive(Context context, Intent intent) {
855 synchronized (mLock) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800856 String action = intent.getAction();
857 String pkgList[] = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800858 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
859 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
860 for (String packageName : pkgList) {
861 if (lookForPackageLocked(packageName)) {
862 setResultCode(Activity.RESULT_OK);
863 return;
864 }
865 }
866 return;
867 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800868 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700869 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
870 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
871 if (userHandle >= 0) {
872 removeUserLocked(userHandle);
873 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800874 } else {
Dianne Hackborn409578f2010-03-10 17:23:43 -0800875 if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
876 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
877 // This package is being updated; don't kill its alarms.
878 return;
879 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800880 Uri data = intent.getData();
881 if (data != null) {
882 String pkg = data.getSchemeSpecificPart();
883 if (pkg != null) {
884 pkgList = new String[]{pkg};
885 }
886 }
887 }
888 if (pkgList != null && (pkgList.length > 0)) {
889 for (String pkg : pkgList) {
890 removeLocked(pkg);
891 mBroadcastStats.remove(pkg);
892 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 }
894 }
895 }
896 }
897
898 private final BroadcastStats getStatsLocked(PendingIntent pi) {
899 String pkg = pi.getTargetPackage();
900 BroadcastStats bs = mBroadcastStats.get(pkg);
901 if (bs == null) {
902 bs = new BroadcastStats();
903 mBroadcastStats.put(pkg, bs);
904 }
905 return bs;
906 }
907
908 class ResultReceiver implements PendingIntent.OnFinished {
909 public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
910 String resultData, Bundle resultExtras) {
911 synchronized (mLock) {
912 BroadcastStats bs = getStatsLocked(pi);
913 if (bs != null) {
914 bs.nesting--;
915 if (bs.nesting <= 0) {
916 bs.nesting = 0;
917 bs.aggregateTime += SystemClock.elapsedRealtime()
918 - bs.startTime;
919 Intent.FilterComparison fc = new Intent.FilterComparison(intent);
920 FilterStats fs = bs.filterStats.get(fc);
921 if (fs == null) {
922 fs = new FilterStats();
923 bs.filterStats.put(fc, fs);
924 }
925 fs.count++;
926 }
927 }
Christopher Tatec4a07d12012-04-06 14:19:13 -0700928 mInFlight.removeFirst();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 mBroadcastRefCount--;
930 if (mBroadcastRefCount == 0) {
931 mWakeLock.release();
Christopher Tatec4a07d12012-04-06 14:19:13 -0700932 } else {
933 // the next of our alarms is now in flight. reattribute the wakelock.
934 final PendingIntent nowInFlight = mInFlight.peekFirst();
935 if (nowInFlight != null) {
936 setWakelockWorkSource(nowInFlight);
937 } else {
938 // should never happen
939 Slog.e(TAG, "Alarm wakelock still held but sent queue empty");
940 mWakeLock.setWorkSource(null);
941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 }
943 }
944 }
945 }
946}