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