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