• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server;
18 
19 import android.app.ActivityManagerNative;
20 import android.app.AlarmManager;
21 import android.app.IAlarmManager;
22 import android.app.PendingIntent;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.pm.PackageManager;
28 import android.net.Uri;
29 import android.os.Binder;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.os.Message;
33 import android.os.PowerManager;
34 import android.os.SystemClock;
35 import android.os.SystemProperties;
36 import android.text.TextUtils;
37 import android.text.format.Time;
38 import android.util.EventLog;
39 import android.util.Log;
40 
41 import java.io.FileDescriptor;
42 import java.io.PrintWriter;
43 import java.util.ArrayList;
44 import java.util.Calendar;
45 import java.util.Collections;
46 import java.util.Comparator;
47 import java.util.HashMap;
48 import java.util.Iterator;
49 import java.util.Map;
50 import java.util.TimeZone;
51 
52 class AlarmManagerService extends IAlarmManager.Stub {
53     // The threshold for how long an alarm can be late before we print a
54     // warning message.  The time duration is in milliseconds.
55     private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
56 
57     private static final int RTC_WAKEUP_MASK = 1 << AlarmManager.RTC_WAKEUP;
58     private static final int RTC_MASK = 1 << AlarmManager.RTC;
59     private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << AlarmManager.ELAPSED_REALTIME_WAKEUP;
60     private static final int ELAPSED_REALTIME_MASK = 1 << AlarmManager.ELAPSED_REALTIME;
61     private static final int TIME_CHANGED_MASK = 1 << 16;
62 
63     private static final String TAG = "AlarmManager";
64     private static final String ClockReceiver_TAG = "ClockReceiver";
65     private static final boolean localLOGV = false;
66     private static final int ALARM_EVENT = 1;
67     private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
68 
69     private static final Intent mBackgroundIntent
70             = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
71 
72     private final Context mContext;
73 
74     private Object mLock = new Object();
75 
76     private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>();
77     private final ArrayList<Alarm> mRtcAlarms = new ArrayList<Alarm>();
78     private final ArrayList<Alarm> mElapsedRealtimeWakeupAlarms = new ArrayList<Alarm>();
79     private final ArrayList<Alarm> mElapsedRealtimeAlarms = new ArrayList<Alarm>();
80     private final IncreasingTimeOrder mIncreasingTimeOrder = new IncreasingTimeOrder();
81 
82     // slots corresponding with the inexact-repeat interval buckets,
83     // ordered from shortest to longest
84     private static final long sInexactSlotIntervals[] = {
85         AlarmManager.INTERVAL_FIFTEEN_MINUTES,
86         AlarmManager.INTERVAL_HALF_HOUR,
87         AlarmManager.INTERVAL_HOUR,
88         AlarmManager.INTERVAL_HALF_DAY,
89         AlarmManager.INTERVAL_DAY
90     };
91     private long mInexactDeliveryTimes[] = { 0, 0, 0, 0, 0};
92 
93     private int mDescriptor;
94     private int mBroadcastRefCount = 0;
95     private PowerManager.WakeLock mWakeLock;
96     private final AlarmThread mWaitThread = new AlarmThread();
97     private final AlarmHandler mHandler = new AlarmHandler();
98     private ClockReceiver mClockReceiver;
99     private UninstallReceiver mUninstallReceiver;
100     private final ResultReceiver mResultReceiver = new ResultReceiver();
101     private final PendingIntent mTimeTickSender;
102     private final PendingIntent mDateChangeSender;
103 
104     private static final class FilterStats {
105         int count;
106     }
107 
108     private static final class BroadcastStats {
109         long aggregateTime;
110         int numWakeup;
111         long startTime;
112         int nesting;
113         HashMap<Intent.FilterComparison, FilterStats> filterStats
114                 = new HashMap<Intent.FilterComparison, FilterStats>();
115     }
116 
117     private final HashMap<String, BroadcastStats> mBroadcastStats
118             = new HashMap<String, BroadcastStats>();
119 
AlarmManagerService(Context context)120     public AlarmManagerService(Context context) {
121         mContext = context;
122         mDescriptor = init();
123         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
124         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
125 
126         mTimeTickSender = PendingIntent.getBroadcast(context, 0,
127                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
128                         Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0);
129         mDateChangeSender = PendingIntent.getBroadcast(context, 0,
130                 new Intent(Intent.ACTION_DATE_CHANGED), 0);
131 
132         // now that we have initied the driver schedule the alarm
133         mClockReceiver= new ClockReceiver();
134         mClockReceiver.scheduleTimeTickEvent();
135         mClockReceiver.scheduleDateChangedEvent();
136         mUninstallReceiver = new UninstallReceiver();
137 
138         if (mDescriptor != -1) {
139             mWaitThread.start();
140         } else {
141             Log.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
142         }
143     }
144 
finalize()145     protected void finalize() throws Throwable {
146         try {
147             close(mDescriptor);
148         } finally {
149             super.finalize();
150         }
151     }
152 
set(int type, long triggerAtTime, PendingIntent operation)153     public void set(int type, long triggerAtTime, PendingIntent operation) {
154         setRepeating(type, triggerAtTime, 0, operation);
155     }
156 
setRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)157     public void setRepeating(int type, long triggerAtTime, long interval,
158             PendingIntent operation) {
159         if (operation == null) {
160             Log.w(TAG, "set/setRepeating ignored because there is no intent");
161             return;
162         }
163         synchronized (mLock) {
164             Alarm alarm = new Alarm();
165             alarm.type = type;
166             alarm.when = triggerAtTime;
167             alarm.repeatInterval = interval;
168             alarm.operation = operation;
169 
170             // Remove this alarm if already scheduled.
171             removeLocked(operation);
172 
173             if (localLOGV) Log.v(TAG, "set: " + alarm);
174 
175             int index = addAlarmLocked(alarm);
176             if (index == 0) {
177                 setLocked(alarm);
178             }
179         }
180     }
181 
setInexactRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)182     public void setInexactRepeating(int type, long triggerAtTime, long interval,
183             PendingIntent operation) {
184         if (operation == null) {
185             Log.w(TAG, "setInexactRepeating ignored because there is no intent");
186             return;
187         }
188 
189         // find the slot in the delivery-times array that we will use
190         int intervalSlot;
191         for (intervalSlot = 0; intervalSlot < sInexactSlotIntervals.length; intervalSlot++) {
192             if (sInexactSlotIntervals[intervalSlot] == interval) {
193                 break;
194             }
195         }
196 
197         // Non-bucket intervals just fall back to the less-efficient
198         // unbucketed recurring alarm implementation
199         if (intervalSlot >= sInexactSlotIntervals.length) {
200             setRepeating(type, triggerAtTime, interval, operation);
201             return;
202         }
203 
204         // Align bucketed alarm deliveries by trying to match
205         // the shortest-interval bucket already scheduled
206         long bucketTime = 0;
207         for (int slot = 0; slot < mInexactDeliveryTimes.length; slot++) {
208             if (mInexactDeliveryTimes[slot] > 0) {
209                 bucketTime = mInexactDeliveryTimes[slot];
210                 break;
211             }
212         }
213 
214         if (bucketTime == 0) {
215             // If nothing is scheduled yet, just start at the requested time
216             bucketTime = triggerAtTime;
217         } else {
218             // Align the new alarm with the existing bucketed sequence.  To achieve
219             // alignment, we slide the start time around by min{interval, slot interval}
220             long adjustment = (interval <= sInexactSlotIntervals[intervalSlot])
221                     ? interval : sInexactSlotIntervals[intervalSlot];
222 
223             // The bucket may have started in the past; adjust
224             while (bucketTime < triggerAtTime) {
225                 bucketTime += adjustment;
226             }
227 
228             // Or the bucket may be set to start more than an interval beyond
229             // our requested trigger time; pull it back to meet our needs
230             while (bucketTime > triggerAtTime + adjustment) {
231                 bucketTime -= adjustment;
232             }
233         }
234 
235         // Remember where this bucket started (reducing the amount of later
236         // fixup required) and set the alarm with the new, bucketed start time.
237         if (localLOGV) Log.v(TAG, "setInexactRepeating: interval=" + interval
238                 + " bucketTime=" + bucketTime);
239         mInexactDeliveryTimes[intervalSlot] = bucketTime;
240         setRepeating(type, bucketTime, interval, operation);
241     }
242 
setTimeZone(String tz)243     public void setTimeZone(String tz) {
244         mContext.enforceCallingOrSelfPermission(
245                 "android.permission.SET_TIME_ZONE",
246                 "setTimeZone");
247 
248         if (TextUtils.isEmpty(tz)) return;
249         TimeZone zone = TimeZone.getTimeZone(tz);
250         // Prevent reentrant calls from stepping on each other when writing
251         // the time zone property
252         boolean timeZoneWasChanged = false;
253         synchronized (this) {
254             String current = SystemProperties.get(TIMEZONE_PROPERTY);
255             if (current == null || !current.equals(zone.getID())) {
256                 if (localLOGV) Log.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
257                 timeZoneWasChanged = true;
258                 SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
259             }
260 
261             // Update the kernel timezone information
262             // Kernel tracks time offsets as 'minutes west of GMT'
263             int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000;
264             setKernelTimezone(mDescriptor, -(gmtOffset));
265         }
266 
267         TimeZone.setDefault(null);
268 
269         if (timeZoneWasChanged) {
270             Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
271             intent.putExtra("time-zone", zone.getID());
272             mContext.sendBroadcast(intent);
273         }
274     }
275 
remove(PendingIntent operation)276     public void remove(PendingIntent operation) {
277         if (operation == null) {
278             return;
279         }
280         synchronized (mLock) {
281             removeLocked(operation);
282         }
283     }
284 
removeLocked(PendingIntent operation)285     public void removeLocked(PendingIntent operation) {
286         removeLocked(mRtcWakeupAlarms, operation);
287         removeLocked(mRtcAlarms, operation);
288         removeLocked(mElapsedRealtimeWakeupAlarms, operation);
289         removeLocked(mElapsedRealtimeAlarms, operation);
290     }
291 
removeLocked(ArrayList<Alarm> alarmList, PendingIntent operation)292     private void removeLocked(ArrayList<Alarm> alarmList,
293             PendingIntent operation) {
294         if (alarmList.size() <= 0) {
295             return;
296         }
297 
298         // iterator over the list removing any it where the intent match
299         Iterator<Alarm> it = alarmList.iterator();
300 
301         while (it.hasNext()) {
302             Alarm alarm = it.next();
303             if (alarm.operation.equals(operation)) {
304                 it.remove();
305             }
306         }
307     }
308 
removeLocked(String packageName)309     public void removeLocked(String packageName) {
310         removeLocked(mRtcWakeupAlarms, packageName);
311         removeLocked(mRtcAlarms, packageName);
312         removeLocked(mElapsedRealtimeWakeupAlarms, packageName);
313         removeLocked(mElapsedRealtimeAlarms, packageName);
314     }
315 
removeLocked(ArrayList<Alarm> alarmList, String packageName)316     private void removeLocked(ArrayList<Alarm> alarmList,
317             String packageName) {
318         if (alarmList.size() <= 0) {
319             return;
320         }
321 
322         // iterator over the list removing any it where the intent match
323         Iterator<Alarm> it = alarmList.iterator();
324 
325         while (it.hasNext()) {
326             Alarm alarm = it.next();
327             if (alarm.operation.getTargetPackage().equals(packageName)) {
328                 it.remove();
329             }
330         }
331     }
332 
getAlarmList(int type)333     private ArrayList<Alarm> getAlarmList(int type) {
334         switch (type) {
335             case AlarmManager.RTC_WAKEUP:              return mRtcWakeupAlarms;
336             case AlarmManager.RTC:                     return mRtcAlarms;
337             case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms;
338             case AlarmManager.ELAPSED_REALTIME:        return mElapsedRealtimeAlarms;
339         }
340 
341         return null;
342     }
343 
addAlarmLocked(Alarm alarm)344     private int addAlarmLocked(Alarm alarm) {
345         ArrayList<Alarm> alarmList = getAlarmList(alarm.type);
346 
347         int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder);
348         if (index < 0) {
349             index = 0 - index - 1;
350         }
351         if (localLOGV) Log.v(TAG, "Adding alarm " + alarm + " at " + index);
352         alarmList.add(index, alarm);
353 
354         if (localLOGV) {
355             // Display the list of alarms for this alarm type
356             Log.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type);
357             int position = 0;
358             for (Alarm a : alarmList) {
359                 Time time = new Time();
360                 time.set(a.when);
361                 String timeStr = time.format("%b %d %I:%M:%S %p");
362                 Log.v(TAG, position + ": " + timeStr
363                         + " " + a.operation.getTargetPackage());
364                 position += 1;
365             }
366         }
367 
368         return index;
369     }
370 
timeToNextAlarm()371     public long timeToNextAlarm() {
372         long nextAlarm = 0xfffffffffffffffl;
373         synchronized (mLock) {
374             for (int i=AlarmManager.RTC_WAKEUP;
375                     i<=AlarmManager.ELAPSED_REALTIME; i++) {
376                 ArrayList<Alarm> alarmList = getAlarmList(i);
377                 if (alarmList.size() > 0) {
378                     Alarm a = alarmList.get(0);
379                     if (a.when < nextAlarm) {
380                         nextAlarm = a.when;
381                     }
382                 }
383             }
384         }
385         return nextAlarm;
386     }
387 
setLocked(Alarm alarm)388     private void setLocked(Alarm alarm)
389     {
390         if (mDescriptor != -1)
391         {
392             set(mDescriptor, alarm.type, (alarm.when * 1000 * 1000));
393         }
394         else
395         {
396             Message msg = Message.obtain();
397             msg.what = ALARM_EVENT;
398 
399             mHandler.removeMessages(ALARM_EVENT);
400             mHandler.sendMessageAtTime(msg, alarm.when);
401         }
402     }
403 
404     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)405     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
406         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
407                 != PackageManager.PERMISSION_GRANTED) {
408             pw.println("Permission Denial: can't dump AlarmManager from from pid="
409                     + Binder.getCallingPid()
410                     + ", uid=" + Binder.getCallingUid());
411             return;
412         }
413 
414         synchronized (mLock) {
415             pw.println("Current Alarm Manager state:");
416             if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) {
417                 pw.println(" ");
418                 pw.print("  Realtime wakeup (now=");
419                         pw.print(System.currentTimeMillis()); pw.println("):");
420                 if (mRtcWakeupAlarms.size() > 0) {
421                     dumpAlarmList(pw, mRtcWakeupAlarms, "  ", "RTC_WAKEUP");
422                 }
423                 if (mRtcAlarms.size() > 0) {
424                     dumpAlarmList(pw, mRtcAlarms, "  ", "RTC");
425                 }
426             }
427             if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) {
428                 pw.println(" ");
429                 pw.print("  Elapsed realtime wakeup (now=");
430                         pw.print(SystemClock.elapsedRealtime()); pw.println("):");
431                 if (mElapsedRealtimeWakeupAlarms.size() > 0) {
432                     dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, "  ", "ELAPSED_WAKEUP");
433                 }
434                 if (mElapsedRealtimeAlarms.size() > 0) {
435                     dumpAlarmList(pw, mElapsedRealtimeAlarms, "  ", "ELAPSED");
436                 }
437             }
438 
439             pw.println(" ");
440             pw.print("  Broadcast ref count: "); pw.println(mBroadcastRefCount);
441 
442             pw.println(" ");
443             pw.println("  Alarm Stats:");
444             for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
445                 BroadcastStats bs = be.getValue();
446                 pw.print("  "); pw.println(be.getKey());
447                 pw.print("    "); pw.print(bs.aggregateTime);
448                         pw.print("ms running, "); pw.print(bs.numWakeup);
449                         pw.println(" wakeups");
450                 for (Map.Entry<Intent.FilterComparison, FilterStats> fe
451                         : bs.filterStats.entrySet()) {
452                     pw.print("    "); pw.print(fe.getValue().count);
453                             pw.print(" alarms: ");
454                             pw.println(fe.getKey().getIntent().toShortString(true, false));
455                 }
456             }
457         }
458     }
459 
dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, String prefix, String label)460     private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, String prefix, String label) {
461         for (int i=list.size()-1; i>=0; i--) {
462             Alarm a = list.get(i);
463             pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
464                     pw.print(": "); pw.println(a);
465             a.dump(pw, prefix + "  ");
466         }
467     }
468 
init()469     private native int init();
close(int fd)470     private native void close(int fd);
set(int fd, int type, long nanoseconds)471     private native void set(int fd, int type, long nanoseconds);
waitForAlarm(int fd)472     private native int waitForAlarm(int fd);
setKernelTimezone(int fd, int minuteswest)473     private native int setKernelTimezone(int fd, int minuteswest);
474 
triggerAlarmsLocked(ArrayList<Alarm> alarmList, ArrayList<Alarm> triggerList, long now)475     private void triggerAlarmsLocked(ArrayList<Alarm> alarmList,
476                                      ArrayList<Alarm> triggerList,
477                                      long now)
478     {
479         Iterator<Alarm> it = alarmList.iterator();
480         ArrayList<Alarm> repeats = new ArrayList<Alarm>();
481 
482         while (it.hasNext())
483         {
484             Alarm alarm = it.next();
485 
486             if (localLOGV) Log.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm);
487 
488             if (alarm.when > now) {
489                 // don't fire alarms in the future
490                 break;
491             }
492 
493             // If the alarm is late, then print a warning message.
494             // Note that this can happen if the user creates a new event on
495             // the Calendar app with a reminder that is in the past. In that
496             // case, the reminder alarm will fire immediately.
497             if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) {
498                 Log.v(TAG, "alarm is late! alarm time: " + alarm.when
499                         + " now: " + now + " delay (in seconds): "
500                         + (now - alarm.when) / 1000);
501             }
502 
503             // Recurring alarms may have passed several alarm intervals while the
504             // phone was asleep or off, so pass a trigger count when sending them.
505             if (localLOGV) Log.v(TAG, "Alarm triggering: " + alarm);
506             alarm.count = 1;
507             if (alarm.repeatInterval > 0) {
508                 // this adjustment will be zero if we're late by
509                 // less than one full repeat interval
510                 alarm.count += (now - alarm.when) / alarm.repeatInterval;
511             }
512             triggerList.add(alarm);
513 
514             // remove the alarm from the list
515             it.remove();
516 
517             // if it repeats queue it up to be read-added to the list
518             if (alarm.repeatInterval > 0) {
519                 repeats.add(alarm);
520             }
521         }
522 
523         // reset any repeating alarms.
524         it = repeats.iterator();
525         while (it.hasNext()) {
526             Alarm alarm = it.next();
527             alarm.when += alarm.count * alarm.repeatInterval;
528             addAlarmLocked(alarm);
529         }
530 
531         if (alarmList.size() > 0) {
532             setLocked(alarmList.get(0));
533         }
534     }
535 
536     /**
537      * This Comparator sorts Alarms into increasing time order.
538      */
539     public static class IncreasingTimeOrder implements Comparator<Alarm> {
compare(Alarm a1, Alarm a2)540         public int compare(Alarm a1, Alarm a2) {
541             long when1 = a1.when;
542             long when2 = a2.when;
543             if (when1 - when2 > 0) {
544                 return 1;
545             }
546             if (when1 - when2 < 0) {
547                 return -1;
548             }
549             return 0;
550         }
551     }
552 
553     private static class Alarm {
554         public int type;
555         public int count;
556         public long when;
557         public long repeatInterval;
558         public PendingIntent operation;
559 
Alarm()560         public Alarm() {
561             when = 0;
562             repeatInterval = 0;
563             operation = null;
564         }
565 
566         @Override
toString()567         public String toString()
568         {
569             StringBuilder sb = new StringBuilder(128);
570             sb.append("Alarm{");
571             sb.append(Integer.toHexString(System.identityHashCode(this)));
572             sb.append(" type ");
573             sb.append(type);
574             sb.append(" ");
575             sb.append(operation.getTargetPackage());
576             sb.append('}');
577             return sb.toString();
578         }
579 
dump(PrintWriter pw, String prefix)580         public void dump(PrintWriter pw, String prefix)
581         {
582             pw.print(prefix); pw.print("type="); pw.print(type);
583                     pw.print(" when="); pw.print(when);
584                     pw.print(" repeatInterval="); pw.print(repeatInterval);
585                     pw.print(" count="); pw.println(count);
586             pw.print(prefix); pw.print("operation="); pw.println(operation);
587         }
588     }
589 
590     private class AlarmThread extends Thread
591     {
AlarmThread()592         public AlarmThread()
593         {
594             super("AlarmManager");
595         }
596 
run()597         public void run()
598         {
599             while (true)
600             {
601                 int result = waitForAlarm(mDescriptor);
602 
603                 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
604 
605                 if ((result & TIME_CHANGED_MASK) != 0) {
606                     remove(mTimeTickSender);
607                     mClockReceiver.scheduleTimeTickEvent();
608                     mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_CHANGED));
609                 }
610 
611                 synchronized (mLock) {
612                     final long nowRTC = System.currentTimeMillis();
613                     final long nowELAPSED = SystemClock.elapsedRealtime();
614                     if (localLOGV) Log.v(
615                         TAG, "Checking for alarms... rtc=" + nowRTC
616                         + ", elapsed=" + nowELAPSED);
617 
618                     if ((result & RTC_WAKEUP_MASK) != 0)
619                         triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
620 
621                     if ((result & RTC_MASK) != 0)
622                         triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
623 
624                     if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0)
625                         triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED);
626 
627                     if ((result & ELAPSED_REALTIME_MASK) != 0)
628                         triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED);
629 
630                     // now trigger the alarms
631                     Iterator<Alarm> it = triggerList.iterator();
632                     while (it.hasNext()) {
633                         Alarm alarm = it.next();
634                         try {
635                             if (localLOGV) Log.v(TAG, "sending alarm " + alarm);
636                             alarm.operation.send(mContext, 0,
637                                     mBackgroundIntent.putExtra(
638                                             Intent.EXTRA_ALARM_COUNT, alarm.count),
639                                     mResultReceiver, mHandler);
640 
641                             // we have an active broadcast so stay awake.
642                             if (mBroadcastRefCount == 0) {
643                                 mWakeLock.acquire();
644                             }
645                             mBroadcastRefCount++;
646 
647                             BroadcastStats bs = getStatsLocked(alarm.operation);
648                             if (bs.nesting == 0) {
649                                 bs.startTime = nowELAPSED;
650                             } else {
651                                 bs.nesting++;
652                             }
653                             if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP
654                                     || alarm.type == AlarmManager.RTC_WAKEUP) {
655                                 bs.numWakeup++;
656                                 ActivityManagerNative.noteWakeupAlarm(
657                                         alarm.operation);
658                             }
659                         } catch (PendingIntent.CanceledException e) {
660                             if (alarm.repeatInterval > 0) {
661                                 // This IntentSender is no longer valid, but this
662                                 // is a repeating alarm, so toss the hoser.
663                                 remove(alarm.operation);
664                             }
665                         } catch (RuntimeException e) {
666                             Log.w(TAG, "Failure sending alarm.", e);
667                         }
668                     }
669                 }
670             }
671         }
672     }
673 
674     private class AlarmHandler extends Handler {
675         public static final int ALARM_EVENT = 1;
676         public static final int MINUTE_CHANGE_EVENT = 2;
677         public static final int DATE_CHANGE_EVENT = 3;
678 
AlarmHandler()679         public AlarmHandler() {
680         }
681 
handleMessage(Message msg)682         public void handleMessage(Message msg) {
683             if (msg.what == ALARM_EVENT) {
684                 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
685                 synchronized (mLock) {
686                     final long nowRTC = System.currentTimeMillis();
687                     triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
688                     triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
689                     triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC);
690                     triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC);
691                 }
692 
693                 // now trigger the alarms without the lock held
694                 Iterator<Alarm> it = triggerList.iterator();
695                 while (it.hasNext())
696                 {
697                     Alarm alarm = it.next();
698                     try {
699                         alarm.operation.send();
700                     } catch (PendingIntent.CanceledException e) {
701                         if (alarm.repeatInterval > 0) {
702                             // This IntentSender is no longer valid, but this
703                             // is a repeating alarm, so toss the hoser.
704                             remove(alarm.operation);
705                         }
706                     }
707                 }
708             }
709         }
710     }
711 
712     class ClockReceiver extends BroadcastReceiver {
ClockReceiver()713         public ClockReceiver() {
714             IntentFilter filter = new IntentFilter();
715             filter.addAction(Intent.ACTION_TIME_TICK);
716             filter.addAction(Intent.ACTION_DATE_CHANGED);
717             mContext.registerReceiver(this, filter);
718         }
719 
720         @Override
onReceive(Context context, Intent intent)721         public void onReceive(Context context, Intent intent) {
722             if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
723             	scheduleTimeTickEvent();
724             } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
725                 // Since the kernel does not keep track of DST, we need to
726                 // reset the TZ information at the beginning of each day
727                 // based off of the current Zone gmt offset + userspace tracked
728                 // daylight savings information.
729                 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
730                 int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000;
731 
732                 setKernelTimezone(mDescriptor, -(gmtOffset));
733             	scheduleDateChangedEvent();
734             }
735         }
736 
scheduleTimeTickEvent()737         public void scheduleTimeTickEvent() {
738             Calendar calendar = Calendar.getInstance();
739             calendar.setTimeInMillis(System.currentTimeMillis());
740             calendar.add(Calendar.MINUTE, 1);
741             calendar.set(Calendar.SECOND, 0);
742             calendar.set(Calendar.MILLISECOND, 0);
743 
744             set(AlarmManager.RTC, calendar.getTimeInMillis(), mTimeTickSender);
745         }
746 
scheduleDateChangedEvent()747         public void scheduleDateChangedEvent() {
748             Calendar calendar = Calendar.getInstance();
749             calendar.setTimeInMillis(System.currentTimeMillis());
750             calendar.set(Calendar.HOUR, 0);
751             calendar.set(Calendar.MINUTE, 0);
752             calendar.set(Calendar.SECOND, 0);
753             calendar.set(Calendar.MILLISECOND, 0);
754             calendar.add(Calendar.DAY_OF_MONTH, 1);
755 
756             set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender);
757         }
758     }
759 
760     class UninstallReceiver extends BroadcastReceiver {
UninstallReceiver()761         public UninstallReceiver() {
762             IntentFilter filter = new IntentFilter();
763             filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
764             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
765             filter.addDataScheme("package");
766             mContext.registerReceiver(this, filter);
767         }
768 
769         @Override
onReceive(Context context, Intent intent)770         public void onReceive(Context context, Intent intent) {
771             synchronized (mLock) {
772                 Uri data = intent.getData();
773                 if (data != null) {
774                     String pkg = data.getSchemeSpecificPart();
775                     removeLocked(pkg);
776                     mBroadcastStats.remove(pkg);
777                 }
778             }
779         }
780     }
781 
getStatsLocked(PendingIntent pi)782     private final BroadcastStats getStatsLocked(PendingIntent pi) {
783         String pkg = pi.getTargetPackage();
784         BroadcastStats bs = mBroadcastStats.get(pkg);
785         if (bs == null) {
786             bs = new BroadcastStats();
787             mBroadcastStats.put(pkg, bs);
788         }
789         return bs;
790     }
791 
792     class ResultReceiver implements PendingIntent.OnFinished {
onSendFinished(PendingIntent pi, Intent intent, int resultCode, String resultData, Bundle resultExtras)793         public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
794                 String resultData, Bundle resultExtras) {
795             synchronized (mLock) {
796                 BroadcastStats bs = getStatsLocked(pi);
797                 if (bs != null) {
798                     bs.nesting--;
799                     if (bs.nesting <= 0) {
800                         bs.nesting = 0;
801                         bs.aggregateTime += SystemClock.elapsedRealtime()
802                                 - bs.startTime;
803                         Intent.FilterComparison fc = new Intent.FilterComparison(intent);
804                         FilterStats fs = bs.filterStats.get(fc);
805                         if (fs == null) {
806                             fs = new FilterStats();
807                             bs.filterStats.put(fc, fs);
808                         }
809                         fs.count++;
810                     }
811                 }
812                 mBroadcastRefCount--;
813                 if (mBroadcastRefCount == 0) {
814                     mWakeLock.release();
815                 }
816             }
817         }
818     }
819 }
820