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