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.util.Pair;
     42 import android.util.Slog;
     43 import android.util.TimeUtils;
     44 
     45 import java.io.ByteArrayOutputStream;
     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.LinkedList;
     57 import java.util.Map;
     58 import java.util.TimeZone;
     59 
     60 import static android.app.AlarmManager.RTC_WAKEUP;
     61 import static android.app.AlarmManager.RTC;
     62 import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
     63 import static android.app.AlarmManager.ELAPSED_REALTIME;
     64 
     65 import com.android.internal.util.LocalLog;
     66 
     67 class AlarmManagerService extends IAlarmManager.Stub {
     68     // The threshold for how long an alarm can be late before we print a
     69     // warning message.  The time duration is in milliseconds.
     70     private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
     71 
     72     private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
     73     private static final int RTC_MASK = 1 << RTC;
     74     private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
     75     private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
     76     private static final int TIME_CHANGED_MASK = 1 << 16;
     77     private static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
     78 
     79     // Mask for testing whether a given alarm type is wakeup vs non-wakeup
     80     private static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
     81 
     82     private static final String TAG = "AlarmManager";
     83     private static final String ClockReceiver_TAG = "ClockReceiver";
     84     private static final boolean localLOGV = false;
     85     private static final boolean DEBUG_BATCH = localLOGV || false;
     86     private static final boolean DEBUG_VALIDATE = localLOGV || false;
     87     private static final int ALARM_EVENT = 1;
     88     private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
     89 
     90     private static final Intent mBackgroundIntent
     91             = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
     92     private static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
     93 
     94     private static final boolean WAKEUP_STATS = false;
     95 
     96     private final Context mContext;
     97 
     98     private final LocalLog mLog = new LocalLog(TAG);
     99 
    100     private Object mLock = new Object();
    101 
    102     private int mDescriptor;
    103     private long mNextWakeup;
    104     private long mNextNonWakeup;
    105     private int mBroadcastRefCount = 0;
    106     private PowerManager.WakeLock mWakeLock;
    107     private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
    108     private final AlarmThread mWaitThread = new AlarmThread();
    109     private final AlarmHandler mHandler = new AlarmHandler();
    110     private ClockReceiver mClockReceiver;
    111     private UninstallReceiver mUninstallReceiver;
    112     private final ResultReceiver mResultReceiver = new ResultReceiver();
    113     private final PendingIntent mTimeTickSender;
    114     private final PendingIntent mDateChangeSender;
    115 
    116     class WakeupEvent {
    117         public long when;
    118         public int uid;
    119         public String action;
    120 
    121         public WakeupEvent(long theTime, int theUid, String theAction) {
    122             when = theTime;
    123             uid = theUid;
    124             action = theAction;
    125         }
    126     }
    127 
    128     private final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
    129     private final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
    130 
    131     static final class Batch {
    132         long start;     // These endpoints are always in ELAPSED
    133         long end;
    134         boolean standalone; // certain "batches" don't participate in coalescing
    135 
    136         final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
    137 
    138         Batch() {
    139             start = 0;
    140             end = Long.MAX_VALUE;
    141         }
    142 
    143         Batch(Alarm seed) {
    144             start = seed.whenElapsed;
    145             end = seed.maxWhen;
    146             alarms.add(seed);
    147         }
    148 
    149         int size() {
    150             return alarms.size();
    151         }
    152 
    153         Alarm get(int index) {
    154             return alarms.get(index);
    155         }
    156 
    157         boolean canHold(long whenElapsed, long maxWhen) {
    158             return (end >= whenElapsed) && (start <= maxWhen);
    159         }
    160 
    161         boolean add(Alarm alarm) {
    162             boolean newStart = false;
    163             // narrows the batch if necessary; presumes that canHold(alarm) is true
    164             int index = Collections.binarySearch(alarms, alarm, sIncreasingTimeOrder);
    165             if (index < 0) {
    166                 index = 0 - index - 1;
    167             }
    168             alarms.add(index, alarm);
    169             if (DEBUG_BATCH) {
    170                 Slog.v(TAG, "Adding " + alarm + " to " + this);
    171             }
    172             if (alarm.whenElapsed > start) {
    173                 start = alarm.whenElapsed;
    174                 newStart = true;
    175             }
    176             if (alarm.maxWhen < end) {
    177                 end = alarm.maxWhen;
    178             }
    179 
    180             if (DEBUG_BATCH) {
    181                 Slog.v(TAG, "    => now " + this);
    182             }
    183             return newStart;
    184         }
    185 
    186         boolean remove(final PendingIntent operation) {
    187             boolean didRemove = false;
    188             long newStart = 0;  // recalculate endpoints as we go
    189             long newEnd = Long.MAX_VALUE;
    190             for (int i = 0; i < alarms.size(); ) {
    191                 Alarm alarm = alarms.get(i);
    192                 if (alarm.operation.equals(operation)) {
    193                     alarms.remove(i);
    194                     didRemove = true;
    195                 } else {
    196                     if (alarm.whenElapsed > newStart) {
    197                         newStart = alarm.whenElapsed;
    198                     }
    199                     if (alarm.maxWhen < newEnd) {
    200                         newEnd = alarm.maxWhen;
    201                     }
    202                     i++;
    203                 }
    204             }
    205             if (didRemove) {
    206                 // commit the new batch bounds
    207                 start = newStart;
    208                 end = newEnd;
    209             }
    210             return didRemove;
    211         }
    212 
    213         boolean remove(final String packageName) {
    214             boolean didRemove = false;
    215             long newStart = 0;  // recalculate endpoints as we go
    216             long newEnd = Long.MAX_VALUE;
    217             for (int i = 0; i < alarms.size(); ) {
    218                 Alarm alarm = alarms.get(i);
    219                 if (alarm.operation.getTargetPackage().equals(packageName)) {
    220                     alarms.remove(i);
    221                     didRemove = true;
    222                 } else {
    223                     if (alarm.whenElapsed > newStart) {
    224                         newStart = alarm.whenElapsed;
    225                     }
    226                     if (alarm.maxWhen < newEnd) {
    227                         newEnd = alarm.maxWhen;
    228                     }
    229                     i++;
    230                 }
    231             }
    232             if (didRemove) {
    233                 // commit the new batch bounds
    234                 start = newStart;
    235                 end = newEnd;
    236             }
    237             return didRemove;
    238         }
    239 
    240         boolean remove(final int userHandle) {
    241             boolean didRemove = false;
    242             long newStart = 0;  // recalculate endpoints as we go
    243             long newEnd = Long.MAX_VALUE;
    244             for (int i = 0; i < alarms.size(); ) {
    245                 Alarm alarm = alarms.get(i);
    246                 if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
    247                     alarms.remove(i);
    248                     didRemove = true;
    249                 } else {
    250                     if (alarm.whenElapsed > newStart) {
    251                         newStart = alarm.whenElapsed;
    252                     }
    253                     if (alarm.maxWhen < newEnd) {
    254                         newEnd = alarm.maxWhen;
    255                     }
    256                     i++;
    257                 }
    258             }
    259             if (didRemove) {
    260                 // commit the new batch bounds
    261                 start = newStart;
    262                 end = newEnd;
    263             }
    264             return didRemove;
    265         }
    266 
    267         boolean hasPackage(final String packageName) {
    268             final int N = alarms.size();
    269             for (int i = 0; i < N; i++) {
    270                 Alarm a = alarms.get(i);
    271                 if (a.operation.getTargetPackage().equals(packageName)) {
    272                     return true;
    273                 }
    274             }
    275             return false;
    276         }
    277 
    278         boolean hasWakeups() {
    279             final int N = alarms.size();
    280             for (int i = 0; i < N; i++) {
    281                 Alarm a = alarms.get(i);
    282                 // non-wakeup alarms are types 1 and 3, i.e. have the low bit set
    283                 if ((a.type & TYPE_NONWAKEUP_MASK) == 0) {
    284                     return true;
    285                 }
    286             }
    287             return false;
    288         }
    289 
    290         @Override
    291         public String toString() {
    292             StringBuilder b = new StringBuilder(40);
    293             b.append("Batch{"); b.append(Integer.toHexString(this.hashCode()));
    294             b.append(" num="); b.append(size());
    295             b.append(" start="); b.append(start);
    296             b.append(" end="); b.append(end);
    297             if (standalone) {
    298                 b.append(" STANDALONE");
    299             }
    300             b.append('}');
    301             return b.toString();
    302         }
    303     }
    304 
    305     static class BatchTimeOrder implements Comparator<Batch> {
    306         public int compare(Batch b1, Batch b2) {
    307             long when1 = b1.start;
    308             long when2 = b2.start;
    309             if (when1 - when2 > 0) {
    310                 return 1;
    311             }
    312             if (when1 - when2 < 0) {
    313                 return -1;
    314             }
    315             return 0;
    316         }
    317     }
    318 
    319     // minimum recurrence period or alarm futurity for us to be able to fuzz it
    320     private static final long MIN_FUZZABLE_INTERVAL = 10000;
    321     private static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
    322     private final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
    323 
    324     static long convertToElapsed(long when, int type) {
    325         final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
    326         if (isRtc) {
    327             when -= System.currentTimeMillis() - SystemClock.elapsedRealtime();
    328         }
    329         return when;
    330     }
    331 
    332     // Apply a heuristic to { recurrence interval, futurity of the trigger time } to
    333     // calculate the end of our nominal delivery window for the alarm.
    334     static long maxTriggerTime(long now, long triggerAtTime, long interval) {
    335         // Current heuristic: batchable window is 75% of either the recurrence interval
    336         // [for a periodic alarm] or of the time from now to the desired delivery time,
    337         // with a minimum delay/interval of 10 seconds, under which we will simply not
    338         // defer the alarm.
    339         long futurity = (interval == 0)
    340                 ? (triggerAtTime - now)
    341                 : interval;
    342         if (futurity < MIN_FUZZABLE_INTERVAL) {
    343             futurity = 0;
    344         }
    345         return triggerAtTime + (long)(.75 * futurity);
    346     }
    347 
    348     // returns true if the batch was added at the head
    349     static boolean addBatchLocked(ArrayList<Batch> list, Batch newBatch) {
    350         int index = Collections.binarySearch(list, newBatch, sBatchOrder);
    351         if (index < 0) {
    352             index = 0 - index - 1;
    353         }
    354         list.add(index, newBatch);
    355         return (index == 0);
    356     }
    357 
    358     // Return the index of the matching batch, or -1 if none found.
    359     int attemptCoalesceLocked(long whenElapsed, long maxWhen) {
    360         final int N = mAlarmBatches.size();
    361         for (int i = 0; i < N; i++) {
    362             Batch b = mAlarmBatches.get(i);
    363             if (!b.standalone && b.canHold(whenElapsed, maxWhen)) {
    364                 return i;
    365             }
    366         }
    367         return -1;
    368     }
    369 
    370     // The RTC clock has moved arbitrarily, so we need to recalculate all the batching
    371     void rebatchAllAlarms() {
    372         synchronized (mLock) {
    373             rebatchAllAlarmsLocked(true);
    374         }
    375     }
    376 
    377     void rebatchAllAlarmsLocked(boolean doValidate) {
    378         ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone();
    379         mAlarmBatches.clear();
    380         final long nowElapsed = SystemClock.elapsedRealtime();
    381         final int oldBatches = oldSet.size();
    382         for (int batchNum = 0; batchNum < oldBatches; batchNum++) {
    383             Batch batch = oldSet.get(batchNum);
    384             final int N = batch.size();
    385             for (int i = 0; i < N; i++) {
    386                 Alarm a = batch.get(i);
    387                 long whenElapsed = convertToElapsed(a.when, a.type);
    388                 final long maxElapsed;
    389                 if (a.whenElapsed == a.maxWhen) {
    390                     // Exact
    391                     maxElapsed = whenElapsed;
    392                 } else {
    393                     // Not exact.  Preserve any explicit window, otherwise recalculate
    394                     // the window based on the alarm's new futurity.  Note that this
    395                     // reflects a policy of preferring timely to deferred delivery.
    396                     maxElapsed = (a.windowLength > 0)
    397                             ? (whenElapsed + a.windowLength)
    398                             : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
    399                 }
    400                 setImplLocked(a.type, a.when, whenElapsed, a.windowLength, maxElapsed,
    401                         a.repeatInterval, a.operation, batch.standalone, doValidate, a.workSource);
    402             }
    403         }
    404     }
    405 
    406     private static final class InFlight extends Intent {
    407         final PendingIntent mPendingIntent;
    408         final WorkSource mWorkSource;
    409         final Pair<String, ComponentName> mTarget;
    410         final BroadcastStats mBroadcastStats;
    411         final FilterStats mFilterStats;
    412 
    413         InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource) {
    414             mPendingIntent = pendingIntent;
    415             mWorkSource = workSource;
    416             Intent intent = pendingIntent.getIntent();
    417             mTarget = intent != null
    418                     ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent())
    419                     : null;
    420             mBroadcastStats = service.getStatsLocked(pendingIntent);
    421             FilterStats fs = mBroadcastStats.filterStats.get(mTarget);
    422             if (fs == null) {
    423                 fs = new FilterStats(mBroadcastStats, mTarget);
    424                 mBroadcastStats.filterStats.put(mTarget, fs);
    425             }
    426             mFilterStats = fs;
    427         }
    428     }
    429 
    430     private static final class FilterStats {
    431         final BroadcastStats mBroadcastStats;
    432         final Pair<String, ComponentName> mTarget;
    433 
    434         long aggregateTime;
    435         int count;
    436         int numWakeup;
    437         long startTime;
    438         int nesting;
    439 
    440         FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target) {
    441             mBroadcastStats = broadcastStats;
    442             mTarget = target;
    443         }
    444     }
    445 
    446     private static final class BroadcastStats {
    447         final String mPackageName;
    448 
    449         long aggregateTime;
    450         int count;
    451         int numWakeup;
    452         long startTime;
    453         int nesting;
    454         final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
    455                 = new HashMap<Pair<String, ComponentName>, FilterStats>();
    456 
    457         BroadcastStats(String packageName) {
    458             mPackageName = packageName;
    459         }
    460     }
    461 
    462     private final HashMap<String, BroadcastStats> mBroadcastStats
    463             = new HashMap<String, BroadcastStats>();
    464 
    465     public AlarmManagerService(Context context) {
    466         mContext = context;
    467         mDescriptor = init();
    468         mNextWakeup = mNextNonWakeup = 0;
    469 
    470         // We have to set current TimeZone info to kernel
    471         // because kernel doesn't keep this after reboot
    472         String tz = SystemProperties.get(TIMEZONE_PROPERTY);
    473         if (tz != null) {
    474             setTimeZone(tz);
    475         }
    476 
    477         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    478         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    479 
    480         mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
    481                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
    482                         Intent.FLAG_RECEIVER_REGISTERED_ONLY
    483                         | Intent.FLAG_RECEIVER_FOREGROUND), 0,
    484                         UserHandle.ALL);
    485         Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
    486         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    487         mDateChangeSender = PendingIntent.getBroadcastAsUser(context, 0, intent,
    488                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
    489 
    490         // now that we have initied the driver schedule the alarm
    491         mClockReceiver= new ClockReceiver();
    492         mClockReceiver.scheduleTimeTickEvent();
    493         mClockReceiver.scheduleDateChangedEvent();
    494         mUninstallReceiver = new UninstallReceiver();
    495 
    496         if (mDescriptor != -1) {
    497             mWaitThread.start();
    498         } else {
    499             Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
    500         }
    501     }
    502 
    503     protected void finalize() throws Throwable {
    504         try {
    505             close(mDescriptor);
    506         } finally {
    507             super.finalize();
    508         }
    509     }
    510 
    511     @Override
    512     public void set(int type, long triggerAtTime, long windowLength, long interval,
    513             PendingIntent operation, WorkSource workSource) {
    514         if (workSource != null) {
    515             mContext.enforceCallingPermission(
    516                     android.Manifest.permission.UPDATE_DEVICE_STATS,
    517                     "AlarmManager.set");
    518         }
    519 
    520         set(type, triggerAtTime, windowLength, interval, operation, false, workSource);
    521     }
    522 
    523     public void set(int type, long triggerAtTime, long windowLength, long interval,
    524             PendingIntent operation, boolean isStandalone, WorkSource workSource) {
    525         if (operation == null) {
    526             Slog.w(TAG, "set/setRepeating ignored because there is no intent");
    527             return;
    528         }
    529 
    530         // Sanity check the window length.  This will catch people mistakenly
    531         // trying to pass an end-of-window timestamp rather than a duration.
    532         if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
    533             Slog.w(TAG, "Window length " + windowLength
    534                     + "ms suspiciously long; limiting to 1 hour");
    535             windowLength = AlarmManager.INTERVAL_HOUR;
    536         }
    537 
    538         if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
    539             throw new IllegalArgumentException("Invalid alarm type " + type);
    540         }
    541 
    542         if (triggerAtTime < 0) {
    543             final long who = Binder.getCallingUid();
    544             final long what = Binder.getCallingPid();
    545             Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who
    546                     + " pid=" + what);
    547             triggerAtTime = 0;
    548         }
    549 
    550         final long nowElapsed = SystemClock.elapsedRealtime();
    551         final long triggerElapsed = convertToElapsed(triggerAtTime, type);
    552         final long maxElapsed;
    553         if (windowLength == AlarmManager.WINDOW_EXACT) {
    554             maxElapsed = triggerElapsed;
    555         } else if (windowLength < 0) {
    556             maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
    557         } else {
    558             maxElapsed = triggerElapsed + windowLength;
    559         }
    560 
    561         synchronized (mLock) {
    562             if (DEBUG_BATCH) {
    563                 Slog.v(TAG, "set(" + operation + ") : type=" + type
    564                         + " triggerAtTime=" + triggerAtTime + " win=" + windowLength
    565                         + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
    566                         + " interval=" + interval + " standalone=" + isStandalone);
    567             }
    568             setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
    569                     interval, operation, isStandalone, true, workSource);
    570         }
    571     }
    572 
    573     private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
    574             long maxWhen, long interval, PendingIntent operation, boolean isStandalone,
    575             boolean doValidate, WorkSource workSource) {
    576         Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
    577                 operation, workSource);
    578         removeLocked(operation);
    579 
    580         int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);
    581         if (whichBatch < 0) {
    582             Batch batch = new Batch(a);
    583             batch.standalone = isStandalone;
    584             addBatchLocked(mAlarmBatches, batch);
    585         } else {
    586             Batch batch = mAlarmBatches.get(whichBatch);
    587             if (batch.add(a)) {
    588                 // The start time of this batch advanced, so batch ordering may
    589                 // have just been broken.  Move it to where it now belongs.
    590                 mAlarmBatches.remove(whichBatch);
    591                 addBatchLocked(mAlarmBatches, batch);
    592             }
    593         }
    594 
    595         if (DEBUG_VALIDATE) {
    596             if (doValidate && !validateConsistencyLocked()) {
    597                 Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when
    598                         + " when(hex)=" + Long.toHexString(when)
    599                         + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen
    600                         + " interval=" + interval + " op=" + operation
    601                         + " standalone=" + isStandalone);
    602                 rebatchAllAlarmsLocked(false);
    603             }
    604         }
    605 
    606         rescheduleKernelAlarmsLocked();
    607     }
    608 
    609     private void logBatchesLocked() {
    610         ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
    611         PrintWriter pw = new PrintWriter(bs);
    612         final long nowRTC = System.currentTimeMillis();
    613         final long nowELAPSED = SystemClock.elapsedRealtime();
    614         final int NZ = mAlarmBatches.size();
    615         for (int iz = 0; iz < NZ; iz++) {
    616             Batch bz = mAlarmBatches.get(iz);
    617             pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
    618             dumpAlarmList(pw, bz.alarms, "  ", nowELAPSED, nowRTC);
    619             pw.flush();
    620             Slog.v(TAG, bs.toString());
    621             bs.reset();
    622         }
    623     }
    624 
    625     private boolean validateConsistencyLocked() {
    626         if (DEBUG_VALIDATE) {
    627             long lastTime = Long.MIN_VALUE;
    628             final int N = mAlarmBatches.size();
    629             for (int i = 0; i < N; i++) {
    630                 Batch b = mAlarmBatches.get(i);
    631                 if (b.start >= lastTime) {
    632                     // duplicate start times are okay because of standalone batches
    633                     lastTime = b.start;
    634                 } else {
    635                     Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
    636                     logBatchesLocked();
    637                     return false;
    638                 }
    639             }
    640         }
    641         return true;
    642     }
    643 
    644     private Batch findFirstWakeupBatchLocked() {
    645         final int N = mAlarmBatches.size();
    646         for (int i = 0; i < N; i++) {
    647             Batch b = mAlarmBatches.get(i);
    648             if (b.hasWakeups()) {
    649                 return b;
    650             }
    651         }
    652         return null;
    653     }
    654 
    655     private void rescheduleKernelAlarmsLocked() {
    656         // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
    657         // prior to that which contains no wakeups, we schedule that as well.
    658         if (mAlarmBatches.size() > 0) {
    659             final Batch firstWakeup = findFirstWakeupBatchLocked();
    660             final Batch firstBatch = mAlarmBatches.get(0);
    661             if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
    662                 mNextWakeup = firstWakeup.start;
    663                 setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
    664             }
    665             if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
    666                 mNextNonWakeup = firstBatch.start;
    667                 setLocked(ELAPSED_REALTIME, firstBatch.start);
    668             }
    669         }
    670     }
    671 
    672     public void setTime(long millis) {
    673         mContext.enforceCallingOrSelfPermission(
    674                 "android.permission.SET_TIME",
    675                 "setTime");
    676 
    677         SystemClock.setCurrentTimeMillis(millis);
    678     }
    679 
    680     public void setTimeZone(String tz) {
    681         mContext.enforceCallingOrSelfPermission(
    682                 "android.permission.SET_TIME_ZONE",
    683                 "setTimeZone");
    684 
    685         long oldId = Binder.clearCallingIdentity();
    686         try {
    687             if (TextUtils.isEmpty(tz)) return;
    688             TimeZone zone = TimeZone.getTimeZone(tz);
    689             // Prevent reentrant calls from stepping on each other when writing
    690             // the time zone property
    691             boolean timeZoneWasChanged = false;
    692             synchronized (this) {
    693                 String current = SystemProperties.get(TIMEZONE_PROPERTY);
    694                 if (current == null || !current.equals(zone.getID())) {
    695                     if (localLOGV) {
    696                         Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
    697                     }
    698                     timeZoneWasChanged = true;
    699                     SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
    700                 }
    701 
    702                 // Update the kernel timezone information
    703                 // Kernel tracks time offsets as 'minutes west of GMT'
    704                 int gmtOffset = zone.getOffset(System.currentTimeMillis());
    705                 setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
    706             }
    707 
    708             TimeZone.setDefault(null);
    709 
    710             if (timeZoneWasChanged) {
    711                 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
    712                 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    713                 intent.putExtra("time-zone", zone.getID());
    714                 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    715             }
    716         } finally {
    717             Binder.restoreCallingIdentity(oldId);
    718         }
    719     }
    720 
    721     public void remove(PendingIntent operation) {
    722         if (operation == null) {
    723             return;
    724         }
    725         synchronized (mLock) {
    726             removeLocked(operation);
    727         }
    728     }
    729 
    730     public void removeLocked(PendingIntent operation) {
    731         boolean didRemove = false;
    732         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
    733             Batch b = mAlarmBatches.get(i);
    734             didRemove |= b.remove(operation);
    735             if (b.size() == 0) {
    736                 mAlarmBatches.remove(i);
    737             }
    738         }
    739 
    740         if (didRemove) {
    741             if (DEBUG_BATCH) {
    742                 Slog.v(TAG, "remove(operation) changed bounds; rebatching");
    743             }
    744             rebatchAllAlarmsLocked(true);
    745             rescheduleKernelAlarmsLocked();
    746         }
    747     }
    748 
    749     public void removeLocked(String packageName) {
    750         boolean didRemove = false;
    751         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
    752             Batch b = mAlarmBatches.get(i);
    753             didRemove |= b.remove(packageName);
    754             if (b.size() == 0) {
    755                 mAlarmBatches.remove(i);
    756             }
    757         }
    758 
    759         if (didRemove) {
    760             if (DEBUG_BATCH) {
    761                 Slog.v(TAG, "remove(package) changed bounds; rebatching");
    762             }
    763             rebatchAllAlarmsLocked(true);
    764             rescheduleKernelAlarmsLocked();
    765         }
    766     }
    767 
    768     public void removeUserLocked(int userHandle) {
    769         boolean didRemove = false;
    770         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
    771             Batch b = mAlarmBatches.get(i);
    772             didRemove |= b.remove(userHandle);
    773             if (b.size() == 0) {
    774                 mAlarmBatches.remove(i);
    775             }
    776         }
    777 
    778         if (didRemove) {
    779             if (DEBUG_BATCH) {
    780                 Slog.v(TAG, "remove(user) changed bounds; rebatching");
    781             }
    782             rebatchAllAlarmsLocked(true);
    783             rescheduleKernelAlarmsLocked();
    784         }
    785     }
    786 
    787     public boolean lookForPackageLocked(String packageName) {
    788         for (int i = 0; i < mAlarmBatches.size(); i++) {
    789             Batch b = mAlarmBatches.get(i);
    790             if (b.hasPackage(packageName)) {
    791                 return true;
    792             }
    793         }
    794         return false;
    795     }
    796 
    797     private void setLocked(int type, long when)
    798     {
    799         if (mDescriptor != -1)
    800         {
    801             // The kernel never triggers alarms with negative wakeup times
    802             // so we ensure they are positive.
    803             long alarmSeconds, alarmNanoseconds;
    804             if (when < 0) {
    805                 alarmSeconds = 0;
    806                 alarmNanoseconds = 0;
    807             } else {
    808                 alarmSeconds = when / 1000;
    809                 alarmNanoseconds = (when % 1000) * 1000 * 1000;
    810             }
    811 
    812             set(mDescriptor, type, alarmSeconds, alarmNanoseconds);
    813         }
    814         else
    815         {
    816             Message msg = Message.obtain();
    817             msg.what = ALARM_EVENT;
    818 
    819             mHandler.removeMessages(ALARM_EVENT);
    820             mHandler.sendMessageAtTime(msg, when);
    821         }
    822     }
    823 
    824     @Override
    825     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    826         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
    827                 != PackageManager.PERMISSION_GRANTED) {
    828             pw.println("Permission Denial: can't dump AlarmManager from from pid="
    829                     + Binder.getCallingPid()
    830                     + ", uid=" + Binder.getCallingUid());
    831             return;
    832         }
    833 
    834         synchronized (mLock) {
    835             pw.println("Current Alarm Manager state:");
    836             final long nowRTC = System.currentTimeMillis();
    837             final long nowELAPSED = SystemClock.elapsedRealtime();
    838             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    839 
    840             pw.print("nowRTC="); pw.print(nowRTC);
    841             pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
    842             pw.print(" nowELAPSED="); pw.println(nowELAPSED);
    843 
    844             long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
    845             long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
    846             pw.print("Next alarm: "); pw.print(mNextNonWakeup);
    847                     pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
    848             pw.print("Next wakeup: "); pw.print(mNextWakeup);
    849                     pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
    850 
    851             if (mAlarmBatches.size() > 0) {
    852                 pw.println();
    853                 pw.print("Pending alarm batches: ");
    854                 pw.println(mAlarmBatches.size());
    855                 for (Batch b : mAlarmBatches) {
    856                     pw.print(b); pw.println(':');
    857                     dumpAlarmList(pw, b.alarms, "  ", nowELAPSED, nowRTC);
    858                 }
    859             }
    860 
    861             pw.println();
    862             pw.print("  Broadcast ref count: "); pw.println(mBroadcastRefCount);
    863             pw.println();
    864 
    865             if (mLog.dump(pw, "  Recent problems", "    ")) {
    866                 pw.println();
    867             }
    868 
    869             final FilterStats[] topFilters = new FilterStats[10];
    870             final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
    871                 @Override
    872                 public int compare(FilterStats lhs, FilterStats rhs) {
    873                     if (lhs.aggregateTime < rhs.aggregateTime) {
    874                         return 1;
    875                     } else if (lhs.aggregateTime > rhs.aggregateTime) {
    876                         return -1;
    877                     }
    878                     return 0;
    879                 }
    880             };
    881             int len = 0;
    882             for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
    883                 BroadcastStats bs = be.getValue();
    884                 for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
    885                         : bs.filterStats.entrySet()) {
    886                     FilterStats fs = fe.getValue();
    887                     int pos = len > 0
    888                             ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
    889                     if (pos < 0) {
    890                         pos = -pos - 1;
    891                     }
    892                     if (pos < topFilters.length) {
    893                         int copylen = topFilters.length - pos - 1;
    894                         if (copylen > 0) {
    895                             System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
    896                         }
    897                         topFilters[pos] = fs;
    898                         if (len < topFilters.length) {
    899                             len++;
    900                         }
    901                     }
    902                 }
    903             }
    904             if (len > 0) {
    905                 pw.println("  Top Alarms:");
    906                 for (int i=0; i<len; i++) {
    907                     FilterStats fs = topFilters[i];
    908                     pw.print("    ");
    909                     if (fs.nesting > 0) pw.print("*ACTIVE* ");
    910                     TimeUtils.formatDuration(fs.aggregateTime, pw);
    911                     pw.print(" running, "); pw.print(fs.numWakeup);
    912                     pw.print(" wakeups, "); pw.print(fs.count);
    913                     pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
    914                     pw.println();
    915                     pw.print("      ");
    916                     if (fs.mTarget.first != null) {
    917                         pw.print(" act="); pw.print(fs.mTarget.first);
    918                     }
    919                     if (fs.mTarget.second != null) {
    920                         pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
    921                     }
    922                     pw.println();
    923                 }
    924             }
    925 
    926             pw.println(" ");
    927             pw.println("  Alarm Stats:");
    928             final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
    929             for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
    930                 BroadcastStats bs = be.getValue();
    931                 pw.print("  ");
    932                 if (bs.nesting > 0) pw.print("*ACTIVE* ");
    933                 pw.print(be.getKey());
    934                 pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
    935                         pw.print(" running, "); pw.print(bs.numWakeup);
    936                         pw.println(" wakeups:");
    937                 tmpFilters.clear();
    938                 for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
    939                         : bs.filterStats.entrySet()) {
    940                     tmpFilters.add(fe.getValue());
    941                 }
    942                 Collections.sort(tmpFilters, comparator);
    943                 for (int i=0; i<tmpFilters.size(); i++) {
    944                     FilterStats fs = tmpFilters.get(i);
    945                     pw.print("    ");
    946                             if (fs.nesting > 0) pw.print("*ACTIVE* ");
    947                             TimeUtils.formatDuration(fs.aggregateTime, pw);
    948                             pw.print(" "); pw.print(fs.numWakeup);
    949                             pw.print(" wakes " ); pw.print(fs.count);
    950                             pw.print(" alarms:");
    951                             if (fs.mTarget.first != null) {
    952                                 pw.print(" act="); pw.print(fs.mTarget.first);
    953                             }
    954                             if (fs.mTarget.second != null) {
    955                                 pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
    956                             }
    957                             pw.println();
    958                 }
    959             }
    960 
    961             if (WAKEUP_STATS) {
    962                 pw.println();
    963                 pw.println("  Recent Wakeup History:");
    964                 long last = -1;
    965                 for (WakeupEvent event : mRecentWakeups) {
    966                     pw.print("    "); pw.print(sdf.format(new Date(event.when)));
    967                     pw.print('|');
    968                     if (last < 0) {
    969                         pw.print('0');
    970                     } else {
    971                         pw.print(event.when - last);
    972                     }
    973                     last = event.when;
    974                     pw.print('|'); pw.print(event.uid);
    975                     pw.print('|'); pw.print(event.action);
    976                     pw.println();
    977                 }
    978                 pw.println();
    979             }
    980         }
    981     }
    982 
    983     private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
    984             String prefix, String label, long now) {
    985         for (int i=list.size()-1; i>=0; i--) {
    986             Alarm a = list.get(i);
    987             pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
    988                     pw.print(": "); pw.println(a);
    989             a.dump(pw, prefix + "  ", now);
    990         }
    991     }
    992 
    993     private static final String labelForType(int type) {
    994         switch (type) {
    995         case RTC: return "RTC";
    996         case RTC_WAKEUP : return "RTC_WAKEUP";
    997         case ELAPSED_REALTIME : return "ELAPSED";
    998         case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
    999         default:
   1000             break;
   1001         }
   1002         return "--unknown--";
   1003     }
   1004 
   1005     private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
   1006             String prefix, long nowELAPSED, long nowRTC) {
   1007         for (int i=list.size()-1; i>=0; i--) {
   1008             Alarm a = list.get(i);
   1009             final String label = labelForType(a.type);
   1010             long now = (a.type <= RTC) ? nowRTC : nowELAPSED;
   1011             pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
   1012                     pw.print(": "); pw.println(a);
   1013             a.dump(pw, prefix + "  ", now);
   1014         }
   1015     }
   1016 
   1017     private native int init();
   1018     private native void close(int fd);
   1019     private native void set(int fd, int type, long seconds, long nanoseconds);
   1020     private native int waitForAlarm(int fd);
   1021     private native int setKernelTimezone(int fd, int minuteswest);
   1022 
   1023     private void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
   1024         // batches are temporally sorted, so we need only pull from the
   1025         // start of the list until we either empty it or hit a batch
   1026         // that is not yet deliverable
   1027         while (mAlarmBatches.size() > 0) {
   1028             Batch batch = mAlarmBatches.get(0);
   1029             if (batch.start > nowELAPSED) {
   1030                 // Everything else is scheduled for the future
   1031                 break;
   1032             }
   1033 
   1034             // We will (re)schedule some alarms now; don't let that interfere
   1035             // with delivery of this current batch
   1036             mAlarmBatches.remove(0);
   1037 
   1038             final int N = batch.size();
   1039             for (int i = 0; i < N; i++) {
   1040                 Alarm alarm = batch.get(i);
   1041                 alarm.count = 1;
   1042                 triggerList.add(alarm);
   1043 
   1044                 // Recurring alarms may have passed several alarm intervals while the
   1045                 // phone was asleep or off, so pass a trigger count when sending them.
   1046                 if (alarm.repeatInterval > 0) {
   1047                     // this adjustment will be zero if we're late by
   1048                     // less than one full repeat interval
   1049                     alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval;
   1050 
   1051                     // Also schedule its next recurrence
   1052                     final long delta = alarm.count * alarm.repeatInterval;
   1053                     final long nextElapsed = alarm.whenElapsed + delta;
   1054                     setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
   1055                             maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
   1056                             alarm.repeatInterval, alarm.operation, batch.standalone, true,
   1057                             alarm.workSource);
   1058                 }
   1059 
   1060             }
   1061         }
   1062     }
   1063 
   1064     /**
   1065      * This Comparator sorts Alarms into increasing time order.
   1066      */
   1067     public static class IncreasingTimeOrder implements Comparator<Alarm> {
   1068         public int compare(Alarm a1, Alarm a2) {
   1069             long when1 = a1.when;
   1070             long when2 = a2.when;
   1071             if (when1 - when2 > 0) {
   1072                 return 1;
   1073             }
   1074             if (when1 - when2 < 0) {
   1075                 return -1;
   1076             }
   1077             return 0;
   1078         }
   1079     }
   1080 
   1081     private static class Alarm {
   1082         public int type;
   1083         public int count;
   1084         public long when;
   1085         public long windowLength;
   1086         public long whenElapsed;    // 'when' in the elapsed time base
   1087         public long maxWhen;        // also in the elapsed time base
   1088         public long repeatInterval;
   1089         public PendingIntent operation;
   1090         public WorkSource workSource;
   1091 
   1092         public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
   1093                 long _interval, PendingIntent _op, WorkSource _ws) {
   1094             type = _type;
   1095             when = _when;
   1096             whenElapsed = _whenElapsed;
   1097             windowLength = _windowLength;
   1098             maxWhen = _maxWhen;
   1099             repeatInterval = _interval;
   1100             operation = _op;
   1101             workSource = _ws;
   1102         }
   1103 
   1104         @Override
   1105         public String toString()
   1106         {
   1107             StringBuilder sb = new StringBuilder(128);
   1108             sb.append("Alarm{");
   1109             sb.append(Integer.toHexString(System.identityHashCode(this)));
   1110             sb.append(" type ");
   1111             sb.append(type);
   1112             sb.append(" ");
   1113             sb.append(operation.getTargetPackage());
   1114             sb.append('}');
   1115             return sb.toString();
   1116         }
   1117 
   1118         public void dump(PrintWriter pw, String prefix, long now) {
   1119             pw.print(prefix); pw.print("type="); pw.print(type);
   1120                     pw.print(" whenElapsed="); pw.print(whenElapsed);
   1121                     pw.print(" when="); TimeUtils.formatDuration(when, now, pw);
   1122                     pw.print(" window="); pw.print(windowLength);
   1123                     pw.print(" repeatInterval="); pw.print(repeatInterval);
   1124                     pw.print(" count="); pw.println(count);
   1125             pw.print(prefix); pw.print("operation="); pw.println(operation);
   1126         }
   1127     }
   1128 
   1129     void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) {
   1130         final int numBatches = batches.size();
   1131         for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) {
   1132             Batch b = batches.get(nextBatch);
   1133             if (b.start > nowELAPSED) {
   1134                 break;
   1135             }
   1136 
   1137             final int numAlarms = b.alarms.size();
   1138             for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) {
   1139                 Alarm a = b.alarms.get(nextAlarm);
   1140                 WakeupEvent e = new WakeupEvent(nowRTC,
   1141                         a.operation.getCreatorUid(),
   1142                         a.operation.getIntent().getAction());
   1143                 mRecentWakeups.add(e);
   1144             }
   1145         }
   1146     }
   1147 
   1148     private class AlarmThread extends Thread
   1149     {
   1150         public AlarmThread()
   1151         {
   1152             super("AlarmManager");
   1153         }
   1154 
   1155         public void run()
   1156         {
   1157             ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
   1158 
   1159             while (true)
   1160             {
   1161                 int result = waitForAlarm(mDescriptor);
   1162 
   1163                 triggerList.clear();
   1164 
   1165                 if ((result & TIME_CHANGED_MASK) != 0) {
   1166                     if (DEBUG_BATCH) {
   1167                         Slog.v(TAG, "Time changed notification from kernel; rebatching");
   1168                     }
   1169                     remove(mTimeTickSender);
   1170                     rebatchAllAlarms();
   1171                     mClockReceiver.scheduleTimeTickEvent();
   1172                     Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
   1173                     intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
   1174                             | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1175                     mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   1176                 }
   1177 
   1178                 synchronized (mLock) {
   1179                     final long nowRTC = System.currentTimeMillis();
   1180                     final long nowELAPSED = SystemClock.elapsedRealtime();
   1181                     if (localLOGV) Slog.v(
   1182                         TAG, "Checking for alarms... rtc=" + nowRTC
   1183                         + ", elapsed=" + nowELAPSED);
   1184 
   1185                     if (WAKEUP_STATS) {
   1186                         if ((result & IS_WAKEUP_MASK) != 0) {
   1187                             long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
   1188                             int n = 0;
   1189                             for (WakeupEvent event : mRecentWakeups) {
   1190                                 if (event.when > newEarliest) break;
   1191                                 n++; // number of now-stale entries at the list head
   1192                             }
   1193                             for (int i = 0; i < n; i++) {
   1194                                 mRecentWakeups.remove();
   1195                             }
   1196 
   1197                             recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);
   1198                         }
   1199                     }
   1200 
   1201                     triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
   1202                     rescheduleKernelAlarmsLocked();
   1203 
   1204                     // now deliver the alarm intents
   1205                     for (int i=0; i<triggerList.size(); i++) {
   1206                         Alarm alarm = triggerList.get(i);
   1207                         try {
   1208                             if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
   1209                             alarm.operation.send(mContext, 0,
   1210                                     mBackgroundIntent.putExtra(
   1211                                             Intent.EXTRA_ALARM_COUNT, alarm.count),
   1212                                     mResultReceiver, mHandler);
   1213 
   1214                             // we have an active broadcast so stay awake.
   1215                             if (mBroadcastRefCount == 0) {
   1216                                 setWakelockWorkSource(alarm.operation, alarm.workSource);
   1217                                 mWakeLock.acquire();
   1218                             }
   1219                             final InFlight inflight = new InFlight(AlarmManagerService.this,
   1220                                     alarm.operation, alarm.workSource);
   1221                             mInFlight.add(inflight);
   1222                             mBroadcastRefCount++;
   1223 
   1224                             final BroadcastStats bs = inflight.mBroadcastStats;
   1225                             bs.count++;
   1226                             if (bs.nesting == 0) {
   1227                                 bs.nesting = 1;
   1228                                 bs.startTime = nowELAPSED;
   1229                             } else {
   1230                                 bs.nesting++;
   1231                             }
   1232                             final FilterStats fs = inflight.mFilterStats;
   1233                             fs.count++;
   1234                             if (fs.nesting == 0) {
   1235                                 fs.nesting = 1;
   1236                                 fs.startTime = nowELAPSED;
   1237                             } else {
   1238                                 fs.nesting++;
   1239                             }
   1240                             if (alarm.type == ELAPSED_REALTIME_WAKEUP
   1241                                     || alarm.type == RTC_WAKEUP) {
   1242                                 bs.numWakeup++;
   1243                                 fs.numWakeup++;
   1244                                 ActivityManagerNative.noteWakeupAlarm(
   1245                                         alarm.operation);
   1246                             }
   1247                         } catch (PendingIntent.CanceledException e) {
   1248                             if (alarm.repeatInterval > 0) {
   1249                                 // This IntentSender is no longer valid, but this
   1250                                 // is a repeating alarm, so toss the hoser.
   1251                                 remove(alarm.operation);
   1252                             }
   1253                         } catch (RuntimeException e) {
   1254                             Slog.w(TAG, "Failure sending alarm.", e);
   1255                         }
   1256                     }
   1257                 }
   1258             }
   1259         }
   1260     }
   1261 
   1262     /**
   1263      * Attribute blame for a WakeLock.
   1264      * @param pi PendingIntent to attribute blame to if ws is null.
   1265      * @param ws WorkSource to attribute blame.
   1266      */
   1267     void setWakelockWorkSource(PendingIntent pi, WorkSource ws) {
   1268         try {
   1269             if (ws != null) {
   1270                 mWakeLock.setWorkSource(ws);
   1271                 return;
   1272             }
   1273 
   1274             final int uid = ActivityManagerNative.getDefault()
   1275                     .getUidForIntentSender(pi.getTarget());
   1276             if (uid >= 0) {
   1277                 mWakeLock.setWorkSource(new WorkSource(uid));
   1278                 return;
   1279             }
   1280         } catch (Exception e) {
   1281         }
   1282 
   1283         // Something went wrong; fall back to attributing the lock to the OS
   1284         mWakeLock.setWorkSource(null);
   1285     }
   1286 
   1287     private class AlarmHandler extends Handler {
   1288         public static final int ALARM_EVENT = 1;
   1289         public static final int MINUTE_CHANGE_EVENT = 2;
   1290         public static final int DATE_CHANGE_EVENT = 3;
   1291 
   1292         public AlarmHandler() {
   1293         }
   1294 
   1295         public void handleMessage(Message msg) {
   1296             if (msg.what == ALARM_EVENT) {
   1297                 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
   1298                 synchronized (mLock) {
   1299                     final long nowRTC = System.currentTimeMillis();
   1300                     final long nowELAPSED = SystemClock.elapsedRealtime();
   1301                     triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
   1302                 }
   1303 
   1304                 // now trigger the alarms without the lock held
   1305                 for (int i=0; i<triggerList.size(); i++) {
   1306                     Alarm alarm = triggerList.get(i);
   1307                     try {
   1308                         alarm.operation.send();
   1309                     } catch (PendingIntent.CanceledException e) {
   1310                         if (alarm.repeatInterval > 0) {
   1311                             // This IntentSender is no longer valid, but this
   1312                             // is a repeating alarm, so toss the hoser.
   1313                             remove(alarm.operation);
   1314                         }
   1315                     }
   1316                 }
   1317             }
   1318         }
   1319     }
   1320 
   1321     class ClockReceiver extends BroadcastReceiver {
   1322         public ClockReceiver() {
   1323             IntentFilter filter = new IntentFilter();
   1324             filter.addAction(Intent.ACTION_TIME_TICK);
   1325             filter.addAction(Intent.ACTION_DATE_CHANGED);
   1326             mContext.registerReceiver(this, filter);
   1327         }
   1328 
   1329         @Override
   1330         public void onReceive(Context context, Intent intent) {
   1331             if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
   1332                 if (DEBUG_BATCH) {
   1333                     Slog.v(TAG, "Received TIME_TICK alarm; rescheduling");
   1334                 }
   1335                 scheduleTimeTickEvent();
   1336             } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
   1337                 // Since the kernel does not keep track of DST, we need to
   1338                 // reset the TZ information at the beginning of each day
   1339                 // based off of the current Zone gmt offset + userspace tracked
   1340                 // daylight savings information.
   1341                 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
   1342                 int gmtOffset = zone.getOffset(System.currentTimeMillis());
   1343                 setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
   1344                 scheduleDateChangedEvent();
   1345             }
   1346         }
   1347 
   1348         public void scheduleTimeTickEvent() {
   1349             final long currentTime = System.currentTimeMillis();
   1350             final long nextTime = 60000 * ((currentTime / 60000) + 1);
   1351 
   1352             // Schedule this event for the amount of time that it would take to get to
   1353             // the top of the next minute.
   1354             final long tickEventDelay = nextTime - currentTime;
   1355 
   1356             final WorkSource workSource = null; // Let system take blame for time tick events.
   1357             set(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
   1358                     0, mTimeTickSender, true, workSource);
   1359         }
   1360 
   1361         public void scheduleDateChangedEvent() {
   1362             Calendar calendar = Calendar.getInstance();
   1363             calendar.setTimeInMillis(System.currentTimeMillis());
   1364             calendar.set(Calendar.HOUR, 0);
   1365             calendar.set(Calendar.MINUTE, 0);
   1366             calendar.set(Calendar.SECOND, 0);
   1367             calendar.set(Calendar.MILLISECOND, 0);
   1368             calendar.add(Calendar.DAY_OF_MONTH, 1);
   1369 
   1370             final WorkSource workSource = null; // Let system take blame for date change events.
   1371             set(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
   1372         }
   1373     }
   1374 
   1375     class UninstallReceiver extends BroadcastReceiver {
   1376         public UninstallReceiver() {
   1377             IntentFilter filter = new IntentFilter();
   1378             filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
   1379             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
   1380             filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
   1381             filter.addDataScheme("package");
   1382             mContext.registerReceiver(this, filter);
   1383              // Register for events related to sdcard installation.
   1384             IntentFilter sdFilter = new IntentFilter();
   1385             sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
   1386             sdFilter.addAction(Intent.ACTION_USER_STOPPED);
   1387             mContext.registerReceiver(this, sdFilter);
   1388         }
   1389 
   1390         @Override
   1391         public void onReceive(Context context, Intent intent) {
   1392             synchronized (mLock) {
   1393                 String action = intent.getAction();
   1394                 String pkgList[] = null;
   1395                 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
   1396                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
   1397                     for (String packageName : pkgList) {
   1398                         if (lookForPackageLocked(packageName)) {
   1399                             setResultCode(Activity.RESULT_OK);
   1400                             return;
   1401                         }
   1402                     }
   1403                     return;
   1404                 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
   1405                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
   1406                 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
   1407                     int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
   1408                     if (userHandle >= 0) {
   1409                         removeUserLocked(userHandle);
   1410                     }
   1411                 } else {
   1412                     if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
   1413                             && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
   1414                         // This package is being updated; don't kill its alarms.
   1415                         return;
   1416                     }
   1417                     Uri data = intent.getData();
   1418                     if (data != null) {
   1419                         String pkg = data.getSchemeSpecificPart();
   1420                         if (pkg != null) {
   1421                             pkgList = new String[]{pkg};
   1422                         }
   1423                     }
   1424                 }
   1425                 if (pkgList != null && (pkgList.length > 0)) {
   1426                     for (String pkg : pkgList) {
   1427                         removeLocked(pkg);
   1428                         mBroadcastStats.remove(pkg);
   1429                     }
   1430                 }
   1431             }
   1432         }
   1433     }
   1434 
   1435     private final BroadcastStats getStatsLocked(PendingIntent pi) {
   1436         String pkg = pi.getTargetPackage();
   1437         BroadcastStats bs = mBroadcastStats.get(pkg);
   1438         if (bs == null) {
   1439             bs = new BroadcastStats(pkg);
   1440             mBroadcastStats.put(pkg, bs);
   1441         }
   1442         return bs;
   1443     }
   1444 
   1445     class ResultReceiver implements PendingIntent.OnFinished {
   1446         public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
   1447                 String resultData, Bundle resultExtras) {
   1448             synchronized (mLock) {
   1449                 InFlight inflight = null;
   1450                 for (int i=0; i<mInFlight.size(); i++) {
   1451                     if (mInFlight.get(i).mPendingIntent == pi) {
   1452                         inflight = mInFlight.remove(i);
   1453                         break;
   1454                     }
   1455                 }
   1456                 if (inflight != null) {
   1457                     final long nowELAPSED = SystemClock.elapsedRealtime();
   1458                     BroadcastStats bs = inflight.mBroadcastStats;
   1459                     bs.nesting--;
   1460                     if (bs.nesting <= 0) {
   1461                         bs.nesting = 0;
   1462                         bs.aggregateTime += nowELAPSED - bs.startTime;
   1463                     }
   1464                     FilterStats fs = inflight.mFilterStats;
   1465                     fs.nesting--;
   1466                     if (fs.nesting <= 0) {
   1467                         fs.nesting = 0;
   1468                         fs.aggregateTime += nowELAPSED - fs.startTime;
   1469                     }
   1470                 } else {
   1471                     mLog.w("No in-flight alarm for " + pi + " " + intent);
   1472                 }
   1473                 mBroadcastRefCount--;
   1474                 if (mBroadcastRefCount == 0) {
   1475                     mWakeLock.release();
   1476                     if (mInFlight.size() > 0) {
   1477                         mLog.w("Finished all broadcasts with " + mInFlight.size()
   1478                                 + " remaining inflights");
   1479                         for (int i=0; i<mInFlight.size(); i++) {
   1480                             mLog.w("  Remaining #" + i + ": " + mInFlight.get(i));
   1481                         }
   1482                         mInFlight.clear();
   1483                     }
   1484                 } else {
   1485                     // the next of our alarms is now in flight.  reattribute the wakelock.
   1486                     if (mInFlight.size() > 0) {
   1487                         InFlight inFlight = mInFlight.get(0);
   1488                         setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource);
   1489                     } else {
   1490                         // should never happen
   1491                         mLog.w("Alarm wakelock still held but sent queue empty");
   1492                         mWakeLock.setWorkSource(null);
   1493                     }
   1494                 }
   1495             }
   1496         }
   1497     }
   1498 }
   1499