blob: bc0656132324c44a991d46b20ef96bfd13cdfb2b [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;
56import java.util.Iterator;
57import 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 Tateb8849c12011-02-08 13:39:01 -080072
73 // Alignment quantum for inexact repeating alarms
74 private static final long QUANTUM = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
75
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 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;
Dianne Hackborn81038902012-11-26 17:04:09 -080086
87 private final LocalLog mLog = new LocalLog(TAG);
88
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 private int mDescriptor;
98 private int mBroadcastRefCount = 0;
99 private PowerManager.WakeLock mWakeLock;
Dianne Hackborn81038902012-11-26 17:04:09 -0800100 private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 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;
Dianne Hackborn81038902012-11-26 17:04:09 -0800108
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
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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800130
131 private static final class FilterStats {
132 final BroadcastStats mBroadcastStats;
133 final Pair<String, ComponentName> mTarget;
134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 long aggregateTime;
Dianne Hackborn81038902012-11-26 17:04:09 -0800136 int count;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 int numWakeup;
138 long startTime;
139 int nesting;
Dianne Hackborn81038902012-11-26 17:04:09 -0800140
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
158 BroadcastStats(String packageName) {
159 mPackageName = packageName;
160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 }
162
163 private final HashMap<String, BroadcastStats> mBroadcastStats
164 = new HashMap<String, BroadcastStats>();
165
166 public AlarmManagerService(Context context) {
167 mContext = context;
168 mDescriptor = init();
Robert CH Chou64ba8e42009-11-04 21:38:49 +0800169
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
178 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
179
Dianne Hackborndb5aca92012-10-26 13:39:41 -0700180 mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 new Intent(Intent.ACTION_TIME_TICK).addFlags(
Dianne Hackborndb5aca92012-10-26 13:39:41 -0700182 Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0,
183 UserHandle.ALL);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800184 Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
185 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborndb5aca92012-10-26 13:39:41 -0700186 mDateChangeSender = PendingIntent.getBroadcastAsUser(context, 0, intent,
187 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188
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 {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800198 Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 }
200 }
201
202 protected void finalize() throws Throwable {
203 try {
204 close(mDescriptor);
205 } finally {
206 super.finalize();
207 }
208 }
209
210 public void set(int type, long triggerAtTime, PendingIntent operation) {
211 setRepeating(type, triggerAtTime, 0, operation);
212 }
213
214 public void setRepeating(int type, long triggerAtTime, long interval,
215 PendingIntent operation) {
216 if (operation == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800217 Slog.w(TAG, "set/setRepeating ignored because there is no intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 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
Joe Onorato8a9b2202010-02-26 18:56:32 -0800230 if (localLOGV) Slog.v(TAG, "set: " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231
232 int index = addAlarmLocked(alarm);
233 if (index == 0) {
234 setLocked(alarm);
235 }
236 }
237 }
238
239 public void setInexactRepeating(int type, long triggerAtTime, long interval,
240 PendingIntent operation) {
241 if (operation == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800242 Slog.w(TAG, "setInexactRepeating ignored because there is no intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 return;
244 }
245
Christopher Tateb8849c12011-02-08 13:39:01 -0800246 if (interval <= 0) {
247 Slog.w(TAG, "setInexactRepeating ignored because interval " + interval
248 + " is invalid");
249 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 }
Christopher Tateb8849c12011-02-08 13:39:01 -0800251
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");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 setRepeating(type, triggerAtTime, interval, operation);
256 return;
257 }
258
Christopher Tateb8849c12011-02-08 13:39:01 -0800259 // 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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 } else {
Christopher Tateb8849c12011-02-08 13:39:01 -0800273 adjustedTriggerTime = triggerAtTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 }
275
Christopher Tateb8849c12011-02-08 13:39:01 -0800276 // 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 }
281
Dan Egnor97e44942010-02-04 20:27:47 -0800282 public void setTime(long millis) {
283 mContext.enforceCallingOrSelfPermission(
284 "android.permission.SET_TIME",
285 "setTime");
286
287 SystemClock.setCurrentTimeMillis(millis);
288 }
289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 public void setTimeZone(String tz) {
291 mContext.enforceCallingOrSelfPermission(
292 "android.permission.SET_TIME_ZONE",
293 "setTimeZone");
294
Christopher Tate89779822012-08-31 14:40:03 -0700295 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311
Christopher Tate89779822012-08-31 14:40:03 -0700312 // 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 }
329 }
330
331 public void remove(PendingIntent operation) {
332 if (operation == null) {
333 return;
334 }
335 synchronized (mLock) {
336 removeLocked(operation);
337 }
338 }
339
340 public void removeLocked(PendingIntent operation) {
341 removeLocked(mRtcWakeupAlarms, operation);
342 removeLocked(mRtcAlarms, operation);
343 removeLocked(mElapsedRealtimeWakeupAlarms, operation);
344 removeLocked(mElapsedRealtimeAlarms, operation);
345 }
346
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
Dianne Hackborn390517b2013-05-30 15:03:32 -0700354 for (int i=0; i<alarmList.size(); i++) {
355 Alarm alarm = alarmList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 if (alarm.operation.equals(operation)) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700357 alarmList.remove(i);
358 i--;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 }
360 }
361 }
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 public void removeLocked(String packageName) {
364 removeLocked(mRtcWakeupAlarms, packageName);
365 removeLocked(mRtcAlarms, packageName);
366 removeLocked(mElapsedRealtimeWakeupAlarms, packageName);
367 removeLocked(mElapsedRealtimeAlarms, packageName);
368 }
369
370 private void removeLocked(ArrayList<Alarm> alarmList,
371 String packageName) {
372 if (alarmList.size() <= 0) {
373 return;
374 }
375
376 // iterator over the list removing any it where the intent match
Dianne Hackborn390517b2013-05-30 15:03:32 -0700377 for (int i=0; i<alarmList.size(); i++) {
378 Alarm alarm = alarmList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 if (alarm.operation.getTargetPackage().equals(packageName)) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700380 alarmList.remove(i);
381 i--;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 }
383 }
384 }
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700385
386 public void removeUserLocked(int userHandle) {
387 removeUserLocked(mRtcWakeupAlarms, userHandle);
388 removeUserLocked(mRtcAlarms, userHandle);
389 removeUserLocked(mElapsedRealtimeWakeupAlarms, userHandle);
390 removeUserLocked(mElapsedRealtimeAlarms, userHandle);
391 }
392
393 private void removeUserLocked(ArrayList<Alarm> alarmList, int userHandle) {
394 if (alarmList.size() <= 0) {
395 return;
396 }
397
398 // iterator over the list removing any it where the intent match
Dianne Hackborn390517b2013-05-30 15:03:32 -0700399 for (int i=0; i<alarmList.size(); i++) {
400 Alarm alarm = alarmList.get(i);
Dianne Hackborn8832c182012-09-17 17:20:24 -0700401 if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700402 alarmList.remove(i);
403 i--;
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700404 }
405 }
406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800408 public boolean lookForPackageLocked(String packageName) {
409 return lookForPackageLocked(mRtcWakeupAlarms, packageName)
410 || lookForPackageLocked(mRtcAlarms, packageName)
411 || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName)
412 || lookForPackageLocked(mElapsedRealtimeAlarms, packageName);
413 }
414
415 private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) {
416 for (int i=alarmList.size()-1; i>=0; i--) {
417 if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) {
418 return true;
419 }
420 }
421 return false;
422 }
423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 private ArrayList<Alarm> getAlarmList(int type) {
425 switch (type) {
426 case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms;
427 case AlarmManager.RTC: return mRtcAlarms;
428 case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms;
429 case AlarmManager.ELAPSED_REALTIME: return mElapsedRealtimeAlarms;
430 }
431
432 return null;
433 }
434
435 private int addAlarmLocked(Alarm alarm) {
436 ArrayList<Alarm> alarmList = getAlarmList(alarm.type);
437
438 int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder);
439 if (index < 0) {
440 index = 0 - index - 1;
441 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800442 if (localLOGV) Slog.v(TAG, "Adding alarm " + alarm + " at " + index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 alarmList.add(index, alarm);
444
445 if (localLOGV) {
446 // Display the list of alarms for this alarm type
Joe Onorato8a9b2202010-02-26 18:56:32 -0800447 Slog.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 int position = 0;
449 for (Alarm a : alarmList) {
450 Time time = new Time();
451 time.set(a.when);
452 String timeStr = time.format("%b %d %I:%M:%S %p");
Joe Onorato8a9b2202010-02-26 18:56:32 -0800453 Slog.v(TAG, position + ": " + timeStr
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 + " " + a.operation.getTargetPackage());
455 position += 1;
456 }
457 }
458
459 return index;
460 }
461
462 public long timeToNextAlarm() {
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700463 long nextAlarm = Long.MAX_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 synchronized (mLock) {
465 for (int i=AlarmManager.RTC_WAKEUP;
466 i<=AlarmManager.ELAPSED_REALTIME; i++) {
467 ArrayList<Alarm> alarmList = getAlarmList(i);
468 if (alarmList.size() > 0) {
469 Alarm a = alarmList.get(0);
470 if (a.when < nextAlarm) {
471 nextAlarm = a.when;
472 }
473 }
474 }
475 }
476 return nextAlarm;
477 }
478
479 private void setLocked(Alarm alarm)
480 {
481 if (mDescriptor != -1)
482 {
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700483 // The kernel never triggers alarms with negative wakeup times
484 // so we ensure they are positive.
485 long alarmSeconds, alarmNanoseconds;
486 if (alarm.when < 0) {
487 alarmSeconds = 0;
488 alarmNanoseconds = 0;
489 } else {
490 alarmSeconds = alarm.when / 1000;
491 alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000;
492 }
493
494 set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 }
496 else
497 {
498 Message msg = Message.obtain();
499 msg.what = ALARM_EVENT;
500
501 mHandler.removeMessages(ALARM_EVENT);
502 mHandler.sendMessageAtTime(msg, alarm.when);
503 }
504 }
505
506 @Override
507 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
508 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
509 != PackageManager.PERMISSION_GRANTED) {
510 pw.println("Permission Denial: can't dump AlarmManager from from pid="
511 + Binder.getCallingPid()
512 + ", uid=" + Binder.getCallingUid());
513 return;
514 }
515
516 synchronized (mLock) {
517 pw.println("Current Alarm Manager state:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700518 if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700519 final long now = System.currentTimeMillis();
520 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700522 pw.print(" Realtime wakeup (now=");
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700523 pw.print(sdf.format(new Date(now))); pw.println("):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700524 if (mRtcWakeupAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700525 dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700526 }
527 if (mRtcAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700528 dumpAlarmList(pw, mRtcAlarms, " ", "RTC", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700531 if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700532 final long now = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 pw.println(" ");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700534 pw.print(" Elapsed realtime wakeup (now=");
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700535 TimeUtils.formatDuration(now, pw); pw.println("):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700536 if (mElapsedRealtimeWakeupAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700537 dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700538 }
539 if (mElapsedRealtimeAlarms.size() > 0) {
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700540 dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800543
544 pw.println();
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700545 pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
Dianne Hackborn81038902012-11-26 17:04:09 -0800546 pw.println();
547
548 if (mLog.dump(pw, " Recent problems", " ")) {
549 pw.println();
550 }
551
552 final FilterStats[] topFilters = new FilterStats[10];
553 final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
554 @Override
555 public int compare(FilterStats lhs, FilterStats rhs) {
556 if (lhs.aggregateTime < rhs.aggregateTime) {
557 return 1;
558 } else if (lhs.aggregateTime > rhs.aggregateTime) {
559 return -1;
560 }
561 return 0;
562 }
563 };
564 int len = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
566 BroadcastStats bs = be.getValue();
Dianne Hackborn81038902012-11-26 17:04:09 -0800567 for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 : bs.filterStats.entrySet()) {
Dianne Hackborn81038902012-11-26 17:04:09 -0800569 FilterStats fs = fe.getValue();
570 int pos = len > 0
571 ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
572 if (pos < 0) {
573 pos = -pos - 1;
574 }
575 if (pos < topFilters.length) {
576 int copylen = topFilters.length - pos - 1;
577 if (copylen > 0) {
578 System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
579 }
580 topFilters[pos] = fs;
581 if (len < topFilters.length) {
582 len++;
583 }
584 }
585 }
586 }
587 if (len > 0) {
588 pw.println(" Top Alarms:");
589 for (int i=0; i<len; i++) {
590 FilterStats fs = topFilters[i];
591 pw.print(" ");
592 if (fs.nesting > 0) pw.print("*ACTIVE* ");
593 TimeUtils.formatDuration(fs.aggregateTime, pw);
594 pw.print(" running, "); pw.print(fs.numWakeup);
595 pw.print(" wakeups, "); pw.print(fs.count);
596 pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
597 pw.println();
598 pw.print(" ");
599 if (fs.mTarget.first != null) {
600 pw.print(" act="); pw.print(fs.mTarget.first);
601 }
602 if (fs.mTarget.second != null) {
603 pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
604 }
605 pw.println();
606 }
607 }
608
609 pw.println(" ");
610 pw.println(" Alarm Stats:");
611 final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
612 for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
613 BroadcastStats bs = be.getValue();
614 pw.print(" ");
615 if (bs.nesting > 0) pw.print("*ACTIVE* ");
616 pw.print(be.getKey());
617 pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
618 pw.print(" running, "); pw.print(bs.numWakeup);
619 pw.println(" wakeups:");
620 tmpFilters.clear();
621 for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
622 : bs.filterStats.entrySet()) {
623 tmpFilters.add(fe.getValue());
624 }
625 Collections.sort(tmpFilters, comparator);
626 for (int i=0; i<tmpFilters.size(); i++) {
627 FilterStats fs = tmpFilters.get(i);
628 pw.print(" ");
629 if (fs.nesting > 0) pw.print("*ACTIVE* ");
630 TimeUtils.formatDuration(fs.aggregateTime, pw);
631 pw.print(" "); pw.print(fs.numWakeup);
632 pw.print(" wakes " ); pw.print(fs.count);
633 pw.print(" alarms:");
634 if (fs.mTarget.first != null) {
635 pw.print(" act="); pw.print(fs.mTarget.first);
636 }
637 if (fs.mTarget.second != null) {
638 pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
639 }
640 pw.println();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 }
642 }
643 }
644 }
645
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700646 private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
647 String prefix, String label, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 for (int i=list.size()-1; i>=0; i--) {
649 Alarm a = list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700650 pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
651 pw.print(": "); pw.println(a);
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700652 a.dump(pw, prefix + " ", now);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654 }
655
656 private native int init();
657 private native void close(int fd);
Jeff Brown11c5f1a2010-03-31 15:29:40 -0700658 private native void set(int fd, int type, long seconds, long nanoseconds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 private native int waitForAlarm(int fd);
660 private native int setKernelTimezone(int fd, int minuteswest);
661
662 private void triggerAlarmsLocked(ArrayList<Alarm> alarmList,
663 ArrayList<Alarm> triggerList,
664 long now)
665 {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700666 ArrayList<Alarm> repeats = null;
667
668 for (int i=0; i<alarmList.size(); i++) {
669 Alarm alarm = alarmList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670
Joe Onorato8a9b2202010-02-26 18:56:32 -0800671 if (localLOGV) Slog.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672
673 if (alarm.when > now) {
674 // don't fire alarms in the future
675 break;
676 }
677
678 // If the alarm is late, then print a warning message.
679 // Note that this can happen if the user creates a new event on
680 // the Calendar app with a reminder that is in the past. In that
681 // case, the reminder alarm will fire immediately.
682 if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800683 Slog.v(TAG, "alarm is late! alarm time: " + alarm.when
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 + " now: " + now + " delay (in seconds): "
685 + (now - alarm.when) / 1000);
686 }
687
688 // Recurring alarms may have passed several alarm intervals while the
689 // phone was asleep or off, so pass a trigger count when sending them.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800690 if (localLOGV) Slog.v(TAG, "Alarm triggering: " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 alarm.count = 1;
692 if (alarm.repeatInterval > 0) {
693 // this adjustment will be zero if we're late by
694 // less than one full repeat interval
695 alarm.count += (now - alarm.when) / alarm.repeatInterval;
696 }
697 triggerList.add(alarm);
698
699 // remove the alarm from the list
Dianne Hackborn390517b2013-05-30 15:03:32 -0700700 alarmList.remove(i);
701 i--;
702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 // if it repeats queue it up to be read-added to the list
704 if (alarm.repeatInterval > 0) {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700705 if (repeats == null) {
706 repeats = new ArrayList<Alarm>();
707 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 repeats.add(alarm);
709 }
710 }
711
712 // reset any repeating alarms.
Dianne Hackborn390517b2013-05-30 15:03:32 -0700713 if (repeats != null) {
714 for (int i=0; i<repeats.size(); i++) {
715 Alarm alarm = repeats.get(i);
716 alarm.when += alarm.count * alarm.repeatInterval;
717 addAlarmLocked(alarm);
718 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 }
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> {
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
750 public Alarm() {
751 when = 0;
752 repeatInterval = 0;
753 operation = null;
754 }
755
756 @Override
757 public String toString()
758 {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700759 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();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 }
769
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700770 public void dump(PrintWriter pw, String prefix, long now) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700771 pw.print(prefix); pw.print("type="); pw.print(type);
Dianne Hackborn043fcd92010-10-06 14:27:34 -0700772 pw.print(" when="); TimeUtils.formatDuration(when, now, pw);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700773 pw.print(" repeatInterval="); pw.print(repeatInterval);
774 pw.print(" count="); pw.println(count);
775 pw.print(prefix); pw.print("operation="); pw.println(operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 }
777 }
778
779 private class AlarmThread extends Thread
780 {
781 public AlarmThread()
782 {
783 super("AlarmManager");
784 }
785
786 public void run()
787 {
Dianne Hackborn390517b2013-05-30 15:03:32 -0700788 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 while (true)
791 {
792 int result = waitForAlarm(mDescriptor);
Dianne Hackborn390517b2013-05-30 15:03:32 -0700793
794 triggerList.clear();
795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 if ((result & TIME_CHANGED_MASK) != 0) {
797 remove(mTimeTickSender);
798 mClockReceiver.scheduleTimeTickEvent();
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800799 Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
Dianne Hackborn89ba6752011-01-23 16:51:16 -0800800 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
801 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700802 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 }
804
805 synchronized (mLock) {
806 final long nowRTC = System.currentTimeMillis();
807 final long nowELAPSED = SystemClock.elapsedRealtime();
Joe Onorato8a9b2202010-02-26 18:56:32 -0800808 if (localLOGV) Slog.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 TAG, "Checking for alarms... rtc=" + nowRTC
810 + ", elapsed=" + nowELAPSED);
811
812 if ((result & RTC_WAKEUP_MASK) != 0)
813 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
814
815 if ((result & RTC_MASK) != 0)
816 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
817
818 if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0)
819 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED);
820
821 if ((result & ELAPSED_REALTIME_MASK) != 0)
822 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED);
823
824 // now trigger the alarms
Dianne Hackborn390517b2013-05-30 15:03:32 -0700825 for (int i=0; i<triggerList.size(); i++) {
826 Alarm alarm = triggerList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800828 if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 alarm.operation.send(mContext, 0,
830 mBackgroundIntent.putExtra(
831 Intent.EXTRA_ALARM_COUNT, alarm.count),
832 mResultReceiver, mHandler);
833
Christopher Tatec4a07d12012-04-06 14:19:13 -0700834 // we have an active broadcast so stay awake.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 if (mBroadcastRefCount == 0) {
Christopher Tatec4a07d12012-04-06 14:19:13 -0700836 setWakelockWorkSource(alarm.operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 mWakeLock.acquire();
838 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800839 final InFlight inflight = new InFlight(AlarmManagerService.this,
840 alarm.operation);
841 mInFlight.add(inflight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 mBroadcastRefCount++;
Dianne Hackborn81038902012-11-26 17:04:09 -0800843
844 final BroadcastStats bs = inflight.mBroadcastStats;
845 bs.count++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 if (bs.nesting == 0) {
Dianne Hackborn81038902012-11-26 17:04:09 -0800847 bs.nesting = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 bs.startTime = nowELAPSED;
849 } else {
850 bs.nesting++;
851 }
Dianne Hackborn81038902012-11-26 17:04:09 -0800852 final FilterStats fs = inflight.mFilterStats;
853 fs.count++;
854 if (fs.nesting == 0) {
855 fs.nesting = 1;
856 fs.startTime = nowELAPSED;
857 } else {
858 fs.nesting++;
859 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP
861 || alarm.type == AlarmManager.RTC_WAKEUP) {
862 bs.numWakeup++;
Dianne Hackborn81038902012-11-26 17:04:09 -0800863 fs.numWakeup++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 ActivityManagerNative.noteWakeupAlarm(
865 alarm.operation);
866 }
867 } catch (PendingIntent.CanceledException e) {
868 if (alarm.repeatInterval > 0) {
869 // This IntentSender is no longer valid, but this
870 // is a repeating alarm, so toss the hoser.
871 remove(alarm.operation);
872 }
873 } catch (RuntimeException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800874 Slog.w(TAG, "Failure sending alarm.", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 }
876 }
877 }
878 }
879 }
880 }
Christopher Tatec4a07d12012-04-06 14:19:13 -0700881
882 void setWakelockWorkSource(PendingIntent pi) {
883 try {
884 final int uid = ActivityManagerNative.getDefault()
885 .getUidForIntentSender(pi.getTarget());
886 if (uid >= 0) {
887 mWakeLock.setWorkSource(new WorkSource(uid));
888 return;
889 }
890 } catch (Exception e) {
891 }
892
893 // Something went wrong; fall back to attributing the lock to the OS
894 mWakeLock.setWorkSource(null);
895 }
896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 private class AlarmHandler extends Handler {
898 public static final int ALARM_EVENT = 1;
899 public static final int MINUTE_CHANGE_EVENT = 2;
900 public static final int DATE_CHANGE_EVENT = 3;
901
902 public AlarmHandler() {
903 }
904
905 public void handleMessage(Message msg) {
906 if (msg.what == ALARM_EVENT) {
907 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
908 synchronized (mLock) {
909 final long nowRTC = System.currentTimeMillis();
910 triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
911 triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
912 triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC);
913 triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC);
914 }
915
916 // now trigger the alarms without the lock held
Dianne Hackborn390517b2013-05-30 15:03:32 -0700917 for (int i=0; i<triggerList.size(); i++) {
918 Alarm alarm = triggerList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 try {
920 alarm.operation.send();
921 } catch (PendingIntent.CanceledException e) {
922 if (alarm.repeatInterval > 0) {
923 // This IntentSender is no longer valid, but this
924 // is a repeating alarm, so toss the hoser.
925 remove(alarm.operation);
926 }
927 }
928 }
929 }
930 }
931 }
932
933 class ClockReceiver extends BroadcastReceiver {
934 public ClockReceiver() {
935 IntentFilter filter = new IntentFilter();
936 filter.addAction(Intent.ACTION_TIME_TICK);
937 filter.addAction(Intent.ACTION_DATE_CHANGED);
938 mContext.registerReceiver(this, filter);
939 }
940
941 @Override
942 public void onReceive(Context context, Intent intent) {
943 if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
944 scheduleTimeTickEvent();
945 } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
946 // Since the kernel does not keep track of DST, we need to
947 // reset the TZ information at the beginning of each day
948 // based off of the current Zone gmt offset + userspace tracked
949 // daylight savings information.
950 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
Lavettacn Xiaoc84cc4f2010-08-30 12:47:23 +0200951 int gmtOffset = zone.getOffset(System.currentTimeMillis());
952 setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 scheduleDateChangedEvent();
954 }
955 }
956
957 public void scheduleTimeTickEvent() {
Paul Westbrook51608a52011-08-25 13:18:54 -0700958 final long currentTime = System.currentTimeMillis();
Sungmin Choi563914a2013-01-10 17:28:40 +0900959 final long nextTime = 60000 * ((currentTime / 60000) + 1);
Paul Westbrook51608a52011-08-25 13:18:54 -0700960
961 // Schedule this event for the amount of time that it would take to get to
962 // the top of the next minute.
Sungmin Choi563914a2013-01-10 17:28:40 +0900963 final long tickEventDelay = nextTime - currentTime;
Paul Westbrook51608a52011-08-25 13:18:54 -0700964
965 set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay,
966 mTimeTickSender);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 }
968
969 public void scheduleDateChangedEvent() {
970 Calendar calendar = Calendar.getInstance();
971 calendar.setTimeInMillis(System.currentTimeMillis());
972 calendar.set(Calendar.HOUR, 0);
973 calendar.set(Calendar.MINUTE, 0);
974 calendar.set(Calendar.SECOND, 0);
975 calendar.set(Calendar.MILLISECOND, 0);
976 calendar.add(Calendar.DAY_OF_MONTH, 1);
977
978 set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender);
979 }
980 }
981
982 class UninstallReceiver extends BroadcastReceiver {
983 public UninstallReceiver() {
984 IntentFilter filter = new IntentFilter();
985 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
986 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800987 filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 filter.addDataScheme("package");
989 mContext.registerReceiver(this, filter);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800990 // Register for events related to sdcard installation.
991 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800992 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700993 sdFilter.addAction(Intent.ACTION_USER_STOPPED);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800994 mContext.registerReceiver(this, sdFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
996
997 @Override
998 public void onReceive(Context context, Intent intent) {
999 synchronized (mLock) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001000 String action = intent.getAction();
1001 String pkgList[] = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001002 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
1003 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
1004 for (String packageName : pkgList) {
1005 if (lookForPackageLocked(packageName)) {
1006 setResultCode(Activity.RESULT_OK);
1007 return;
1008 }
1009 }
1010 return;
1011 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001012 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001013 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
1014 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1015 if (userHandle >= 0) {
1016 removeUserLocked(userHandle);
1017 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001018 } else {
Dianne Hackborn409578f2010-03-10 17:23:43 -08001019 if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
1020 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1021 // This package is being updated; don't kill its alarms.
1022 return;
1023 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001024 Uri data = intent.getData();
1025 if (data != null) {
1026 String pkg = data.getSchemeSpecificPart();
1027 if (pkg != null) {
1028 pkgList = new String[]{pkg};
1029 }
1030 }
1031 }
1032 if (pkgList != null && (pkgList.length > 0)) {
1033 for (String pkg : pkgList) {
1034 removeLocked(pkg);
1035 mBroadcastStats.remove(pkg);
1036 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 }
1038 }
1039 }
1040 }
1041
1042 private final BroadcastStats getStatsLocked(PendingIntent pi) {
1043 String pkg = pi.getTargetPackage();
1044 BroadcastStats bs = mBroadcastStats.get(pkg);
1045 if (bs == null) {
Dianne Hackborn81038902012-11-26 17:04:09 -08001046 bs = new BroadcastStats(pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 mBroadcastStats.put(pkg, bs);
1048 }
1049 return bs;
1050 }
Dianne Hackborn81038902012-11-26 17:04:09 -08001051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 class ResultReceiver implements PendingIntent.OnFinished {
1053 public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
1054 String resultData, Bundle resultExtras) {
1055 synchronized (mLock) {
Dianne Hackborn81038902012-11-26 17:04:09 -08001056 InFlight inflight = null;
1057 for (int i=0; i<mInFlight.size(); i++) {
1058 if (mInFlight.get(i).mPendingIntent == pi) {
1059 inflight = mInFlight.remove(i);
1060 break;
1061 }
1062 }
1063 if (inflight != null) {
1064 final long nowELAPSED = SystemClock.elapsedRealtime();
1065 BroadcastStats bs = inflight.mBroadcastStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 bs.nesting--;
1067 if (bs.nesting <= 0) {
1068 bs.nesting = 0;
Dianne Hackborn81038902012-11-26 17:04:09 -08001069 bs.aggregateTime += nowELAPSED - bs.startTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 }
Dianne Hackborn81038902012-11-26 17:04:09 -08001071 FilterStats fs = inflight.mFilterStats;
1072 fs.nesting--;
1073 if (fs.nesting <= 0) {
1074 fs.nesting = 0;
1075 fs.aggregateTime += nowELAPSED - fs.startTime;
1076 }
1077 } else {
1078 mLog.w("No in-flight alarm for " + pi + " " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 }
1080 mBroadcastRefCount--;
1081 if (mBroadcastRefCount == 0) {
1082 mWakeLock.release();
Dianne Hackborn81038902012-11-26 17:04:09 -08001083 if (mInFlight.size() > 0) {
1084 mLog.w("Finished all broadcasts with " + mInFlight.size()
1085 + " remaining inflights");
1086 for (int i=0; i<mInFlight.size(); i++) {
1087 mLog.w(" Remaining #" + i + ": " + mInFlight.get(i));
1088 }
1089 mInFlight.clear();
1090 }
Christopher Tatec4a07d12012-04-06 14:19:13 -07001091 } else {
1092 // the next of our alarms is now in flight. reattribute the wakelock.
Dianne Hackborn81038902012-11-26 17:04:09 -08001093 if (mInFlight.size() > 0) {
1094 setWakelockWorkSource(mInFlight.get(0).mPendingIntent);
Christopher Tatec4a07d12012-04-06 14:19:13 -07001095 } else {
1096 // should never happen
Dianne Hackborn81038902012-11-26 17:04:09 -08001097 mLog.w("Alarm wakelock still held but sent queue empty");
Christopher Tatec4a07d12012-04-06 14:19:13 -07001098 mWakeLock.setWorkSource(null);
1099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 }
1101 }
1102 }
1103 }
1104}