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