blob: 0be9ca59331588251fb134a94cf9f0c78939f69e [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;
Dianne Hackborn81038902012-11-26 17:04:09 -080025import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.pm.PackageManager;
30import android.net.Uri;
31import android.os.Binder;
32import android.os.Bundle;
33import android.os.Handler;
34import android.os.Message;
35import android.os.PowerManager;
36import android.os.SystemClock;
37import android.os.SystemProperties;
Dianne Hackborn80a4af22012-08-27 19:18:31 -070038import android.os.UserHandle;
Christopher Tatec4a07d12012-04-06 14:19:13 -070039import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.text.TextUtils;
41import android.text.format.Time;
Dianne Hackborn81038902012-11-26 17:04:09 -080042import android.util.Pair;
Joe Onorato8a9b2202010-02-26 18:56:32 -080043import android.util.Slog;
Dianne Hackborn043fcd92010-10-06 14:27:34 -070044import android.util.TimeUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045
46import java.io.FileDescriptor;
47import java.io.PrintWriter;
Dianne Hackborn043fcd92010-10-06 14:27:34 -070048import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import java.util.ArrayList;
Dianne Hackborn81038902012-11-26 17:04:09 -080050import java.util.Arrays;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import java.util.Calendar;
52import java.util.Collections;
53import java.util.Comparator;
Mike Lockwood1f7b4132009-11-20 15:12:51 -050054import java.util.Date;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import java.util.HashMap;
Christopher Tate18a75f12013-07-01 18:18:59 -070056import java.util.LinkedList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import java.util.Map;
58import java.util.TimeZone;
59
Dianne Hackborn81038902012-11-26 17:04:09 -080060import com.android.internal.util.LocalLog;
61
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062class 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;
Christopher Tate18a75f12013-07-01 18:18:59 -070072 private static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
Christopher Tateb8849c12011-02-08 13:39:01 -080073
74 // Alignment quantum for inexact repeating alarms
75 private static final long QUANTUM = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
76
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 private static final String TAG = "AlarmManager";
78 private static final String ClockReceiver_TAG = "ClockReceiver";
79 private static final boolean localLOGV = false;
80 private static final int ALARM_EVENT = 1;
81 private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
82
83 private static final Intent mBackgroundIntent
84 = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
85
Christopher Tate18a75f12013-07-01 18:18:59 -070086 private static final boolean WAKEUP_STATS = true;
87
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 private final Context mContext;
Dianne Hackborn81038902012-11-26 17:04:09 -080089
90 private final LocalLog mLog = new LocalLog(TAG);
91
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 private Object mLock = new Object();
93
94 private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>();
95 private final ArrayList<Alarm> mRtcAlarms = new ArrayList<Alarm>();
96 private final ArrayList<Alarm> mElapsedRealtimeWakeupAlarms = new ArrayList<Alarm>();
97 private final ArrayList<Alarm> mElapsedRealtimeAlarms = new ArrayList<Alarm>();
98 private final IncreasingTimeOrder mIncreasingTimeOrder = new IncreasingTimeOrder();
99
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private int mDescriptor;
101 private int mBroadcastRefCount = 0;
102 private PowerManager.WakeLock mWakeLock;
Dianne Hackborn81038902012-11-26 17:04:09 -0800103 private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 private final AlarmThread mWaitThread = new AlarmThread();
105 private final AlarmHandler mHandler = new AlarmHandler();
106 private ClockReceiver mClockReceiver;
107 private UninstallReceiver mUninstallReceiver;
108 private final ResultReceiver mResultReceiver = new ResultReceiver();
109 private final PendingIntent mTimeTickSender;
110 private final PendingIntent mDateChangeSender;
Dianne Hackborn81038902012-11-26 17:04:09 -0800111
Christopher Tate18a75f12013-07-01 18:18:59 -0700112 class WakeupEvent {
113 public long when;
114 public int uid;
115 public String action;
116
117 public WakeupEvent(long theTime, int theUid, String theAction) {
118 when = theTime;
119 uid = theUid;
120 action = theAction;
121 }
122 }
123
124 private final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
125 private final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
126
Dianne Hackborn81038902012-11-26 17:04:09 -0800127 private static final class InFlight extends Intent {
128 final PendingIntent mPendingIntent;
129 final Pair<String, ComponentName> mTarget;
130 final BroadcastStats mBroadcastStats;
131 final FilterStats mFilterStats;
132
133 InFlight(AlarmManagerService service, PendingIntent pendingIntent) {
134 mPendingIntent = pendingIntent;
135 Intent intent = pendingIntent.getIntent();
136 mTarget = intent != null
137 ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent())
138 : null;
139 mBroadcastStats = service.getStatsLocked(pendingIntent);
140 FilterStats fs = mBroadcastStats.filterStats.get(mTarget);
141 if (fs == null) {
142 fs = new FilterStats(mBroadcastStats, mTarget);
143 mBroadcastStats.filterStats.put(mTarget, fs);
144 }
145 mFilterStats = fs;
146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800148
149 private static final class FilterStats {
150 final BroadcastStats mBroadcastStats;
151 final Pair<String, ComponentName> mTarget;
152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 long aggregateTime;
Dianne Hackborn81038902012-11-26 17:04:09 -0800154 int count;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 int numWakeup;
156 long startTime;
157 int nesting;
Dianne Hackborn81038902012-11-26 17:04:09 -0800158
159 FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target) {
160 mBroadcastStats = broadcastStats;
161 mTarget = target;
162 }
163 }
164
165 private static final class BroadcastStats {
166 final String mPackageName;
167
168 long aggregateTime;
169 int count;
170 int numWakeup;
171 long startTime;
172 int nesting;
173 final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
174 = new HashMap<Pair<String, ComponentName>, FilterStats>();
175
176 BroadcastStats(String packageName) {
177 mPackageName = packageName;
178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 }
180
181 private final HashMap<String, BroadcastStats> mBroadcastStats
182 = new HashMap<String, BroadcastStats>();
183
184 public AlarmManagerService(Context context) {
185 mContext = context;
186 mDescriptor = init();
Robert CH Chou64ba8e42009-11-04 21:38:49 +0800187
188 // We have to set current TimeZone info to kernel
189 // because kernel doesn't keep this after reboot
190 String tz = SystemProperties.get(TIMEZONE_PROPERTY);
191 if (tz != null) {
192 setTimeZone(tz);
193 }
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
196 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
197
Dianne Hackborndb5aca92012-10-26 13:39:41 -0700198 mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 new Intent(Intent.ACTION_TIME_TICK).addFlags(
Dianne Hackborndb5aca92012-10-26 13:39:41 -0700200 Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0,
201 UserHandle.ALL);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800202 Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
203 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborndb5aca92012-10-26 13:39:41 -0700204 mDateChangeSender = PendingIntent.getBroadcastAsUser(context, 0, intent,
205 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
207 // now that we have initied the driver schedule the alarm
208 mClockReceiver= new ClockReceiver();
209 mClockReceiver.scheduleTimeTickEvent();
210 mClockReceiver.scheduleDateChangedEvent();
211 mUninstallReceiver = new UninstallReceiver();
212
213 if (mDescriptor != -1) {
214 mWaitThread.start();
215 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800216 Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 }
218 }
219
220 protected void finalize() throws Throwable {
221 try {
222 close(mDescriptor);
223 } finally {
224 super.finalize();
225 }
226 }
227
228 public void set(int type, long triggerAtTime, PendingIntent operation) {
229 setRepeating(type, triggerAtTime, 0, operation);
230 }
231
232 public void setRepeating(int type, long triggerAtTime, long interval,
233 PendingIntent operation) {
234 if (operation == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800235 Slog.w(TAG, "set/setRepeating ignored because there is no intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 return;
237 }
238 synchronized (mLock) {
239 Alarm alarm = new Alarm();
240 alarm.type = type;
241 alarm.when = triggerAtTime;
242 alarm.repeatInterval = interval;
243 alarm.operation = operation;
244
245 // Remove this alarm if already scheduled.
246 removeLocked(operation);
247
Joe Onorato8a9b2202010-02-26 18:56:32 -0800248 if (localLOGV) Slog.v(TAG, "set: " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249
250 int index = addAlarmLocked(alarm);
251 if (index == 0) {
252 setLocked(alarm);
253 }
254 }
255 }
256
257 public void setInexactRepeating(int type, long triggerAtTime, long interval,
258 PendingIntent operation) {
259 if (operation == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800260 Slog.w(TAG, "setInexactRepeating ignored because there is no intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 return;
262 }
263
Christopher Tateb8849c12011-02-08 13:39:01 -0800264 if (interval <= 0) {
265 Slog.w(TAG, "setInexactRepeating ignored because interval " + interval
266 + " is invalid");
267 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 }
Christopher Tateb8849c12011-02-08 13:39:01 -0800269
270 // If the requested interval isn't a multiple of 15 minutes, just treat it as exact
271 if (interval % QUANTUM != 0) {
272 if (localLOGV) Slog.v(TAG, "Interval " + interval + " not a quantum multiple");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 setRepeating(type, triggerAtTime, interval, operation);
274 return;
275 }
276
Christopher Tateb8849c12011-02-08 13:39:01 -0800277 // Translate times into the ELAPSED timebase for alignment purposes so that
278 // alignment never tries to match against wall clock times.
279 final boolean isRtc = (type == AlarmManager.RTC || type == AlarmManager.RTC_WAKEUP);
280 final long skew = (isRtc)
281 ? System.currentTimeMillis() - SystemClock.elapsedRealtime()
282 : 0;
283
284 // Slip forward to the next ELAPSED-timebase quantum after the stated time. If
285 // we're *at* a quantum point, leave it alone.
286 final long adjustedTriggerTime;
287 long offset = (triggerAtTime - skew) % QUANTUM;
288 if (offset != 0) {
289 adjustedTriggerTime = triggerAtTime - offset + QUANTUM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 } else {
Christopher Tateb8849c12011-02-08 13:39:01 -0800291 adjustedTriggerTime = triggerAtTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 }
293
Christopher Tateb8849c12011-02-08 13:39:01 -0800294 // Set the alarm based on the quantum-aligned start time
295 if (localLOGV) Slog.v(TAG, "setInexactRepeating: type=" + type + " interval=" + interval
296 + " trigger=" + adjustedTriggerTime + " orig=" + triggerAtTime);
297 setRepeating(type, adjustedTriggerTime, interval, operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 }
299
Dan Egnor97e44942010-02-04 20:27:47 -0800300 public void setTime(long millis) {
301 mContext.enforceCallingOrSelfPermission(
302 "android.permission.SET_TIME",
303 "setTime");
304
305 SystemClock.setCurrentTimeMillis(millis);
306 }
307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 public void setTimeZone(String tz) {
309 mContext.enforceCallingOrSelfPermission(
310 "android.permission.SET_TIME_ZONE",
311 "setTimeZone");
312
Christopher Tate89779822012-08-31 14:40:03 -0700313 long oldId = Binder.clearCallingIdentity();
314 try {
315 if (TextUtils.isEmpty(tz)) return;
316 TimeZone zone = TimeZone.getTimeZone(tz);
317 // Prevent reentrant calls from stepping on each other when writing
318 // the time zone property
319 boolean timeZoneWasChanged = false;
320 synchronized (this) {
321 String current = SystemProperties.get(TIMEZONE_PROPERTY);
322 if (current == null || !current.equals(zone.getID())) {
323 if (localLOGV) {
324 Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
325 }
326 timeZoneWasChanged = true;
327 SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
328 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329
Christopher Tate89779822012-08-31 14:40:03 -0700330 // Update the kernel timezone information
331 // Kernel tracks time offsets as 'minutes west of GMT'
332 int gmtOffset = zone.getOffset(System.currentTimeMillis());
333 setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
334 }
335
336 TimeZone.setDefault(null);
337
338 if (timeZoneWasChanged) {
339 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
340 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
341 intent.putExtra("time-zone", zone.getID());
342 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
343 }
344 } finally {
345 Binder.restoreCallingIdentity(oldId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 }
347 }
348
349 public void remove(PendingIntent operation) {
350 if (operation == null) {
351 return;
352 }
353 synchronized (mLock) {
354 removeLocked(operation);
355 }
356 }
357
358 public void removeLocked(PendingIntent operation) {
359 removeLocked(mRtcWakeupAlarms, operation);
360 removeLocked(mRtcAlarms, operation);
361 removeLocked(mElapsedRealtimeWakeupAlarms, operation);
362 removeLocked(mElapsedRealtimeAlarms, operation);
363 }
364
365 private void removeLocked(ArrayList<Alarm> alarmList,
366 PendingIntent operation) {
367 if (alarmList.size() <= 0) {
368 return;
369 }
370
371 // iterator over the list removing any it where the intent match
Dianne Hackborn390517b2013-05-30 15:03:32 -0700372 for (int i=0; i<alarmList.size(); i++) {
373 Alarm alarm = alarmList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 if (alarm.operation.equals(operation)) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700375 alarmList.remove(i);
376 i--;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 }
378 }
379 }
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 public void removeLocked(String packageName) {
382 removeLocked(mRtcWakeupAlarms, packageName);
383 removeLocked(mRtcAlarms, packageName);
384 removeLocked(mElapsedRealtimeWakeupAlarms, packageName);
385 removeLocked(mElapsedRealtimeAlarms, packageName);
386 }
387
388 private void removeLocked(ArrayList<Alarm> alarmList,
389 String packageName) {
390 if (alarmList.size() <= 0) {
391 return;
392 }
393
394 // iterator over the list removing any it where the intent match
Dianne Hackborn390517b2013-05-30 15:03:32 -0700395 for (int i=0; i<alarmList.size(); i++) {
396 Alarm alarm = alarmList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 if (alarm.operation.getTargetPackage().equals(packageName)) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700398 alarmList.remove(i);
399 i--;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 }
401 }
402 }
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700403
404 public void removeUserLocked(int userHandle) {
405 removeUserLocked(mRtcWakeupAlarms, userHandle);
406 removeUserLocked(mRtcAlarms, userHandle);
407 removeUserLocked(mElapsedRealtimeWakeupAlarms, userHandle);
408 removeUserLocked(mElapsedRealtimeAlarms, userHandle);
409 }
410
411 private void removeUserLocked(ArrayList<Alarm> alarmList, int userHandle) {
412 if (alarmList.size() <= 0) {
413 return;
414 }
415
416 // iterator over the list removing any it where the intent match
Dianne Hackborn390517b2013-05-30 15:03:32 -0700417 for (int i=0; i<alarmList.size(); i++) {
418 Alarm alarm = alarmList.get(i);
Dianne Hackborn8832c182012-09-17 17:20:24 -0700419 if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700420 alarmList.remove(i);
421 i--;
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700422 }
423 }
424 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800426 public boolean lookForPackageLocked(String packageName) {
427 return lookForPackageLocked(mRtcWakeupAlarms, packageName)
428 || lookForPackageLocked(mRtcAlarms, packageName)
429 || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName)
430 || lookForPackageLocked(mElapsedRealtimeAlarms, packageName);
431 }
432
433 private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) {
434 for (int i=alarmList.size()-1; i>=0; i--) {
435 if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) {
436 return true;
437 }
438 }
439 return false;
440 }
441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 private ArrayList<Alarm> getAlarmList(int type) {
443 switch (type) {
444 case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms;
445 case AlarmManager.RTC: return mRtcAlarms;
446 case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms;
447 case AlarmManager.ELAPSED_REALTIME: return mElapsedRealtimeAlarms;
448 }
449
450 return null;
451 }
452
453 private int addAlarmLocked(Alarm alarm) {
454 ArrayList<Alarm> alarmList = getAlarmList(alarm.type);
455
456 int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder);
457 if (index < 0) {
458 index = 0 - index - 1;
459 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800460 if (localLOGV) Slog.v(TAG, "Adding alarm " + alarm + " at " + index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 alarmList.add(index, alarm);
462
463 if (localLOGV) {
464 // Display the list of alarms for this alarm type
Joe Onorato8a9b2202010-02-26 18:56:32 -0800465 Slog.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 int position = 0;
467 for (Alarm a : alarmList) {
468 Time time = new Time();
469 time.set(a.when);
470 String timeStr = time.format("%b %d %I:%M:%S %p");
Joe Onorato8a9b2202010-02-26 18:56:32 -0800471 Slog.v(TAG, position + ": " + timeStr
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 + " " + a.operation.getTargetPackage());
473 position += 1;
474 }
475 }
476
477 return index;
478 }
479
480 public long timeToNextAlarm() {
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700481 long nextAlarm = Long.MAX_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 synchronized (mLock) {
483 for (int i=AlarmManager.RTC_WAKEUP;
484 i<=AlarmManager.ELAPSED_REALTIME; i++) {
485 ArrayList<Alarm> alarmList = getAlarmList(i);
486 if (alarmList.size() > 0) {
487 Alarm a = alarmList.get(0);
488 if (a.when < nextAlarm) {
489 nextAlarm = a.when;
490 }
491 }
492 }
493 }
494 return nextAlarm;
495 }
496
497 private void setLocked(Alarm alarm)
498 {
499 if (mDescriptor != -1)
500 {
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700501 // The kernel never triggers alarms with negative wakeup times
502 // so we ensure they are positive.
503 long alarmSeconds, alarmNanoseconds;
504 if (alarm.when < 0) {
505 alarmSeconds = 0;
506 alarmNanoseconds = 0;
507 } else {
508 alarmSeconds = alarm.when / 1000;
509 alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000;
510 }
511
512 set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 }
514 else
515 {
516 Message msg = Message.obtain();
517 msg.what = ALARM_EVENT;
518
519 mHandler.removeMessages(ALARM_EVENT);
520 mHandler.sendMessageAtTime(msg, alarm.when);
521 }
522 }
523
524 @Override
525 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
526 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
527 != PackageManager.PERMISSION_GRANTED) {
528 pw.println("Permission Denial: can't dump AlarmManager from from pid="
529 + Binder.getCallingPid()
530 + ", uid=" + Binder.getCallingUid());
531 return;
532 }
533
534 synchronized (mLock) {
535 pw.println("Current Alarm Manager state:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700536 if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700537 final long now = System.currentTimeMillis();
538 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700540 pw.print(" Realtime wakeup (now=");
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700541 pw.print(sdf.format(new Date(now))); pw.println("):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700542 if (mRtcWakeupAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700543 dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700544 }
545 if (mRtcAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700546 dumpAlarmList(pw, mRtcAlarms, " ", "RTC", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700547 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700549 if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700550 final long now = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700552 pw.print(" Elapsed realtime wakeup (now=");
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700553 TimeUtils.formatDuration(now, pw); pw.println("):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700554 if (mElapsedRealtimeWakeupAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700555 dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700556 }
557 if (mElapsedRealtimeAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700558 dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800561
562 pw.println();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700563 pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
Dianne Hackborn81038902012-11-26 17:04:09 -0800564 pw.println();
565
566 if (mLog.dump(pw, " Recent problems", " ")) {
567 pw.println();
568 }
569
570 final FilterStats[] topFilters = new FilterStats[10];
571 final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
572 @Override
573 public int compare(FilterStats lhs, FilterStats rhs) {
574 if (lhs.aggregateTime < rhs.aggregateTime) {
575 return 1;
576 } else if (lhs.aggregateTime > rhs.aggregateTime) {
577 return -1;
578 }
579 return 0;
580 }
581 };
582 int len = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
584 BroadcastStats bs = be.getValue();
Dianne Hackborn81038902012-11-26 17:04:09 -0800585 for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 : bs.filterStats.entrySet()) {
Dianne Hackborn81038902012-11-26 17:04:09 -0800587 FilterStats fs = fe.getValue();
588 int pos = len > 0
589 ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
590 if (pos < 0) {
591 pos = -pos - 1;
592 }
593 if (pos < topFilters.length) {
594 int copylen = topFilters.length - pos - 1;
595 if (copylen > 0) {
596 System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
597 }
598 topFilters[pos] = fs;
599 if (len < topFilters.length) {
600 len++;
601 }
602 }
603 }
604 }
605 if (len > 0) {
606 pw.println(" Top Alarms:");
607 for (int i=0; i<len; i++) {
608 FilterStats fs = topFilters[i];
609 pw.print(" ");
610 if (fs.nesting > 0) pw.print("*ACTIVE* ");
611 TimeUtils.formatDuration(fs.aggregateTime, pw);
612 pw.print(" running, "); pw.print(fs.numWakeup);
613 pw.print(" wakeups, "); pw.print(fs.count);
614 pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
615 pw.println();
616 pw.print(" ");
617 if (fs.mTarget.first != null) {
618 pw.print(" act="); pw.print(fs.mTarget.first);
619 }
620 if (fs.mTarget.second != null) {
621 pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
622 }
623 pw.println();
624 }
625 }
626
627 pw.println(" ");
628 pw.println(" Alarm Stats:");
629 final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
630 for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
631 BroadcastStats bs = be.getValue();
632 pw.print(" ");
633 if (bs.nesting > 0) pw.print("*ACTIVE* ");
634 pw.print(be.getKey());
635 pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
636 pw.print(" running, "); pw.print(bs.numWakeup);
637 pw.println(" wakeups:");
638 tmpFilters.clear();
639 for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
640 : bs.filterStats.entrySet()) {
641 tmpFilters.add(fe.getValue());
642 }
643 Collections.sort(tmpFilters, comparator);
644 for (int i=0; i<tmpFilters.size(); i++) {
645 FilterStats fs = tmpFilters.get(i);
646 pw.print(" ");
647 if (fs.nesting > 0) pw.print("*ACTIVE* ");
648 TimeUtils.formatDuration(fs.aggregateTime, pw);
649 pw.print(" "); pw.print(fs.numWakeup);
650 pw.print(" wakes " ); pw.print(fs.count);
651 pw.print(" alarms:");
652 if (fs.mTarget.first != null) {
653 pw.print(" act="); pw.print(fs.mTarget.first);
654 }
655 if (fs.mTarget.second != null) {
656 pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
657 }
658 pw.println();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 }
660 }
Christopher Tate18a75f12013-07-01 18:18:59 -0700661
662 if (WAKEUP_STATS) {
663 pw.println();
664 pw.println(" Recent Wakeup History:");
665 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss.SSS");
666 long last = -1;
667 for (WakeupEvent event : mRecentWakeups) {
668 pw.print(" "); pw.print(sdf.format(new Date(event.when)));
669 pw.print('|');
670 if (last < 0) {
671 pw.print('0');
672 } else {
673 pw.print(event.when - last);
674 }
675 last = event.when;
676 pw.print('|'); pw.print(event.uid);
677 pw.print('|'); pw.print(event.action);
678 pw.println();
679 }
680 pw.println();
681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 }
683 }
684
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700685 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
686 String prefix, String label, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 for (int i=list.size()-1; i>=0; i--) {
688 Alarm a = list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700689 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
690 pw.print(": "); pw.println(a);
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700691 a.dump(pw, prefix + " ", now);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 }
693 }
694
695 private native int init();
696 private native void close(int fd);
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700697 private native void set(int fd, int type, long seconds, long nanoseconds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 private native int waitForAlarm(int fd);
699 private native int setKernelTimezone(int fd, int minuteswest);
700
701 private void triggerAlarmsLocked(ArrayList<Alarm> alarmList,
702 ArrayList<Alarm> triggerList,
703 long now)
704 {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700705 ArrayList<Alarm> repeats = null;
706
707 for (int i=0; i<alarmList.size(); i++) {
708 Alarm alarm = alarmList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709
Joe Onorato8a9b2202010-02-26 18:56:32 -0800710 if (localLOGV) Slog.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711
712 if (alarm.when > now) {
713 // don't fire alarms in the future
714 break;
715 }
716
717 // If the alarm is late, then print a warning message.
718 // Note that this can happen if the user creates a new event on
719 // the Calendar app with a reminder that is in the past. In that
720 // case, the reminder alarm will fire immediately.
721 if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800722 Slog.v(TAG, "alarm is late! alarm time: " + alarm.when
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 + " now: " + now + " delay (in seconds): "
724 + (now - alarm.when) / 1000);
725 }
726
727 // Recurring alarms may have passed several alarm intervals while the
728 // phone was asleep or off, so pass a trigger count when sending them.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800729 if (localLOGV) Slog.v(TAG, "Alarm triggering: " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 alarm.count = 1;
731 if (alarm.repeatInterval > 0) {
732 // this adjustment will be zero if we're late by
733 // less than one full repeat interval
734 alarm.count += (now - alarm.when) / alarm.repeatInterval;
735 }
736 triggerList.add(alarm);
737
738 // remove the alarm from the list
Dianne Hackborn390517b2013-05-30 15:03:32 -0700739 alarmList.remove(i);
740 i--;
741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 // if it repeats queue it up to be read-added to the list
743 if (alarm.repeatInterval > 0) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700744 if (repeats == null) {
745 repeats = new ArrayList<Alarm>();
746 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 repeats.add(alarm);
748 }
749 }
750
751 // reset any repeating alarms.
Dianne Hackborn390517b2013-05-30 15:03:32 -0700752 if (repeats != null) {
753 for (int i=0; i<repeats.size(); i++) {
754 Alarm alarm = repeats.get(i);
755 alarm.when += alarm.count * alarm.repeatInterval;
756 addAlarmLocked(alarm);
757 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 }
759
760 if (alarmList.size() > 0) {
761 setLocked(alarmList.get(0));
762 }
763 }
764
765 /**
766 * This Comparator sorts Alarms into increasing time order.
767 */
768 public static class IncreasingTimeOrder implements Comparator<Alarm> {
769 public int compare(Alarm a1, Alarm a2) {
770 long when1 = a1.when;
771 long when2 = a2.when;
772 if (when1 - when2 > 0) {
773 return 1;
774 }
775 if (when1 - when2 < 0) {
776 return -1;
777 }
778 return 0;
779 }
780 }
781
782 private static class Alarm {
783 public int type;
784 public int count;
785 public long when;
786 public long repeatInterval;
787 public PendingIntent operation;
788
789 public Alarm() {
790 when = 0;
791 repeatInterval = 0;
792 operation = null;
793 }
794
795 @Override
796 public String toString()
797 {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700798 StringBuilder sb = new StringBuilder(128);
799 sb.append("Alarm{");
800 sb.append(Integer.toHexString(System.identityHashCode(this)));
801 sb.append(" type ");
802 sb.append(type);
803 sb.append(" ");
804 sb.append(operation.getTargetPackage());
805 sb.append('}');
806 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
808
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700809 public void dump(PrintWriter pw, String prefix, long now) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700810 pw.print(prefix); pw.print("type="); pw.print(type);
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700811 pw.print(" when="); TimeUtils.formatDuration(when, now, pw);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700812 pw.print(" repeatInterval="); pw.print(repeatInterval);
813 pw.print(" count="); pw.println(count);
814 pw.print(prefix); pw.print("operation="); pw.println(operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 }
816 }
Christopher Tate18a75f12013-07-01 18:18:59 -0700817
818 void recordWakeupAlarms(ArrayList<Alarm> alarms, long now, long skewToRTC) {
819 for (Alarm a : alarms) {
820 if (a.when > now) {
821 break;
822 }
823
824 WakeupEvent e = new WakeupEvent(now + skewToRTC,
825 a.operation.getCreatorUid(),
826 a.operation.getIntent().getAction());
827 mRecentWakeups.add(e);
828 }
829 }
830
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 private class AlarmThread extends Thread
832 {
833 public AlarmThread()
834 {
835 super("AlarmManager");
836 }
837
838 public void run()
839 {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700840 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 while (true)
843 {
844 int result = waitForAlarm(mDescriptor);
Dianne Hackborn390517b2013-05-30 15:03:32 -0700845
846 triggerList.clear();
847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 if ((result & TIME_CHANGED_MASK) != 0) {
849 remove(mTimeTickSender);
850 mClockReceiver.scheduleTimeTickEvent();
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800851 Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
Dianne Hackborn89ba6752011-01-23 16:51:16 -0800852 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
853 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700854 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 }
856
857 synchronized (mLock) {
858 final long nowRTC = System.currentTimeMillis();
859 final long nowELAPSED = SystemClock.elapsedRealtime();
Joe Onorato8a9b2202010-02-26 18:56:32 -0800860 if (localLOGV) Slog.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 TAG, "Checking for alarms... rtc=" + nowRTC
862 + ", elapsed=" + nowELAPSED);
863
Christopher Tate18a75f12013-07-01 18:18:59 -0700864 if (WAKEUP_STATS) {
865 if ((result & IS_WAKEUP_MASK) != 0) {
866 long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
867 int n = 0;
868 for (WakeupEvent event : mRecentWakeups) {
869 if (event.when > newEarliest) break;
870 n++; // number of now-stale entries at the list head
871 }
872 for (int i = 0; i < n; i++) {
873 mRecentWakeups.remove();
874 }
875
876 recordWakeupAlarms(mRtcWakeupAlarms,
877 nowRTC,
878 0);
879 recordWakeupAlarms(mElapsedRealtimeWakeupAlarms,
880 nowELAPSED,
881 nowRTC - nowELAPSED);
882 }
883 }
884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 if ((result & RTC_WAKEUP_MASK) != 0)
886 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
887
888 if ((result & RTC_MASK) != 0)
889 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
890
891 if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0)
892 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED);
893
894 if ((result & ELAPSED_REALTIME_MASK) != 0)
895 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED);
896
897 // now trigger the alarms
Dianne Hackborn390517b2013-05-30 15:03:32 -0700898 for (int i=0; i<triggerList.size(); i++) {
899 Alarm alarm = triggerList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800901 if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 alarm.operation.send(mContext, 0,
903 mBackgroundIntent.putExtra(
904 Intent.EXTRA_ALARM_COUNT, alarm.count),
905 mResultReceiver, mHandler);
906
Christopher Tatec4a07d12012-04-06 14:19:13 -0700907 // we have an active broadcast so stay awake.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 if (mBroadcastRefCount == 0) {
Christopher Tatec4a07d12012-04-06 14:19:13 -0700909 setWakelockWorkSource(alarm.operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 mWakeLock.acquire();
911 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800912 final InFlight inflight = new InFlight(AlarmManagerService.this,
913 alarm.operation);
914 mInFlight.add(inflight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 mBroadcastRefCount++;
Dianne Hackborn81038902012-11-26 17:04:09 -0800916
917 final BroadcastStats bs = inflight.mBroadcastStats;
918 bs.count++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 if (bs.nesting == 0) {
Dianne Hackborn81038902012-11-26 17:04:09 -0800920 bs.nesting = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 bs.startTime = nowELAPSED;
922 } else {
923 bs.nesting++;
924 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800925 final FilterStats fs = inflight.mFilterStats;
926 fs.count++;
927 if (fs.nesting == 0) {
928 fs.nesting = 1;
929 fs.startTime = nowELAPSED;
930 } else {
931 fs.nesting++;
932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP
934 || alarm.type == AlarmManager.RTC_WAKEUP) {
935 bs.numWakeup++;
Dianne Hackborn81038902012-11-26 17:04:09 -0800936 fs.numWakeup++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 ActivityManagerNative.noteWakeupAlarm(
938 alarm.operation);
939 }
940 } catch (PendingIntent.CanceledException e) {
941 if (alarm.repeatInterval > 0) {
942 // This IntentSender is no longer valid, but this
943 // is a repeating alarm, so toss the hoser.
944 remove(alarm.operation);
945 }
946 } catch (RuntimeException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800947 Slog.w(TAG, "Failure sending alarm.", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 }
949 }
950 }
951 }
952 }
953 }
Christopher Tatec4a07d12012-04-06 14:19:13 -0700954
955 void setWakelockWorkSource(PendingIntent pi) {
956 try {
957 final int uid = ActivityManagerNative.getDefault()
958 .getUidForIntentSender(pi.getTarget());
959 if (uid >= 0) {
960 mWakeLock.setWorkSource(new WorkSource(uid));
961 return;
962 }
963 } catch (Exception e) {
964 }
965
966 // Something went wrong; fall back to attributing the lock to the OS
967 mWakeLock.setWorkSource(null);
968 }
969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 private class AlarmHandler extends Handler {
971 public static final int ALARM_EVENT = 1;
972 public static final int MINUTE_CHANGE_EVENT = 2;
973 public static final int DATE_CHANGE_EVENT = 3;
974
975 public AlarmHandler() {
976 }
977
978 public void handleMessage(Message msg) {
979 if (msg.what == ALARM_EVENT) {
980 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
981 synchronized (mLock) {
982 final long nowRTC = System.currentTimeMillis();
983 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
984 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
985 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC);
986 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC);
987 }
988
989 // now trigger the alarms without the lock held
Dianne Hackborn390517b2013-05-30 15:03:32 -0700990 for (int i=0; i<triggerList.size(); i++) {
991 Alarm alarm = triggerList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 try {
993 alarm.operation.send();
994 } catch (PendingIntent.CanceledException e) {
995 if (alarm.repeatInterval > 0) {
996 // This IntentSender is no longer valid, but this
997 // is a repeating alarm, so toss the hoser.
998 remove(alarm.operation);
999 }
1000 }
1001 }
1002 }
1003 }
1004 }
1005
1006 class ClockReceiver extends BroadcastReceiver {
1007 public ClockReceiver() {
1008 IntentFilter filter = new IntentFilter();
1009 filter.addAction(Intent.ACTION_TIME_TICK);
1010 filter.addAction(Intent.ACTION_DATE_CHANGED);
1011 mContext.registerReceiver(this, filter);
1012 }
1013
1014 @Override
1015 public void onReceive(Context context, Intent intent) {
1016 if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
1017 scheduleTimeTickEvent();
1018 } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
1019 // Since the kernel does not keep track of DST, we need to
1020 // reset the TZ information at the beginning of each day
1021 // based off of the current Zone gmt offset + userspace tracked
1022 // daylight savings information.
1023 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
Lavettacn Xiaoc84cc4f2010-08-30 12:47:23 +02001024 int gmtOffset = zone.getOffset(System.currentTimeMillis());
1025 setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 scheduleDateChangedEvent();
1027 }
1028 }
1029
1030 public void scheduleTimeTickEvent() {
Paul Westbrook51608a52011-08-25 13:18:54 -07001031 final long currentTime = System.currentTimeMillis();
Sungmin Choi563914a2013-01-10 17:28:40 +09001032 final long nextTime = 60000 * ((currentTime / 60000) + 1);
Paul Westbrook51608a52011-08-25 13:18:54 -07001033
1034 // Schedule this event for the amount of time that it would take to get to
1035 // the top of the next minute.
Sungmin Choi563914a2013-01-10 17:28:40 +09001036 final long tickEventDelay = nextTime - currentTime;
Paul Westbrook51608a52011-08-25 13:18:54 -07001037
1038 set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay,
1039 mTimeTickSender);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 }
1041
1042 public void scheduleDateChangedEvent() {
1043 Calendar calendar = Calendar.getInstance();
1044 calendar.setTimeInMillis(System.currentTimeMillis());
1045 calendar.set(Calendar.HOUR, 0);
1046 calendar.set(Calendar.MINUTE, 0);
1047 calendar.set(Calendar.SECOND, 0);
1048 calendar.set(Calendar.MILLISECOND, 0);
1049 calendar.add(Calendar.DAY_OF_MONTH, 1);
1050
1051 set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender);
1052 }
1053 }
1054
1055 class UninstallReceiver extends BroadcastReceiver {
1056 public UninstallReceiver() {
1057 IntentFilter filter = new IntentFilter();
1058 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1059 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001060 filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 filter.addDataScheme("package");
1062 mContext.registerReceiver(this, filter);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001063 // Register for events related to sdcard installation.
1064 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001065 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001066 sdFilter.addAction(Intent.ACTION_USER_STOPPED);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001067 mContext.registerReceiver(this, sdFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 }
1069
1070 @Override
1071 public void onReceive(Context context, Intent intent) {
1072 synchronized (mLock) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001073 String action = intent.getAction();
1074 String pkgList[] = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001075 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
1076 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
1077 for (String packageName : pkgList) {
1078 if (lookForPackageLocked(packageName)) {
1079 setResultCode(Activity.RESULT_OK);
1080 return;
1081 }
1082 }
1083 return;
1084 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001085 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001086 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
1087 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1088 if (userHandle >= 0) {
1089 removeUserLocked(userHandle);
1090 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001091 } else {
Dianne Hackborn409578f2010-03-10 17:23:43 -08001092 if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
1093 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1094 // This package is being updated; don't kill its alarms.
1095 return;
1096 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001097 Uri data = intent.getData();
1098 if (data != null) {
1099 String pkg = data.getSchemeSpecificPart();
1100 if (pkg != null) {
1101 pkgList = new String[]{pkg};
1102 }
1103 }
1104 }
1105 if (pkgList != null && (pkgList.length > 0)) {
1106 for (String pkg : pkgList) {
1107 removeLocked(pkg);
1108 mBroadcastStats.remove(pkg);
1109 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 }
1111 }
1112 }
1113 }
1114
1115 private final BroadcastStats getStatsLocked(PendingIntent pi) {
1116 String pkg = pi.getTargetPackage();
1117 BroadcastStats bs = mBroadcastStats.get(pkg);
1118 if (bs == null) {
Dianne Hackborn81038902012-11-26 17:04:09 -08001119 bs = new BroadcastStats(pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 mBroadcastStats.put(pkg, bs);
1121 }
1122 return bs;
1123 }
Dianne Hackborn81038902012-11-26 17:04:09 -08001124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 class ResultReceiver implements PendingIntent.OnFinished {
1126 public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
1127 String resultData, Bundle resultExtras) {
1128 synchronized (mLock) {
Dianne Hackborn81038902012-11-26 17:04:09 -08001129 InFlight inflight = null;
1130 for (int i=0; i<mInFlight.size(); i++) {
1131 if (mInFlight.get(i).mPendingIntent == pi) {
1132 inflight = mInFlight.remove(i);
1133 break;
1134 }
1135 }
1136 if (inflight != null) {
1137 final long nowELAPSED = SystemClock.elapsedRealtime();
1138 BroadcastStats bs = inflight.mBroadcastStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 bs.nesting--;
1140 if (bs.nesting <= 0) {
1141 bs.nesting = 0;
Dianne Hackborn81038902012-11-26 17:04:09 -08001142 bs.aggregateTime += nowELAPSED - bs.startTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 }
Dianne Hackborn81038902012-11-26 17:04:09 -08001144 FilterStats fs = inflight.mFilterStats;
1145 fs.nesting--;
1146 if (fs.nesting <= 0) {
1147 fs.nesting = 0;
1148 fs.aggregateTime += nowELAPSED - fs.startTime;
1149 }
1150 } else {
1151 mLog.w("No in-flight alarm for " + pi + " " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 }
1153 mBroadcastRefCount--;
1154 if (mBroadcastRefCount == 0) {
1155 mWakeLock.release();
Dianne Hackborn81038902012-11-26 17:04:09 -08001156 if (mInFlight.size() > 0) {
1157 mLog.w("Finished all broadcasts with " + mInFlight.size()
1158 + " remaining inflights");
1159 for (int i=0; i<mInFlight.size(); i++) {
1160 mLog.w(" Remaining #" + i + ": " + mInFlight.get(i));
1161 }
1162 mInFlight.clear();
1163 }
Christopher Tatec4a07d12012-04-06 14:19:13 -07001164 } else {
1165 // the next of our alarms is now in flight. reattribute the wakelock.
Dianne Hackborn81038902012-11-26 17:04:09 -08001166 if (mInFlight.size() > 0) {
1167 setWakelockWorkSource(mInFlight.get(0).mPendingIntent);
Christopher Tatec4a07d12012-04-06 14:19:13 -07001168 } else {
1169 // should never happen
Dianne Hackborn81038902012-11-26 17:04:09 -08001170 mLog.w("Alarm wakelock still held but sent queue empty");
Christopher Tatec4a07d12012-04-06 14:19:13 -07001171 mWakeLock.setWorkSource(null);
1172 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 }
1174 }
1175 }
1176 }
1177}