Home | History | Annotate | Download | only in server
      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.Activity;
     20 import android.app.ActivityManagerNative;
     21 import android.app.AlarmManager;
     22 import android.app.IAlarmManager;
     23 import android.app.PendingIntent;
     24 import android.content.BroadcastReceiver;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.IntentFilter;
     28 import android.content.pm.PackageManager;
     29 import android.net.Uri;
     30 import android.os.Binder;
     31 import android.os.Bundle;
     32 import android.os.Handler;
     33 import android.os.Message;
     34 import android.os.PowerManager;
     35 import android.os.SystemClock;
     36 import android.os.SystemProperties;
     37 import android.os.UserHandle;
     38 import android.os.WorkSource;
     39 import android.text.TextUtils;
     40 import android.text.format.Time;
     41 import android.util.Slog;
     42 import android.util.TimeUtils;
     43 
     44 import java.io.FileDescriptor;
     45 import java.io.PrintWriter;
     46 import java.text.SimpleDateFormat;
     47 import java.util.ArrayList;
     48 import java.util.Calendar;
     49 import java.util.Collections;
     50 import java.util.Comparator;
     51 import java.util.Date;
     52 import java.util.HashMap;
     53 import java.util.Iterator;
     54 import java.util.LinkedList;
     55 import java.util.Map;
     56 import java.util.TimeZone;
     57 
     58 class 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