AlarmManagerService.java revision 1e38382b542f5cef9957a89692b02c55a3dd351c
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.Activity;
20import android.app.ActivityManager;
21import android.app.ActivityManagerNative;
22import android.app.AlarmManager;
23import android.app.IAlarmManager;
24import android.app.PendingIntent;
25import android.content.BroadcastReceiver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.pm.PackageManager;
30import android.net.Uri;
31import android.os.Binder;
32import android.os.Bundle;
33import android.os.Handler;
34import android.os.IBinder;
35import android.os.Message;
36import android.os.PowerManager;
37import android.os.Process;
38import android.os.SystemClock;
39import android.os.SystemProperties;
40import android.os.UserHandle;
41import android.os.WorkSource;
42import android.provider.Settings;
43import android.text.TextUtils;
44import android.text.format.DateFormat;
45import android.util.ArrayMap;
46import android.util.Log;
47import android.util.Slog;
48import android.util.SparseArray;
49import android.util.SparseBooleanArray;
50import android.util.TimeUtils;
51
52import java.io.ByteArrayOutputStream;
53import java.io.FileDescriptor;
54import java.io.PrintWriter;
55import java.text.SimpleDateFormat;
56import java.util.ArrayList;
57import java.util.Arrays;
58import java.util.Calendar;
59import java.util.Collections;
60import java.util.Comparator;
61import java.util.Date;
62import java.util.HashMap;
63import java.util.LinkedList;
64import java.util.Locale;
65import java.util.Random;
66import java.util.TimeZone;
67
68import static android.app.AlarmManager.RTC_WAKEUP;
69import static android.app.AlarmManager.RTC;
70import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
71import static android.app.AlarmManager.ELAPSED_REALTIME;
72
73import com.android.internal.util.LocalLog;
74
75class AlarmManagerService extends SystemService {
76    // The threshold for how long an alarm can be late before we print a
77    // warning message.  The time duration is in milliseconds.
78    private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
79
80    // Minimum futurity of a new alarm
81    private static final long MIN_FUTURITY = 5 * 1000;  // 5 seconds, in millis
82
83    // Minimum alarm recurrence interval
84    private static final long MIN_INTERVAL = 60 * 1000;  // one minute, in millis
85
86    private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
87    private static final int RTC_MASK = 1 << RTC;
88    private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
89    private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
90    static final int TIME_CHANGED_MASK = 1 << 16;
91    static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
92
93    // Mask for testing whether a given alarm type is wakeup vs non-wakeup
94    static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
95
96    static final String TAG = "AlarmManager";
97    static final String ClockReceiver_TAG = "ClockReceiver";
98    static final boolean localLOGV = false;
99    static final boolean DEBUG_BATCH = localLOGV || false;
100    static final boolean DEBUG_VALIDATE = localLOGV || false;
101    static final boolean DEBUG_ALARM_CLOCK = localLOGV || false;
102    static final boolean RECORD_ALARMS_IN_HISTORY = true;
103    static final int ALARM_EVENT = 1;
104    static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
105
106    static final Intent mBackgroundIntent
107            = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
108    static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
109
110    static final boolean WAKEUP_STATS = false;
111
112    private static final Intent NEXT_ALARM_CLOCK_CHANGED_INTENT = new Intent(
113            AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
114
115    final LocalLog mLog = new LocalLog(TAG);
116
117    final Object mLock = new Object();
118
119    long mNativeData;
120    private long mNextWakeup;
121    private long mNextNonWakeup;
122    int mBroadcastRefCount = 0;
123    PowerManager.WakeLock mWakeLock;
124    boolean mLastWakeLockUnimportantForLogging;
125    ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<Alarm>();
126    ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
127    final AlarmHandler mHandler = new AlarmHandler();
128    ClockReceiver mClockReceiver;
129    InteractiveStateReceiver mInteractiveStateReceiver;
130    private UninstallReceiver mUninstallReceiver;
131    final ResultReceiver mResultReceiver = new ResultReceiver();
132    PendingIntent mTimeTickSender;
133    PendingIntent mDateChangeSender;
134    Random mRandom;
135    boolean mInteractive = true;
136    long mNonInteractiveStartTime;
137    long mNonInteractiveTime;
138    long mLastAlarmDeliveryTime;
139    long mStartCurrentDelayTime;
140    long mNextNonWakeupDeliveryTime;
141    int mNumTimeChanged;
142
143    private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser =
144            new SparseArray<>();
145    private final SparseArray<AlarmManager.AlarmClockInfo> mTmpSparseAlarmClockArray =
146            new SparseArray<>();
147    private final SparseBooleanArray mPendingSendNextAlarmClockChangedForUser =
148            new SparseBooleanArray();
149    private boolean mNextAlarmClockMayChange;
150
151    // May only use on mHandler's thread, locking not required.
152    private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
153            new SparseArray<>();
154
155    // Alarm delivery ordering bookkeeping
156    static final int PRIO_TICK = 0;
157    static final int PRIO_WAKEUP = 1;
158    static final int PRIO_NORMAL = 2;
159
160    class PriorityClass {
161        int seq;
162        int priority;
163
164        PriorityClass() {
165            seq = mCurrentSeq - 1;
166            priority = PRIO_NORMAL;
167        }
168    }
169
170    final HashMap<String, PriorityClass> mPriorities =
171            new HashMap<String, PriorityClass>();
172    int mCurrentSeq = 0;
173
174    class WakeupEvent {
175        public long when;
176        public int uid;
177        public String action;
178
179        public WakeupEvent(long theTime, int theUid, String theAction) {
180            when = theTime;
181            uid = theUid;
182            action = theAction;
183        }
184    }
185
186    final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
187    final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
188
189    final class Batch {
190        long start;     // These endpoints are always in ELAPSED
191        long end;
192        int flags;      // Flags for alarms, such as FLAG_STANDALONE.
193
194        final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
195
196        Batch() {
197            start = 0;
198            end = Long.MAX_VALUE;
199            flags = 0;
200        }
201
202        Batch(Alarm seed) {
203            start = seed.whenElapsed;
204            end = seed.maxWhenElapsed;
205            flags = seed.flags;
206            alarms.add(seed);
207        }
208
209        int size() {
210            return alarms.size();
211        }
212
213        Alarm get(int index) {
214            return alarms.get(index);
215        }
216
217        boolean canHold(long whenElapsed, long maxWhen) {
218            return (end >= whenElapsed) && (start <= maxWhen);
219        }
220
221        boolean add(Alarm alarm) {
222            boolean newStart = false;
223            // narrows the batch if necessary; presumes that canHold(alarm) is true
224            int index = Collections.binarySearch(alarms, alarm, sIncreasingTimeOrder);
225            if (index < 0) {
226                index = 0 - index - 1;
227            }
228            alarms.add(index, alarm);
229            if (DEBUG_BATCH) {
230                Slog.v(TAG, "Adding " + alarm + " to " + this);
231            }
232            if (alarm.whenElapsed > start) {
233                start = alarm.whenElapsed;
234                newStart = true;
235            }
236            if (alarm.maxWhenElapsed < end) {
237                end = alarm.maxWhenElapsed;
238            }
239            flags |= alarm.flags;
240
241            if (DEBUG_BATCH) {
242                Slog.v(TAG, "    => now " + this);
243            }
244            return newStart;
245        }
246
247        boolean remove(final PendingIntent operation) {
248            boolean didRemove = false;
249            long newStart = 0;  // recalculate endpoints as we go
250            long newEnd = Long.MAX_VALUE;
251            int newFlags = 0;
252            for (int i = 0; i < alarms.size(); ) {
253                Alarm alarm = alarms.get(i);
254                if (alarm.operation.equals(operation)) {
255                    alarms.remove(i);
256                    didRemove = true;
257                    if (alarm.alarmClock != null) {
258                        mNextAlarmClockMayChange = true;
259                    }
260                } else {
261                    if (alarm.whenElapsed > newStart) {
262                        newStart = alarm.whenElapsed;
263                    }
264                    if (alarm.maxWhenElapsed < newEnd) {
265                        newEnd = alarm.maxWhenElapsed;
266                    }
267                    newFlags |= alarm.flags;
268                    i++;
269                }
270            }
271            if (didRemove) {
272                // commit the new batch bounds
273                start = newStart;
274                end = newEnd;
275                flags = newFlags;
276            }
277            return didRemove;
278        }
279
280        boolean remove(final String packageName) {
281            boolean didRemove = false;
282            long newStart = 0;  // recalculate endpoints as we go
283            long newEnd = Long.MAX_VALUE;
284            int newFlags = 0;
285            for (int i = 0; i < alarms.size(); ) {
286                Alarm alarm = alarms.get(i);
287                if (alarm.operation.getTargetPackage().equals(packageName)) {
288                    alarms.remove(i);
289                    didRemove = true;
290                    if (alarm.alarmClock != null) {
291                        mNextAlarmClockMayChange = true;
292                    }
293                } else {
294                    if (alarm.whenElapsed > newStart) {
295                        newStart = alarm.whenElapsed;
296                    }
297                    if (alarm.maxWhenElapsed < newEnd) {
298                        newEnd = alarm.maxWhenElapsed;
299                    }
300                    newFlags |= alarm.flags;
301                    i++;
302                }
303            }
304            if (didRemove) {
305                // commit the new batch bounds
306                start = newStart;
307                end = newEnd;
308                flags = newFlags;
309            }
310            return didRemove;
311        }
312
313        boolean remove(final int userHandle) {
314            boolean didRemove = false;
315            long newStart = 0;  // recalculate endpoints as we go
316            long newEnd = Long.MAX_VALUE;
317            for (int i = 0; i < alarms.size(); ) {
318                Alarm alarm = alarms.get(i);
319                if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
320                    alarms.remove(i);
321                    didRemove = true;
322                    if (alarm.alarmClock != null) {
323                        mNextAlarmClockMayChange = true;
324                    }
325                } else {
326                    if (alarm.whenElapsed > newStart) {
327                        newStart = alarm.whenElapsed;
328                    }
329                    if (alarm.maxWhenElapsed < newEnd) {
330                        newEnd = alarm.maxWhenElapsed;
331                    }
332                    i++;
333                }
334            }
335            if (didRemove) {
336                // commit the new batch bounds
337                start = newStart;
338                end = newEnd;
339            }
340            return didRemove;
341        }
342
343        boolean hasPackage(final String packageName) {
344            final int N = alarms.size();
345            for (int i = 0; i < N; i++) {
346                Alarm a = alarms.get(i);
347                if (a.operation.getTargetPackage().equals(packageName)) {
348                    return true;
349                }
350            }
351            return false;
352        }
353
354        boolean hasWakeups() {
355            final int N = alarms.size();
356            for (int i = 0; i < N; i++) {
357                Alarm a = alarms.get(i);
358                // non-wakeup alarms are types 1 and 3, i.e. have the low bit set
359                if ((a.type & TYPE_NONWAKEUP_MASK) == 0) {
360                    return true;
361                }
362            }
363            return false;
364        }
365
366        @Override
367        public String toString() {
368            StringBuilder b = new StringBuilder(40);
369            b.append("Batch{"); b.append(Integer.toHexString(this.hashCode()));
370            b.append(" num="); b.append(size());
371            b.append(" start="); b.append(start);
372            b.append(" end="); b.append(end);
373            if (flags != 0) {
374                b.append(" flgs=0x");
375                b.append(Integer.toHexString(flags));
376            }
377            b.append('}');
378            return b.toString();
379        }
380    }
381
382    static class BatchTimeOrder implements Comparator<Batch> {
383        public int compare(Batch b1, Batch b2) {
384            long when1 = b1.start;
385            long when2 = b2.start;
386            if (when1 - when2 > 0) {
387                return 1;
388            }
389            if (when1 - when2 < 0) {
390                return -1;
391            }
392            return 0;
393        }
394    }
395
396    final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
397        @Override
398        public int compare(Alarm lhs, Alarm rhs) {
399            // priority class trumps everything.  TICK < WAKEUP < NORMAL
400            if (lhs.priorityClass.priority < rhs.priorityClass.priority) {
401                return -1;
402            } else if (lhs.priorityClass.priority > rhs.priorityClass.priority) {
403                return 1;
404            }
405
406            // within each class, sort by nominal delivery time
407            if (lhs.whenElapsed < rhs.whenElapsed) {
408                return -1;
409            } else if (lhs.whenElapsed > rhs.whenElapsed) {
410                return 1;
411            }
412
413            // same priority class + same target delivery time
414            return 0;
415        }
416    };
417
418    void calculateDeliveryPriorities(ArrayList<Alarm> alarms) {
419        final int N = alarms.size();
420        for (int i = 0; i < N; i++) {
421            Alarm a = alarms.get(i);
422
423            final int alarmPrio;
424            if (Intent.ACTION_TIME_TICK.equals(a.operation.getIntent().getAction())) {
425                alarmPrio = PRIO_TICK;
426            } else if (a.wakeup) {
427                alarmPrio = PRIO_WAKEUP;
428            } else {
429                alarmPrio = PRIO_NORMAL;
430            }
431
432            PriorityClass packagePrio = a.priorityClass;
433            if (packagePrio == null) packagePrio = mPriorities.get(a.operation.getCreatorPackage());
434            if (packagePrio == null) {
435                packagePrio = a.priorityClass = new PriorityClass(); // lowest prio & stale sequence
436                mPriorities.put(a.operation.getCreatorPackage(), packagePrio);
437            }
438            a.priorityClass = packagePrio;
439
440            if (packagePrio.seq != mCurrentSeq) {
441                // first alarm we've seen in the current delivery generation from this package
442                packagePrio.priority = alarmPrio;
443                packagePrio.seq = mCurrentSeq;
444            } else {
445                // Multiple alarms from this package being delivered in this generation;
446                // bump the package's delivery class if it's warranted.
447                // TICK < WAKEUP < NORMAL
448                if (alarmPrio < packagePrio.priority) {
449                    packagePrio.priority = alarmPrio;
450                }
451            }
452        }
453    }
454
455    // minimum recurrence period or alarm futurity for us to be able to fuzz it
456    static final long MIN_FUZZABLE_INTERVAL = 10000;
457    static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
458    final ArrayList<Batch> mAlarmBatches = new ArrayList<>();
459
460    // set to null if in idle mode; while in this mode, any alarms we don't want
461    // to run during this time are placed in mPendingWhileIdleAlarms
462    Alarm mPendingIdleUntil = null;
463    final ArrayList<Alarm> mPendingWhileIdleAlarms = new ArrayList<>();
464
465    public AlarmManagerService(Context context) {
466        super(context);
467    }
468
469    static long convertToElapsed(long when, int type) {
470        final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
471        if (isRtc) {
472            when -= System.currentTimeMillis() - SystemClock.elapsedRealtime();
473        }
474        return when;
475    }
476
477    // Apply a heuristic to { recurrence interval, futurity of the trigger time } to
478    // calculate the end of our nominal delivery window for the alarm.
479    static long maxTriggerTime(long now, long triggerAtTime, long interval) {
480        // Current heuristic: batchable window is 75% of either the recurrence interval
481        // [for a periodic alarm] or of the time from now to the desired delivery time,
482        // with a minimum delay/interval of 10 seconds, under which we will simply not
483        // defer the alarm.
484        long futurity = (interval == 0)
485                ? (triggerAtTime - now)
486                : interval;
487        if (futurity < MIN_FUZZABLE_INTERVAL) {
488            futurity = 0;
489        }
490        return triggerAtTime + (long)(.75 * futurity);
491    }
492
493    // returns true if the batch was added at the head
494    static boolean addBatchLocked(ArrayList<Batch> list, Batch newBatch) {
495        int index = Collections.binarySearch(list, newBatch, sBatchOrder);
496        if (index < 0) {
497            index = 0 - index - 1;
498        }
499        list.add(index, newBatch);
500        return (index == 0);
501    }
502
503    // Return the index of the matching batch, or -1 if none found.
504    int attemptCoalesceLocked(long whenElapsed, long maxWhen) {
505        final int N = mAlarmBatches.size();
506        for (int i = 0; i < N; i++) {
507            Batch b = mAlarmBatches.get(i);
508            if ((b.flags&AlarmManager.FLAG_STANDALONE) == 0 && b.canHold(whenElapsed, maxWhen)) {
509                return i;
510            }
511        }
512        return -1;
513    }
514
515    // The RTC clock has moved arbitrarily, so we need to recalculate all the batching
516    void rebatchAllAlarms() {
517        synchronized (mLock) {
518            rebatchAllAlarmsLocked(true);
519        }
520    }
521
522    void rebatchAllAlarmsLocked(boolean doValidate) {
523        ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone();
524        mAlarmBatches.clear();
525        Alarm oldPendingIdleUntil = mPendingIdleUntil;
526        final long nowElapsed = SystemClock.elapsedRealtime();
527        final int oldBatches = oldSet.size();
528        for (int batchNum = 0; batchNum < oldBatches; batchNum++) {
529            Batch batch = oldSet.get(batchNum);
530            final int N = batch.size();
531            for (int i = 0; i < N; i++) {
532                reAddAlarmLocked(batch.get(i), nowElapsed, doValidate);
533            }
534        }
535        if (oldPendingIdleUntil != null && oldPendingIdleUntil != mPendingIdleUntil) {
536            Slog.wtf(TAG, "Rebatching: idle until changed from " + oldPendingIdleUntil
537                    + " to " + mPendingIdleUntil);
538            if (mPendingIdleUntil == null) {
539                // Somehow we lost this...  we need to restore all of the pending alarms.
540                restorePendingWhileIdleAlarmsLocked();
541            }
542        }
543        rescheduleKernelAlarmsLocked();
544        updateNextAlarmClockLocked();
545    }
546
547    void reAddAlarmLocked(Alarm a, long nowElapsed, boolean doValidate) {
548        a.when = a.origWhen;
549        long whenElapsed = convertToElapsed(a.when, a.type);
550        final long maxElapsed;
551        if (a.whenElapsed == a.maxWhenElapsed) {
552            // Exact
553            maxElapsed = whenElapsed;
554        } else {
555            // Not exact.  Preserve any explicit window, otherwise recalculate
556            // the window based on the alarm's new futurity.  Note that this
557            // reflects a policy of preferring timely to deferred delivery.
558            maxElapsed = (a.windowLength > 0)
559                    ? (whenElapsed + a.windowLength)
560                    : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
561        }
562        a.whenElapsed = whenElapsed;
563        a.maxWhenElapsed = maxElapsed;
564        setImplLocked(a, true, doValidate);
565    }
566
567    void restorePendingWhileIdleAlarmsLocked() {
568        final long nowElapsed = SystemClock.elapsedRealtime();
569        for (int i=mPendingWhileIdleAlarms.size() - 1; i >= 0 && mPendingIdleUntil != null; i --) {
570            Alarm a = mPendingWhileIdleAlarms.remove(i);
571            reAddAlarmLocked(a, nowElapsed, false);
572        }
573        rescheduleKernelAlarmsLocked();
574        updateNextAlarmClockLocked();
575    }
576
577    static final class InFlight extends Intent {
578        final PendingIntent mPendingIntent;
579        final WorkSource mWorkSource;
580        final String mTag;
581        final BroadcastStats mBroadcastStats;
582        final FilterStats mFilterStats;
583        final int mAlarmType;
584
585        InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource,
586                int alarmType, String tag) {
587            mPendingIntent = pendingIntent;
588            mWorkSource = workSource;
589            mTag = tag;
590            mBroadcastStats = service.getStatsLocked(pendingIntent);
591            FilterStats fs = mBroadcastStats.filterStats.get(mTag);
592            if (fs == null) {
593                fs = new FilterStats(mBroadcastStats, mTag);
594                mBroadcastStats.filterStats.put(mTag, fs);
595            }
596            mFilterStats = fs;
597            mAlarmType = alarmType;
598        }
599    }
600
601    static final class FilterStats {
602        final BroadcastStats mBroadcastStats;
603        final String mTag;
604
605        long aggregateTime;
606        int count;
607        int numWakeup;
608        long startTime;
609        int nesting;
610
611        FilterStats(BroadcastStats broadcastStats, String tag) {
612            mBroadcastStats = broadcastStats;
613            mTag = tag;
614        }
615    }
616
617    static final class BroadcastStats {
618        final int mUid;
619        final String mPackageName;
620
621        long aggregateTime;
622        int count;
623        int numWakeup;
624        long startTime;
625        int nesting;
626        final ArrayMap<String, FilterStats> filterStats = new ArrayMap<String, FilterStats>();
627
628        BroadcastStats(int uid, String packageName) {
629            mUid = uid;
630            mPackageName = packageName;
631        }
632    }
633
634    final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
635            = new SparseArray<ArrayMap<String, BroadcastStats>>();
636
637    int mNumDelayedAlarms = 0;
638    long mTotalDelayTime = 0;
639    long mMaxDelayTime = 0;
640
641    @Override
642    public void onStart() {
643        mNativeData = init();
644        mNextWakeup = mNextNonWakeup = 0;
645
646        // We have to set current TimeZone info to kernel
647        // because kernel doesn't keep this after reboot
648        setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
649
650        PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
651        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
652
653        mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
654                new Intent(Intent.ACTION_TIME_TICK).addFlags(
655                        Intent.FLAG_RECEIVER_REGISTERED_ONLY
656                        | Intent.FLAG_RECEIVER_FOREGROUND), 0,
657                        UserHandle.ALL);
658        Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
659        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
660        mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
661                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
662
663        // now that we have initied the driver schedule the alarm
664        mClockReceiver = new ClockReceiver();
665        mClockReceiver.scheduleTimeTickEvent();
666        mClockReceiver.scheduleDateChangedEvent();
667        mInteractiveStateReceiver = new InteractiveStateReceiver();
668        mUninstallReceiver = new UninstallReceiver();
669
670        if (mNativeData != 0) {
671            AlarmThread waitThread = new AlarmThread();
672            waitThread.start();
673        } else {
674            Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
675        }
676
677        publishBinderService(Context.ALARM_SERVICE, mService);
678    }
679
680    @Override
681    protected void finalize() throws Throwable {
682        try {
683            close(mNativeData);
684        } finally {
685            super.finalize();
686        }
687    }
688
689    void setTimeZoneImpl(String tz) {
690        if (TextUtils.isEmpty(tz)) {
691            return;
692        }
693
694        TimeZone zone = TimeZone.getTimeZone(tz);
695        // Prevent reentrant calls from stepping on each other when writing
696        // the time zone property
697        boolean timeZoneWasChanged = false;
698        synchronized (this) {
699            String current = SystemProperties.get(TIMEZONE_PROPERTY);
700            if (current == null || !current.equals(zone.getID())) {
701                if (localLOGV) {
702                    Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
703                }
704                timeZoneWasChanged = true;
705                SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
706            }
707
708            // Update the kernel timezone information
709            // Kernel tracks time offsets as 'minutes west of GMT'
710            int gmtOffset = zone.getOffset(System.currentTimeMillis());
711            setKernelTimezone(mNativeData, -(gmtOffset / 60000));
712        }
713
714        TimeZone.setDefault(null);
715
716        if (timeZoneWasChanged) {
717            Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
718            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
719            intent.putExtra("time-zone", zone.getID());
720            getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
721        }
722    }
723
724    void removeImpl(PendingIntent operation) {
725        if (operation == null) {
726            return;
727        }
728        synchronized (mLock) {
729            removeLocked(operation);
730        }
731    }
732
733    void setImpl(int type, long triggerAtTime, long windowLength, long interval,
734            PendingIntent operation, int flags, WorkSource workSource,
735            AlarmManager.AlarmClockInfo alarmClock) {
736        if (operation == null) {
737            Slog.w(TAG, "set/setRepeating ignored because there is no intent");
738            return;
739        }
740
741        // Sanity check the window length.  This will catch people mistakenly
742        // trying to pass an end-of-window timestamp rather than a duration.
743        if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
744            Slog.w(TAG, "Window length " + windowLength
745                    + "ms suspiciously long; limiting to 1 hour");
746            windowLength = AlarmManager.INTERVAL_HOUR;
747        }
748
749        // Sanity check the recurrence interval.  This will catch people who supply
750        // seconds when the API expects milliseconds.
751        if (interval > 0 && interval < MIN_INTERVAL) {
752            Slog.w(TAG, "Suspiciously short interval " + interval
753                    + " millis; expanding to " + (int)(MIN_INTERVAL/1000)
754                    + " seconds");
755            interval = MIN_INTERVAL;
756        }
757
758        if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
759            throw new IllegalArgumentException("Invalid alarm type " + type);
760        }
761
762        if (triggerAtTime < 0) {
763            final long who = Binder.getCallingUid();
764            final long what = Binder.getCallingPid();
765            Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who
766                    + " pid=" + what);
767            triggerAtTime = 0;
768        }
769
770        final long nowElapsed = SystemClock.elapsedRealtime();
771        final long nominalTrigger = convertToElapsed(triggerAtTime, type);
772        // Try to prevent spamming by making sure we aren't firing alarms in the immediate future
773        final long minTrigger = nowElapsed + MIN_FUTURITY;
774        final long triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger;
775
776        final long maxElapsed;
777        if (windowLength == AlarmManager.WINDOW_EXACT) {
778            maxElapsed = triggerElapsed;
779        } else if (windowLength < 0) {
780            maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
781        } else {
782            maxElapsed = triggerElapsed + windowLength;
783        }
784
785        final int userId = UserHandle.getCallingUserId();
786
787        synchronized (mLock) {
788            if (DEBUG_BATCH) {
789                Slog.v(TAG, "set(" + operation + ") : type=" + type
790                        + " triggerAtTime=" + triggerAtTime + " win=" + windowLength
791                        + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
792                        + " interval=" + interval + " flags=0x" + Integer.toHexString(flags));
793            }
794            setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
795                    interval, operation, flags, true, workSource, alarmClock, userId);
796        }
797    }
798
799    private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
800            long maxWhen, long interval, PendingIntent operation, int flags,
801            boolean doValidate, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
802            int userId) {
803        Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
804                operation, workSource, flags, alarmClock, userId);
805        removeLocked(operation);
806        setImplLocked(a, false, doValidate);
807    }
808
809    private void setImplLocked(Alarm a, boolean rebatching, boolean doValidate) {
810        if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
811            // This is a special alarm that will put the system idle until it goes off.
812            // The caller has given the time they want this to happen at, however we need
813            // to pull that earlier if there are existing alarms that have requested to
814            // bring us out of idle.
815            final int N = mAlarmBatches.size();
816            for (int i = 0; i < N; i++) {
817                Batch b = mAlarmBatches.get(i);
818                if (a.whenElapsed > b.end) {
819                    // There are no interesting things happening before our idle until,
820                    // so keep the requested time.
821                    break;
822                }
823                if ((b.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
824                    a.when = a.whenElapsed = a.maxWhenElapsed = b.end;
825                    break;
826                }
827            }
828            // Add fuzz to make the alarm go off some time before the actual desired time.
829            final long nowElapsed = SystemClock.elapsedRealtime();
830            long fuzz = fuzzForDuration(a.whenElapsed-nowElapsed);
831            if (fuzz > 0) {
832                if (mRandom == null) {
833                    mRandom = new Random();
834                }
835                a.whenElapsed -= mRandom.nextLong() % fuzz;
836            }
837
838        } else if (mPendingIdleUntil != null) {
839            // We currently have an idle until alarm scheduled; if the new alarm has
840            // not explicitly stated it wants to run while idle, then put it on hold.
841            if ((a.flags&(AlarmManager.FLAG_ALLOW_WHILE_IDLE|AlarmManager.FLAG_WAKE_FROM_IDLE))
842                    == 0) {
843                mPendingWhileIdleAlarms.add(a);
844                return;
845            }
846        }
847
848        int whichBatch = ((a.flags&AlarmManager.FLAG_STANDALONE) != 0)
849                ? -1 : attemptCoalesceLocked(a.whenElapsed, a.maxWhenElapsed);
850        if (whichBatch < 0) {
851            Batch batch = new Batch(a);
852            addBatchLocked(mAlarmBatches, batch);
853        } else {
854            Batch batch = mAlarmBatches.get(whichBatch);
855            if (batch.add(a)) {
856                // The start time of this batch advanced, so batch ordering may
857                // have just been broken.  Move it to where it now belongs.
858                mAlarmBatches.remove(whichBatch);
859                addBatchLocked(mAlarmBatches, batch);
860            }
861        }
862
863        if (a.alarmClock != null) {
864            mNextAlarmClockMayChange = true;
865        }
866
867        boolean needRebatch = false;
868
869        if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
870            mPendingIdleUntil = a;
871            needRebatch = true;
872        } else if ((a.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0 && mPendingIdleUntil != null) {
873            // If we are adding an alarm that asks to wake from idle, and we are currently
874            // idling, then we need to rebatch alarms in case the idle until time needs to
875            // be updated.
876            needRebatch = true;
877        }
878
879        if (!rebatching) {
880            if (DEBUG_VALIDATE) {
881                if (doValidate && !validateConsistencyLocked()) {
882                    Slog.v(TAG, "Tipping-point operation: type=" + a.type + " when=" + a.when
883                            + " when(hex)=" + Long.toHexString(a.when)
884                            + " whenElapsed=" + a.whenElapsed
885                            + " maxWhenElapsed=" + a.maxWhenElapsed
886                            + " interval=" + a.repeatInterval + " op=" + a.operation
887                            + " flags=0x" + Integer.toHexString(a.flags));
888                    rebatchAllAlarmsLocked(false);
889                    needRebatch = false;
890                }
891            }
892
893            if (needRebatch) {
894                rebatchAllAlarmsLocked(false);
895            }
896
897            rescheduleKernelAlarmsLocked();
898            updateNextAlarmClockLocked();
899        }
900    }
901
902    private final IBinder mService = new IAlarmManager.Stub() {
903        @Override
904        public void set(int type, long triggerAtTime, long windowLength, long interval, int flags,
905                PendingIntent operation, WorkSource workSource,
906                AlarmManager.AlarmClockInfo alarmClock) {
907            if (workSource != null) {
908                getContext().enforceCallingPermission(
909                        android.Manifest.permission.UPDATE_DEVICE_STATS,
910                        "AlarmManager.set");
911            }
912
913            if (windowLength == AlarmManager.WINDOW_EXACT) {
914                flags |= AlarmManager.FLAG_STANDALONE;
915            }
916            if (alarmClock != null) {
917                flags |= AlarmManager.FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE;
918            }
919            if (Binder.getCallingUid() < Process.FIRST_APPLICATION_UID) {
920                flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE;
921            }
922            setImpl(type, triggerAtTime, windowLength, interval, operation,
923                    flags, workSource, alarmClock);
924        }
925
926        @Override
927        public boolean setTime(long millis) {
928            getContext().enforceCallingOrSelfPermission(
929                    "android.permission.SET_TIME",
930                    "setTime");
931
932            if (mNativeData == 0) {
933                Slog.w(TAG, "Not setting time since no alarm driver is available.");
934                return false;
935            }
936
937            synchronized (mLock) {
938                return setKernelTime(mNativeData, millis) == 0;
939            }
940        }
941
942        @Override
943        public void setTimeZone(String tz) {
944            getContext().enforceCallingOrSelfPermission(
945                    "android.permission.SET_TIME_ZONE",
946                    "setTimeZone");
947
948            final long oldId = Binder.clearCallingIdentity();
949            try {
950                setTimeZoneImpl(tz);
951            } finally {
952                Binder.restoreCallingIdentity(oldId);
953            }
954        }
955
956        @Override
957        public void remove(PendingIntent operation) {
958            removeImpl(operation);
959
960        }
961
962        @Override
963        public AlarmManager.AlarmClockInfo getNextAlarmClock(int userId) {
964            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
965                    Binder.getCallingUid(), userId, false /* allowAll */, false /* requireFull */,
966                    "getNextAlarmClock", null);
967
968            return getNextAlarmClockImpl(userId);
969        }
970
971        @Override
972        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
973            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
974                    != PackageManager.PERMISSION_GRANTED) {
975                pw.println("Permission Denial: can't dump AlarmManager from from pid="
976                        + Binder.getCallingPid()
977                        + ", uid=" + Binder.getCallingUid());
978                return;
979            }
980
981            dumpImpl(pw);
982        }
983    };
984
985    void dumpImpl(PrintWriter pw) {
986        synchronized (mLock) {
987            pw.println("Current Alarm Manager state:");
988            final long nowRTC = System.currentTimeMillis();
989            final long nowELAPSED = SystemClock.elapsedRealtime();
990            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
991
992            pw.print("nowRTC="); pw.print(nowRTC);
993            pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
994            pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw);
995            pw.println();
996            if (!mInteractive) {
997                pw.print("Time since non-interactive: ");
998                TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw);
999                pw.println();
1000                pw.print("Max wakeup delay: ");
1001                TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw);
1002                pw.println();
1003                pw.print("Time since last dispatch: ");
1004                TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw);
1005                pw.println();
1006                pw.print("Next non-wakeup delivery time: ");
1007                TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw);
1008                pw.println();
1009            }
1010
1011            long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
1012            long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
1013            pw.print("Next non-wakeup alarm: ");
1014                    TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw);
1015                    pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
1016            pw.print("Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
1017                    pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
1018            pw.print("Num time change events: "); pw.println(mNumTimeChanged);
1019
1020            if (mAlarmBatches.size() > 0) {
1021                pw.println();
1022                pw.print("Pending alarm batches: ");
1023                pw.println(mAlarmBatches.size());
1024                for (Batch b : mAlarmBatches) {
1025                    pw.print(b); pw.println(':');
1026                    dumpAlarmList(pw, b.alarms, "  ", nowELAPSED, nowRTC, sdf);
1027                }
1028            }
1029            if (mPendingIdleUntil != null) {
1030                pw.println();
1031                pw.println("Idle mode state:");
1032                pw.print("  Idling until: "); pw.println(mPendingIdleUntil);
1033                mPendingIdleUntil.dump(pw, "    ", nowELAPSED, nowRTC, sdf);
1034                pw.println("  Pending alarms:");
1035                dumpAlarmList(pw, mPendingWhileIdleAlarms, "    ", nowELAPSED, nowRTC, sdf);
1036            }
1037
1038            pw.println();
1039            pw.print("Past-due non-wakeup alarms: ");
1040            if (mPendingNonWakeupAlarms.size() > 0) {
1041                pw.println(mPendingNonWakeupAlarms.size());
1042                dumpAlarmList(pw, mPendingNonWakeupAlarms, "  ", nowELAPSED, nowRTC, sdf);
1043            } else {
1044                pw.println("(none)");
1045            }
1046            pw.print("  Number of delayed alarms: "); pw.print(mNumDelayedAlarms);
1047            pw.print(", total delay time: "); TimeUtils.formatDuration(mTotalDelayTime, pw);
1048            pw.println();
1049            pw.print("  Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw);
1050            pw.print(", max non-interactive time: ");
1051            TimeUtils.formatDuration(mNonInteractiveTime, pw);
1052            pw.println();
1053
1054            pw.println();
1055            pw.print("  Broadcast ref count: "); pw.println(mBroadcastRefCount);
1056            pw.println();
1057
1058            if (mLog.dump(pw, "  Recent problems", "    ")) {
1059                pw.println();
1060            }
1061
1062            final FilterStats[] topFilters = new FilterStats[10];
1063            final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
1064                @Override
1065                public int compare(FilterStats lhs, FilterStats rhs) {
1066                    if (lhs.aggregateTime < rhs.aggregateTime) {
1067                        return 1;
1068                    } else if (lhs.aggregateTime > rhs.aggregateTime) {
1069                        return -1;
1070                    }
1071                    return 0;
1072                }
1073            };
1074            int len = 0;
1075            for (int iu=0; iu<mBroadcastStats.size(); iu++) {
1076                ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
1077                for (int ip=0; ip<uidStats.size(); ip++) {
1078                    BroadcastStats bs = uidStats.valueAt(ip);
1079                    for (int is=0; is<bs.filterStats.size(); is++) {
1080                        FilterStats fs = bs.filterStats.valueAt(is);
1081                        int pos = len > 0
1082                                ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
1083                        if (pos < 0) {
1084                            pos = -pos - 1;
1085                        }
1086                        if (pos < topFilters.length) {
1087                            int copylen = topFilters.length - pos - 1;
1088                            if (copylen > 0) {
1089                                System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
1090                            }
1091                            topFilters[pos] = fs;
1092                            if (len < topFilters.length) {
1093                                len++;
1094                            }
1095                        }
1096                    }
1097                }
1098            }
1099            if (len > 0) {
1100                pw.println("  Top Alarms:");
1101                for (int i=0; i<len; i++) {
1102                    FilterStats fs = topFilters[i];
1103                    pw.print("    ");
1104                    if (fs.nesting > 0) pw.print("*ACTIVE* ");
1105                    TimeUtils.formatDuration(fs.aggregateTime, pw);
1106                    pw.print(" running, "); pw.print(fs.numWakeup);
1107                    pw.print(" wakeups, "); pw.print(fs.count);
1108                    pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid);
1109                    pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName);
1110                    pw.println();
1111                    pw.print("      "); pw.print(fs.mTag);
1112                    pw.println();
1113                }
1114            }
1115
1116            pw.println(" ");
1117            pw.println("  Alarm Stats:");
1118            final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
1119            for (int iu=0; iu<mBroadcastStats.size(); iu++) {
1120                ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
1121                for (int ip=0; ip<uidStats.size(); ip++) {
1122                    BroadcastStats bs = uidStats.valueAt(ip);
1123                    pw.print("  ");
1124                    if (bs.nesting > 0) pw.print("*ACTIVE* ");
1125                    UserHandle.formatUid(pw, bs.mUid);
1126                    pw.print(":");
1127                    pw.print(bs.mPackageName);
1128                    pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
1129                            pw.print(" running, "); pw.print(bs.numWakeup);
1130                            pw.println(" wakeups:");
1131                    tmpFilters.clear();
1132                    for (int is=0; is<bs.filterStats.size(); is++) {
1133                        tmpFilters.add(bs.filterStats.valueAt(is));
1134                    }
1135                    Collections.sort(tmpFilters, comparator);
1136                    for (int i=0; i<tmpFilters.size(); i++) {
1137                        FilterStats fs = tmpFilters.get(i);
1138                        pw.print("    ");
1139                                if (fs.nesting > 0) pw.print("*ACTIVE* ");
1140                                TimeUtils.formatDuration(fs.aggregateTime, pw);
1141                                pw.print(" "); pw.print(fs.numWakeup);
1142                                pw.print(" wakes " ); pw.print(fs.count);
1143                                pw.print(" alarms: ");
1144                                pw.print(fs.mTag);
1145                                pw.println();
1146                    }
1147                }
1148            }
1149
1150            if (WAKEUP_STATS) {
1151                pw.println();
1152                pw.println("  Recent Wakeup History:");
1153                long last = -1;
1154                for (WakeupEvent event : mRecentWakeups) {
1155                    pw.print("    "); pw.print(sdf.format(new Date(event.when)));
1156                    pw.print('|');
1157                    if (last < 0) {
1158                        pw.print('0');
1159                    } else {
1160                        pw.print(event.when - last);
1161                    }
1162                    last = event.when;
1163                    pw.print('|'); pw.print(event.uid);
1164                    pw.print('|'); pw.print(event.action);
1165                    pw.println();
1166                }
1167                pw.println();
1168            }
1169        }
1170    }
1171
1172    private void logBatchesLocked(SimpleDateFormat sdf) {
1173        ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
1174        PrintWriter pw = new PrintWriter(bs);
1175        final long nowRTC = System.currentTimeMillis();
1176        final long nowELAPSED = SystemClock.elapsedRealtime();
1177        final int NZ = mAlarmBatches.size();
1178        for (int iz = 0; iz < NZ; iz++) {
1179            Batch bz = mAlarmBatches.get(iz);
1180            pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
1181            dumpAlarmList(pw, bz.alarms, "  ", nowELAPSED, nowRTC, sdf);
1182            pw.flush();
1183            Slog.v(TAG, bs.toString());
1184            bs.reset();
1185        }
1186    }
1187
1188    private boolean validateConsistencyLocked() {
1189        if (DEBUG_VALIDATE) {
1190            long lastTime = Long.MIN_VALUE;
1191            final int N = mAlarmBatches.size();
1192            for (int i = 0; i < N; i++) {
1193                Batch b = mAlarmBatches.get(i);
1194                if (b.start >= lastTime) {
1195                    // duplicate start times are okay because of standalone batches
1196                    lastTime = b.start;
1197                } else {
1198                    Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
1199                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
1200                    logBatchesLocked(sdf);
1201                    return false;
1202                }
1203            }
1204        }
1205        return true;
1206    }
1207
1208    private Batch findFirstWakeupBatchLocked() {
1209        final int N = mAlarmBatches.size();
1210        for (int i = 0; i < N; i++) {
1211            Batch b = mAlarmBatches.get(i);
1212            if (b.hasWakeups()) {
1213                return b;
1214            }
1215        }
1216        return null;
1217    }
1218
1219    private AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
1220        synchronized (mLock) {
1221            return mNextAlarmClockForUser.get(userId);
1222        }
1223    }
1224
1225    /**
1226     * Recomputes the next alarm clock for all users.
1227     */
1228    private void updateNextAlarmClockLocked() {
1229        if (!mNextAlarmClockMayChange) {
1230            return;
1231        }
1232        mNextAlarmClockMayChange = false;
1233
1234        SparseArray<AlarmManager.AlarmClockInfo> nextForUser = mTmpSparseAlarmClockArray;
1235        nextForUser.clear();
1236
1237        final int N = mAlarmBatches.size();
1238        for (int i = 0; i < N; i++) {
1239            ArrayList<Alarm> alarms = mAlarmBatches.get(i).alarms;
1240            final int M = alarms.size();
1241
1242            for (int j = 0; j < M; j++) {
1243                Alarm a = alarms.get(j);
1244                if (a.alarmClock != null) {
1245                    final int userId = a.userId;
1246
1247                    if (DEBUG_ALARM_CLOCK) {
1248                        Log.v(TAG, "Found AlarmClockInfo at " +
1249                                formatNextAlarm(getContext(), a.alarmClock, userId) +
1250                                " for user " + userId);
1251                    }
1252
1253                    // Alarms and batches are sorted by time, no need to compare times here.
1254                    if (nextForUser.get(userId) == null) {
1255                        nextForUser.put(userId, a.alarmClock);
1256                    }
1257                }
1258            }
1259        }
1260
1261        // Update mNextAlarmForUser with new values.
1262        final int NN = nextForUser.size();
1263        for (int i = 0; i < NN; i++) {
1264            AlarmManager.AlarmClockInfo newAlarm = nextForUser.valueAt(i);
1265            int userId = nextForUser.keyAt(i);
1266            AlarmManager.AlarmClockInfo currentAlarm = mNextAlarmClockForUser.get(userId);
1267            if (!newAlarm.equals(currentAlarm)) {
1268                updateNextAlarmInfoForUserLocked(userId, newAlarm);
1269            }
1270        }
1271
1272        // Remove users without any alarm clocks scheduled.
1273        final int NNN = mNextAlarmClockForUser.size();
1274        for (int i = NNN - 1; i >= 0; i--) {
1275            int userId = mNextAlarmClockForUser.keyAt(i);
1276            if (nextForUser.get(userId) == null) {
1277                updateNextAlarmInfoForUserLocked(userId, null);
1278            }
1279        }
1280    }
1281
1282    private void updateNextAlarmInfoForUserLocked(int userId,
1283            AlarmManager.AlarmClockInfo alarmClock) {
1284        if (alarmClock != null) {
1285            if (DEBUG_ALARM_CLOCK) {
1286                Log.v(TAG, "Next AlarmClockInfoForUser(" + userId + "): " +
1287                        formatNextAlarm(getContext(), alarmClock, userId));
1288            }
1289            mNextAlarmClockForUser.put(userId, alarmClock);
1290        } else {
1291            if (DEBUG_ALARM_CLOCK) {
1292                Log.v(TAG, "Next AlarmClockInfoForUser(" + userId + "): None");
1293            }
1294            mNextAlarmClockForUser.remove(userId);
1295        }
1296
1297        mPendingSendNextAlarmClockChangedForUser.put(userId, true);
1298        mHandler.removeMessages(AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED);
1299        mHandler.sendEmptyMessage(AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED);
1300    }
1301
1302    /**
1303     * Updates NEXT_ALARM_FORMATTED and sends NEXT_ALARM_CLOCK_CHANGED_INTENT for all users
1304     * for which alarm clocks have changed since the last call to this.
1305     *
1306     * Do not call with a lock held. Only call from mHandler's thread.
1307     *
1308     * @see AlarmHandler#SEND_NEXT_ALARM_CLOCK_CHANGED
1309     */
1310    private void sendNextAlarmClockChanged() {
1311        SparseArray<AlarmManager.AlarmClockInfo> pendingUsers = mHandlerSparseAlarmClockArray;
1312        pendingUsers.clear();
1313
1314        synchronized (mLock) {
1315            final int N  = mPendingSendNextAlarmClockChangedForUser.size();
1316            for (int i = 0; i < N; i++) {
1317                int userId = mPendingSendNextAlarmClockChangedForUser.keyAt(i);
1318                pendingUsers.append(userId, mNextAlarmClockForUser.get(userId));
1319            }
1320            mPendingSendNextAlarmClockChangedForUser.clear();
1321        }
1322
1323        final int N = pendingUsers.size();
1324        for (int i = 0; i < N; i++) {
1325            int userId = pendingUsers.keyAt(i);
1326            AlarmManager.AlarmClockInfo alarmClock = pendingUsers.valueAt(i);
1327            Settings.System.putStringForUser(getContext().getContentResolver(),
1328                    Settings.System.NEXT_ALARM_FORMATTED,
1329                    formatNextAlarm(getContext(), alarmClock, userId),
1330                    userId);
1331
1332            getContext().sendBroadcastAsUser(NEXT_ALARM_CLOCK_CHANGED_INTENT,
1333                    new UserHandle(userId));
1334        }
1335    }
1336
1337    /**
1338     * Formats an alarm like platform/packages/apps/DeskClock used to.
1339     */
1340    private static String formatNextAlarm(final Context context, AlarmManager.AlarmClockInfo info,
1341            int userId) {
1342        String skeleton = DateFormat.is24HourFormat(context, userId) ? "EHm" : "Ehma";
1343        String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
1344        return (info == null) ? "" :
1345                DateFormat.format(pattern, info.getTriggerTime()).toString();
1346    }
1347
1348    void rescheduleKernelAlarmsLocked() {
1349        // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
1350        // prior to that which contains no wakeups, we schedule that as well.
1351        long nextNonWakeup = 0;
1352        if (mAlarmBatches.size() > 0) {
1353            final Batch firstWakeup = findFirstWakeupBatchLocked();
1354            final Batch firstBatch = mAlarmBatches.get(0);
1355            // always update the kernel alarms, as a backstop against missed wakeups
1356            if (firstWakeup != null) {
1357                mNextWakeup = firstWakeup.start;
1358                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
1359            }
1360            if (firstBatch != firstWakeup) {
1361                nextNonWakeup = firstBatch.start;
1362            }
1363        }
1364        if (mPendingNonWakeupAlarms.size() > 0) {
1365            if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) {
1366                nextNonWakeup = mNextNonWakeupDeliveryTime;
1367            }
1368        }
1369        // always update the kernel alarm, as a backstop against missed wakeups
1370        if (nextNonWakeup != 0) {
1371            mNextNonWakeup = nextNonWakeup;
1372            setLocked(ELAPSED_REALTIME, nextNonWakeup);
1373        }
1374    }
1375
1376    private void removeLocked(PendingIntent operation) {
1377        boolean didRemove = false;
1378        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1379            Batch b = mAlarmBatches.get(i);
1380            didRemove |= b.remove(operation);
1381            if (b.size() == 0) {
1382                mAlarmBatches.remove(i);
1383            }
1384        }
1385        for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
1386            if (mPendingWhileIdleAlarms.get(i).operation.equals(operation)) {
1387                // Don't set didRemove, since this doesn't impact the scheduled alarms.
1388                mPendingWhileIdleAlarms.remove(i);
1389            }
1390        }
1391
1392        if (didRemove) {
1393            if (DEBUG_BATCH) {
1394                Slog.v(TAG, "remove(operation) changed bounds; rebatching");
1395            }
1396            boolean restorePending = false;
1397            if (mPendingIdleUntil != null && mPendingIdleUntil.operation.equals(operation)) {
1398                mPendingIdleUntil = null;
1399                restorePending = true;
1400            }
1401            rebatchAllAlarmsLocked(true);
1402            if (restorePending) {
1403                restorePendingWhileIdleAlarmsLocked();
1404            }
1405            updateNextAlarmClockLocked();
1406        }
1407    }
1408
1409    void removeLocked(String packageName) {
1410        boolean didRemove = false;
1411        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1412            Batch b = mAlarmBatches.get(i);
1413            didRemove |= b.remove(packageName);
1414            if (b.size() == 0) {
1415                mAlarmBatches.remove(i);
1416            }
1417        }
1418        for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
1419            if (mPendingWhileIdleAlarms.get(i).operation.getTargetPackage().equals(packageName)) {
1420                // Don't set didRemove, since this doesn't impact the scheduled alarms.
1421                mPendingWhileIdleAlarms.remove(i);
1422            }
1423        }
1424
1425        if (didRemove) {
1426            if (DEBUG_BATCH) {
1427                Slog.v(TAG, "remove(package) changed bounds; rebatching");
1428            }
1429            rebatchAllAlarmsLocked(true);
1430            rescheduleKernelAlarmsLocked();
1431            updateNextAlarmClockLocked();
1432        }
1433    }
1434
1435    void removeUserLocked(int userHandle) {
1436        boolean didRemove = false;
1437        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1438            Batch b = mAlarmBatches.get(i);
1439            didRemove |= b.remove(userHandle);
1440            if (b.size() == 0) {
1441                mAlarmBatches.remove(i);
1442            }
1443        }
1444        for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
1445            if (UserHandle.getUserId(mPendingWhileIdleAlarms.get(i).operation.getCreatorUid())
1446                    == userHandle) {
1447                // Don't set didRemove, since this doesn't impact the scheduled alarms.
1448                mPendingWhileIdleAlarms.remove(i);
1449            }
1450        }
1451
1452        if (didRemove) {
1453            if (DEBUG_BATCH) {
1454                Slog.v(TAG, "remove(user) changed bounds; rebatching");
1455            }
1456            rebatchAllAlarmsLocked(true);
1457            rescheduleKernelAlarmsLocked();
1458            updateNextAlarmClockLocked();
1459        }
1460    }
1461
1462    void interactiveStateChangedLocked(boolean interactive) {
1463        if (mInteractive != interactive) {
1464            mInteractive = interactive;
1465            final long nowELAPSED = SystemClock.elapsedRealtime();
1466            if (interactive) {
1467                if (mPendingNonWakeupAlarms.size() > 0) {
1468                    final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
1469                    mTotalDelayTime += thisDelayTime;
1470                    if (mMaxDelayTime < thisDelayTime) {
1471                        mMaxDelayTime = thisDelayTime;
1472                    }
1473                    deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED);
1474                    mPendingNonWakeupAlarms.clear();
1475                }
1476                if (mNonInteractiveStartTime > 0) {
1477                    long dur = nowELAPSED - mNonInteractiveStartTime;
1478                    if (dur > mNonInteractiveTime) {
1479                        mNonInteractiveTime = dur;
1480                    }
1481                }
1482            } else {
1483                mNonInteractiveStartTime = nowELAPSED;
1484            }
1485        }
1486    }
1487
1488    boolean lookForPackageLocked(String packageName) {
1489        for (int i = 0; i < mAlarmBatches.size(); i++) {
1490            Batch b = mAlarmBatches.get(i);
1491            if (b.hasPackage(packageName)) {
1492                return true;
1493            }
1494        }
1495        for (int i = 0; i < mPendingWhileIdleAlarms.size(); i++) {
1496            if (mPendingWhileIdleAlarms.get(i).operation.getTargetPackage().equals(packageName)) {
1497                return true;
1498            }
1499        }
1500        return false;
1501    }
1502
1503    private void setLocked(int type, long when) {
1504        if (mNativeData != 0) {
1505            // The kernel never triggers alarms with negative wakeup times
1506            // so we ensure they are positive.
1507            long alarmSeconds, alarmNanoseconds;
1508            if (when < 0) {
1509                alarmSeconds = 0;
1510                alarmNanoseconds = 0;
1511            } else {
1512                alarmSeconds = when / 1000;
1513                alarmNanoseconds = (when % 1000) * 1000 * 1000;
1514            }
1515
1516            set(mNativeData, type, alarmSeconds, alarmNanoseconds);
1517        } else {
1518            Message msg = Message.obtain();
1519            msg.what = ALARM_EVENT;
1520
1521            mHandler.removeMessages(ALARM_EVENT);
1522            mHandler.sendMessageAtTime(msg, when);
1523        }
1524    }
1525
1526    private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
1527            String prefix, String label, long nowRTC, long nowELAPSED, SimpleDateFormat sdf) {
1528        for (int i=list.size()-1; i>=0; i--) {
1529            Alarm a = list.get(i);
1530            pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
1531                    pw.print(": "); pw.println(a);
1532            a.dump(pw, prefix + "  ", nowRTC, nowELAPSED, sdf);
1533        }
1534    }
1535
1536    private static final String labelForType(int type) {
1537        switch (type) {
1538        case RTC: return "RTC";
1539        case RTC_WAKEUP : return "RTC_WAKEUP";
1540        case ELAPSED_REALTIME : return "ELAPSED";
1541        case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
1542        default:
1543            break;
1544        }
1545        return "--unknown--";
1546    }
1547
1548    private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
1549            String prefix, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) {
1550        for (int i=list.size()-1; i>=0; i--) {
1551            Alarm a = list.get(i);
1552            final String label = labelForType(a.type);
1553            pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
1554                    pw.print(": "); pw.println(a);
1555            a.dump(pw, prefix + "  ", nowRTC, nowELAPSED, sdf);
1556        }
1557    }
1558
1559    private native long init();
1560    private native void close(long nativeData);
1561    private native void set(long nativeData, int type, long seconds, long nanoseconds);
1562    private native int waitForAlarm(long nativeData);
1563    private native int setKernelTime(long nativeData, long millis);
1564    private native int setKernelTimezone(long nativeData, int minuteswest);
1565
1566    boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
1567            final long nowRTC) {
1568        boolean hasWakeup = false;
1569        // batches are temporally sorted, so we need only pull from the
1570        // start of the list until we either empty it or hit a batch
1571        // that is not yet deliverable
1572        while (mAlarmBatches.size() > 0) {
1573            Batch batch = mAlarmBatches.get(0);
1574            if (batch.start > nowELAPSED) {
1575                // Everything else is scheduled for the future
1576                break;
1577            }
1578
1579            // We will (re)schedule some alarms now; don't let that interfere
1580            // with delivery of this current batch
1581            mAlarmBatches.remove(0);
1582
1583            final int N = batch.size();
1584            for (int i = 0; i < N; i++) {
1585                Alarm alarm = batch.get(i);
1586                alarm.count = 1;
1587                triggerList.add(alarm);
1588                if (mPendingIdleUntil == alarm) {
1589                    mPendingIdleUntil = null;
1590                    rebatchAllAlarmsLocked(false);
1591                    restorePendingWhileIdleAlarmsLocked();
1592                }
1593
1594                // Recurring alarms may have passed several alarm intervals while the
1595                // phone was asleep or off, so pass a trigger count when sending them.
1596                if (alarm.repeatInterval > 0) {
1597                    // this adjustment will be zero if we're late by
1598                    // less than one full repeat interval
1599                    alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval;
1600
1601                    // Also schedule its next recurrence
1602                    final long delta = alarm.count * alarm.repeatInterval;
1603                    final long nextElapsed = alarm.whenElapsed + delta;
1604                    setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
1605                            maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
1606                            alarm.repeatInterval, alarm.operation, alarm.flags, true,
1607                            alarm.workSource, alarm.alarmClock, alarm.userId);
1608                }
1609
1610                if (alarm.wakeup) {
1611                    hasWakeup = true;
1612                }
1613
1614                // We removed an alarm clock. Let the caller recompute the next alarm clock.
1615                if (alarm.alarmClock != null) {
1616                    mNextAlarmClockMayChange = true;
1617                }
1618            }
1619        }
1620
1621        // This is a new alarm delivery set; bump the sequence number to indicate that
1622        // all apps' alarm delivery classes should be recalculated.
1623        mCurrentSeq++;
1624        calculateDeliveryPriorities(triggerList);
1625        Collections.sort(triggerList, mAlarmDispatchComparator);
1626
1627        if (localLOGV) {
1628            for (int i=0; i<triggerList.size(); i++) {
1629                Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i));
1630            }
1631        }
1632
1633        return hasWakeup;
1634    }
1635
1636    /**
1637     * This Comparator sorts Alarms into increasing time order.
1638     */
1639    public static class IncreasingTimeOrder implements Comparator<Alarm> {
1640        public int compare(Alarm a1, Alarm a2) {
1641            long when1 = a1.when;
1642            long when2 = a2.when;
1643            if (when1 - when2 > 0) {
1644                return 1;
1645            }
1646            if (when1 - when2 < 0) {
1647                return -1;
1648            }
1649            return 0;
1650        }
1651    }
1652
1653    private static class Alarm {
1654        public final int type;
1655        public final long origWhen;
1656        public final boolean wakeup;
1657        public final PendingIntent operation;
1658        public final String  tag;
1659        public final WorkSource workSource;
1660        public final int flags;
1661        public int count;
1662        public long when;
1663        public long windowLength;
1664        public long whenElapsed;    // 'when' in the elapsed time base
1665        public long maxWhenElapsed; // also in the elapsed time base
1666        public long repeatInterval;
1667        public final AlarmManager.AlarmClockInfo alarmClock;
1668        public final int userId;
1669        public PriorityClass priorityClass;
1670
1671        public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
1672                long _interval, PendingIntent _op, WorkSource _ws, int _flags,
1673                AlarmManager.AlarmClockInfo _info, int _userId) {
1674            type = _type;
1675            origWhen = _when;
1676            wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
1677                    || _type == AlarmManager.RTC_WAKEUP;
1678            when = _when;
1679            whenElapsed = _whenElapsed;
1680            windowLength = _windowLength;
1681            maxWhenElapsed = _maxWhen;
1682            repeatInterval = _interval;
1683            operation = _op;
1684            tag = makeTag(_op, _type);
1685            workSource = _ws;
1686            flags = _flags;
1687            alarmClock = _info;
1688            userId = _userId;
1689        }
1690
1691        public static String makeTag(PendingIntent pi, int type) {
1692            return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
1693                    ? "*walarm*:" : "*alarm*:");
1694        }
1695
1696        @Override
1697        public String toString() {
1698            StringBuilder sb = new StringBuilder(128);
1699            sb.append("Alarm{");
1700            sb.append(Integer.toHexString(System.identityHashCode(this)));
1701            sb.append(" type ");
1702            sb.append(type);
1703            sb.append(" when ");
1704            sb.append(when);
1705            sb.append(" ");
1706            sb.append(operation.getTargetPackage());
1707            sb.append('}');
1708            return sb.toString();
1709        }
1710
1711        public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED,
1712                SimpleDateFormat sdf) {
1713            final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
1714            pw.print(prefix); pw.print("tag="); pw.println(tag);
1715            pw.print(prefix); pw.print("type="); pw.print(type);
1716                    pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
1717                            nowELAPSED, pw);
1718                    if (isRtc) {
1719                        pw.print(" when="); pw.print(sdf.format(new Date(when)));
1720                    } else {
1721                        pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw);
1722                    }
1723                    pw.println();
1724            pw.print(prefix); pw.print("window="); pw.print(windowLength);
1725                    pw.print(" repeatInterval="); pw.print(repeatInterval);
1726                    pw.print(" count="); pw.print(count);
1727                    pw.print(" flags=0x"); pw.println(Integer.toHexString(flags));
1728            pw.print(prefix); pw.print("operation="); pw.println(operation);
1729        }
1730    }
1731
1732    void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) {
1733        final int numBatches = batches.size();
1734        for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) {
1735            Batch b = batches.get(nextBatch);
1736            if (b.start > nowELAPSED) {
1737                break;
1738            }
1739
1740            final int numAlarms = b.alarms.size();
1741            for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) {
1742                Alarm a = b.alarms.get(nextAlarm);
1743                WakeupEvent e = new WakeupEvent(nowRTC,
1744                        a.operation.getCreatorUid(),
1745                        a.operation.getIntent().getAction());
1746                mRecentWakeups.add(e);
1747            }
1748        }
1749    }
1750
1751    long currentNonWakeupFuzzLocked(long nowELAPSED) {
1752        long timeSinceOn = nowELAPSED - mNonInteractiveStartTime;
1753        if (timeSinceOn < 5*60*1000) {
1754            // If the screen has been off for 5 minutes, only delay by at most two minutes.
1755            return 2*60*1000;
1756        } else if (timeSinceOn < 30*60*1000) {
1757            // If the screen has been off for 30 minutes, only delay by at most 15 minutes.
1758            return 15*60*1000;
1759        } else {
1760            // Otherwise, we will delay by at most an hour.
1761            return 60*60*1000;
1762        }
1763    }
1764
1765    static long fuzzForDuration(long duration) {
1766        if (duration < 15*60*1000) {
1767            // If the duration until the time is less than 15 minutes, the maximum fuzz
1768            // is the duration.
1769            return duration;
1770        } else if (duration < 90*60*1000) {
1771            // If duration is less than 1 1/2 hours, the maximum fuzz is 15 minutes,
1772            return 15*60*1000;
1773        } else {
1774            // Otherwise, we will fuzz by at most half an hour.
1775            return 30*60*1000;
1776        }
1777    }
1778
1779    boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) {
1780        if (mInteractive) {
1781            return false;
1782        }
1783        if (mLastAlarmDeliveryTime <= 0) {
1784            return false;
1785        }
1786        if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime < nowELAPSED) {
1787            // This is just a little paranoia, if somehow we have pending non-wakeup alarms
1788            // and the next delivery time is in the past, then just deliver them all.  This
1789            // avoids bugs where we get stuck in a loop trying to poll for alarms.
1790            return false;
1791        }
1792        long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime;
1793        return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED);
1794    }
1795
1796    void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) {
1797        mLastAlarmDeliveryTime = nowELAPSED;
1798        for (int i=0; i<triggerList.size(); i++) {
1799            Alarm alarm = triggerList.get(i);
1800            try {
1801                if (localLOGV) {
1802                    Slog.v(TAG, "sending alarm " + alarm);
1803                }
1804                if (RECORD_ALARMS_IN_HISTORY) {
1805                    if (alarm.workSource != null && alarm.workSource.size() > 0) {
1806                        for (int wi=0; wi<alarm.workSource.size(); wi++) {
1807                            ActivityManagerNative.noteAlarmStart(
1808                                    alarm.operation, alarm.workSource.get(wi), alarm.tag);
1809                        }
1810                    } else {
1811                        ActivityManagerNative.noteAlarmStart(
1812                                alarm.operation, -1, alarm.tag);
1813                    }
1814                }
1815                alarm.operation.send(getContext(), 0,
1816                        mBackgroundIntent.putExtra(
1817                                Intent.EXTRA_ALARM_COUNT, alarm.count),
1818                        mResultReceiver, mHandler);
1819
1820                // we have an active broadcast so stay awake.
1821                if (mBroadcastRefCount == 0) {
1822                    setWakelockWorkSource(alarm.operation, alarm.workSource,
1823                            alarm.type, alarm.tag, true);
1824                    mWakeLock.acquire();
1825                }
1826                final InFlight inflight = new InFlight(AlarmManagerService.this,
1827                        alarm.operation, alarm.workSource, alarm.type, alarm.tag);
1828                mInFlight.add(inflight);
1829                mBroadcastRefCount++;
1830
1831                final BroadcastStats bs = inflight.mBroadcastStats;
1832                bs.count++;
1833                if (bs.nesting == 0) {
1834                    bs.nesting = 1;
1835                    bs.startTime = nowELAPSED;
1836                } else {
1837                    bs.nesting++;
1838                }
1839                final FilterStats fs = inflight.mFilterStats;
1840                fs.count++;
1841                if (fs.nesting == 0) {
1842                    fs.nesting = 1;
1843                    fs.startTime = nowELAPSED;
1844                } else {
1845                    fs.nesting++;
1846                }
1847                if (alarm.type == ELAPSED_REALTIME_WAKEUP
1848                        || alarm.type == RTC_WAKEUP) {
1849                    bs.numWakeup++;
1850                    fs.numWakeup++;
1851                    if (alarm.workSource != null && alarm.workSource.size() > 0) {
1852                        for (int wi=0; wi<alarm.workSource.size(); wi++) {
1853                            ActivityManagerNative.noteWakeupAlarm(
1854                                    alarm.operation, alarm.workSource.get(wi),
1855                                    alarm.workSource.getName(wi), alarm.tag);
1856                        }
1857                    } else {
1858                        ActivityManagerNative.noteWakeupAlarm(
1859                                alarm.operation, -1, null, alarm.tag);
1860                    }
1861                }
1862            } catch (PendingIntent.CanceledException e) {
1863                if (alarm.repeatInterval > 0) {
1864                    // This IntentSender is no longer valid, but this
1865                    // is a repeating alarm, so toss the hoser.
1866                    removeImpl(alarm.operation);
1867                }
1868            } catch (RuntimeException e) {
1869                Slog.w(TAG, "Failure sending alarm.", e);
1870            }
1871        }
1872    }
1873
1874    private class AlarmThread extends Thread
1875    {
1876        public AlarmThread()
1877        {
1878            super("AlarmManager");
1879        }
1880
1881        public void run()
1882        {
1883            ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
1884
1885            while (true)
1886            {
1887                int result = waitForAlarm(mNativeData);
1888
1889                triggerList.clear();
1890
1891                if ((result & TIME_CHANGED_MASK) != 0) {
1892                    if (DEBUG_BATCH) {
1893                        Slog.v(TAG, "Time changed notification from kernel; rebatching");
1894                    }
1895                    removeImpl(mTimeTickSender);
1896                    rebatchAllAlarms();
1897                    mClockReceiver.scheduleTimeTickEvent();
1898                    synchronized (mLock) {
1899                        mNumTimeChanged++;
1900                    }
1901                    Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
1902                    intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
1903                            | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1904                    getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
1905                }
1906
1907                synchronized (mLock) {
1908                    final long nowRTC = System.currentTimeMillis();
1909                    final long nowELAPSED = SystemClock.elapsedRealtime();
1910                    if (localLOGV) Slog.v(
1911                        TAG, "Checking for alarms... rtc=" + nowRTC
1912                        + ", elapsed=" + nowELAPSED);
1913
1914                    if (WAKEUP_STATS) {
1915                        if ((result & IS_WAKEUP_MASK) != 0) {
1916                            long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
1917                            int n = 0;
1918                            for (WakeupEvent event : mRecentWakeups) {
1919                                if (event.when > newEarliest) break;
1920                                n++; // number of now-stale entries at the list head
1921                            }
1922                            for (int i = 0; i < n; i++) {
1923                                mRecentWakeups.remove();
1924                            }
1925
1926                            recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);
1927                        }
1928                    }
1929
1930                    boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
1931                    if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
1932                        // if there are no wakeup alarms and the screen is off, we can
1933                        // delay what we have so far until the future.
1934                        if (mPendingNonWakeupAlarms.size() == 0) {
1935                            mStartCurrentDelayTime = nowELAPSED;
1936                            mNextNonWakeupDeliveryTime = nowELAPSED
1937                                    + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2);
1938                        }
1939                        mPendingNonWakeupAlarms.addAll(triggerList);
1940                        mNumDelayedAlarms += triggerList.size();
1941                        rescheduleKernelAlarmsLocked();
1942                        updateNextAlarmClockLocked();
1943                    } else {
1944                        // now deliver the alarm intents; if there are pending non-wakeup
1945                        // alarms, we need to merge them in to the list.  note we don't
1946                        // just deliver them first because we generally want non-wakeup
1947                        // alarms delivered after wakeup alarms.
1948                        rescheduleKernelAlarmsLocked();
1949                        updateNextAlarmClockLocked();
1950                        if (mPendingNonWakeupAlarms.size() > 0) {
1951                            calculateDeliveryPriorities(mPendingNonWakeupAlarms);
1952                            triggerList.addAll(mPendingNonWakeupAlarms);
1953                            Collections.sort(triggerList, mAlarmDispatchComparator);
1954                            final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
1955                            mTotalDelayTime += thisDelayTime;
1956                            if (mMaxDelayTime < thisDelayTime) {
1957                                mMaxDelayTime = thisDelayTime;
1958                            }
1959                            mPendingNonWakeupAlarms.clear();
1960                        }
1961                        deliverAlarmsLocked(triggerList, nowELAPSED);
1962                    }
1963                }
1964            }
1965        }
1966    }
1967
1968    /**
1969     * Attribute blame for a WakeLock.
1970     * @param pi PendingIntent to attribute blame to if ws is null.
1971     * @param ws WorkSource to attribute blame.
1972     */
1973    void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag,
1974            boolean first) {
1975        try {
1976            final boolean unimportant = pi == mTimeTickSender;
1977            mWakeLock.setUnimportantForLogging(unimportant);
1978            if (first || mLastWakeLockUnimportantForLogging) {
1979                mWakeLock.setHistoryTag(tag);
1980            } else {
1981                mWakeLock.setHistoryTag(null);
1982            }
1983            mLastWakeLockUnimportantForLogging = unimportant;
1984            if (ws != null) {
1985                mWakeLock.setWorkSource(ws);
1986                return;
1987            }
1988
1989            final int uid = ActivityManagerNative.getDefault()
1990                    .getUidForIntentSender(pi.getTarget());
1991            if (uid >= 0) {
1992                mWakeLock.setWorkSource(new WorkSource(uid));
1993                return;
1994            }
1995        } catch (Exception e) {
1996        }
1997
1998        // Something went wrong; fall back to attributing the lock to the OS
1999        mWakeLock.setWorkSource(null);
2000    }
2001
2002    private class AlarmHandler extends Handler {
2003        public static final int ALARM_EVENT = 1;
2004        public static final int MINUTE_CHANGE_EVENT = 2;
2005        public static final int DATE_CHANGE_EVENT = 3;
2006        public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 4;
2007
2008        public AlarmHandler() {
2009        }
2010
2011        public void handleMessage(Message msg) {
2012            if (msg.what == ALARM_EVENT) {
2013                ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
2014                synchronized (mLock) {
2015                    final long nowRTC = System.currentTimeMillis();
2016                    final long nowELAPSED = SystemClock.elapsedRealtime();
2017                    triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
2018                    updateNextAlarmClockLocked();
2019                }
2020
2021                // now trigger the alarms without the lock held
2022                for (int i=0; i<triggerList.size(); i++) {
2023                    Alarm alarm = triggerList.get(i);
2024                    try {
2025                        alarm.operation.send();
2026                    } catch (PendingIntent.CanceledException e) {
2027                        if (alarm.repeatInterval > 0) {
2028                            // This IntentSender is no longer valid, but this
2029                            // is a repeating alarm, so toss the hoser.
2030                            removeImpl(alarm.operation);
2031                        }
2032                    }
2033                }
2034            } else if (msg.what == SEND_NEXT_ALARM_CLOCK_CHANGED) {
2035                sendNextAlarmClockChanged();
2036            }
2037        }
2038    }
2039
2040    class ClockReceiver extends BroadcastReceiver {
2041        public ClockReceiver() {
2042            IntentFilter filter = new IntentFilter();
2043            filter.addAction(Intent.ACTION_TIME_TICK);
2044            filter.addAction(Intent.ACTION_DATE_CHANGED);
2045            getContext().registerReceiver(this, filter);
2046        }
2047
2048        @Override
2049        public void onReceive(Context context, Intent intent) {
2050            if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
2051                if (DEBUG_BATCH) {
2052                    Slog.v(TAG, "Received TIME_TICK alarm; rescheduling");
2053                }
2054                scheduleTimeTickEvent();
2055            } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
2056                // Since the kernel does not keep track of DST, we need to
2057                // reset the TZ information at the beginning of each day
2058                // based off of the current Zone gmt offset + userspace tracked
2059                // daylight savings information.
2060                TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
2061                int gmtOffset = zone.getOffset(System.currentTimeMillis());
2062                setKernelTimezone(mNativeData, -(gmtOffset / 60000));
2063                scheduleDateChangedEvent();
2064            }
2065        }
2066
2067        public void scheduleTimeTickEvent() {
2068            final long currentTime = System.currentTimeMillis();
2069            final long nextTime = 60000 * ((currentTime / 60000) + 1);
2070
2071            // Schedule this event for the amount of time that it would take to get to
2072            // the top of the next minute.
2073            final long tickEventDelay = nextTime - currentTime;
2074
2075            final WorkSource workSource = null; // Let system take blame for time tick events.
2076            setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
2077                    0, mTimeTickSender, AlarmManager.FLAG_STANDALONE, workSource, null);
2078        }
2079
2080        public void scheduleDateChangedEvent() {
2081            Calendar calendar = Calendar.getInstance();
2082            calendar.setTimeInMillis(System.currentTimeMillis());
2083            calendar.set(Calendar.HOUR, 0);
2084            calendar.set(Calendar.MINUTE, 0);
2085            calendar.set(Calendar.SECOND, 0);
2086            calendar.set(Calendar.MILLISECOND, 0);
2087            calendar.add(Calendar.DAY_OF_MONTH, 1);
2088
2089            final WorkSource workSource = null; // Let system take blame for date change events.
2090            setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender,
2091                    AlarmManager.FLAG_STANDALONE, workSource, null);
2092        }
2093    }
2094
2095    class InteractiveStateReceiver extends BroadcastReceiver {
2096        public InteractiveStateReceiver() {
2097            IntentFilter filter = new IntentFilter();
2098            filter.addAction(Intent.ACTION_SCREEN_OFF);
2099            filter.addAction(Intent.ACTION_SCREEN_ON);
2100            filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
2101            getContext().registerReceiver(this, filter);
2102        }
2103
2104        @Override
2105        public void onReceive(Context context, Intent intent) {
2106            synchronized (mLock) {
2107                interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
2108            }
2109        }
2110    }
2111
2112    class UninstallReceiver extends BroadcastReceiver {
2113        public UninstallReceiver() {
2114            IntentFilter filter = new IntentFilter();
2115            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
2116            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
2117            filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
2118            filter.addDataScheme("package");
2119            getContext().registerReceiver(this, filter);
2120             // Register for events related to sdcard installation.
2121            IntentFilter sdFilter = new IntentFilter();
2122            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
2123            sdFilter.addAction(Intent.ACTION_USER_STOPPED);
2124            getContext().registerReceiver(this, sdFilter);
2125        }
2126
2127        @Override
2128        public void onReceive(Context context, Intent intent) {
2129            synchronized (mLock) {
2130                String action = intent.getAction();
2131                String pkgList[] = null;
2132                if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
2133                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
2134                    for (String packageName : pkgList) {
2135                        if (lookForPackageLocked(packageName)) {
2136                            setResultCode(Activity.RESULT_OK);
2137                            return;
2138                        }
2139                    }
2140                    return;
2141                } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
2142                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
2143                } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
2144                    int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
2145                    if (userHandle >= 0) {
2146                        removeUserLocked(userHandle);
2147                    }
2148                } else {
2149                    if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
2150                            && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
2151                        // This package is being updated; don't kill its alarms.
2152                        return;
2153                    }
2154                    Uri data = intent.getData();
2155                    if (data != null) {
2156                        String pkg = data.getSchemeSpecificPart();
2157                        if (pkg != null) {
2158                            pkgList = new String[]{pkg};
2159                        }
2160                    }
2161                }
2162                if (pkgList != null && (pkgList.length > 0)) {
2163                    for (String pkg : pkgList) {
2164                        removeLocked(pkg);
2165                        mPriorities.remove(pkg);
2166                        for (int i=mBroadcastStats.size()-1; i>=0; i--) {
2167                            ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
2168                            if (uidStats.remove(pkg) != null) {
2169                                if (uidStats.size() <= 0) {
2170                                    mBroadcastStats.removeAt(i);
2171                                }
2172                            }
2173                        }
2174                    }
2175                }
2176            }
2177        }
2178    }
2179
2180    private final BroadcastStats getStatsLocked(PendingIntent pi) {
2181        String pkg = pi.getCreatorPackage();
2182        int uid = pi.getCreatorUid();
2183        ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid);
2184        if (uidStats == null) {
2185            uidStats = new ArrayMap<String, BroadcastStats>();
2186            mBroadcastStats.put(uid, uidStats);
2187        }
2188        BroadcastStats bs = uidStats.get(pkg);
2189        if (bs == null) {
2190            bs = new BroadcastStats(uid, pkg);
2191            uidStats.put(pkg, bs);
2192        }
2193        return bs;
2194    }
2195
2196    class ResultReceiver implements PendingIntent.OnFinished {
2197        public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
2198                String resultData, Bundle resultExtras) {
2199            synchronized (mLock) {
2200                InFlight inflight = null;
2201                for (int i=0; i<mInFlight.size(); i++) {
2202                    if (mInFlight.get(i).mPendingIntent == pi) {
2203                        inflight = mInFlight.remove(i);
2204                        break;
2205                    }
2206                }
2207                if (inflight != null) {
2208                    final long nowELAPSED = SystemClock.elapsedRealtime();
2209                    BroadcastStats bs = inflight.mBroadcastStats;
2210                    bs.nesting--;
2211                    if (bs.nesting <= 0) {
2212                        bs.nesting = 0;
2213                        bs.aggregateTime += nowELAPSED - bs.startTime;
2214                    }
2215                    FilterStats fs = inflight.mFilterStats;
2216                    fs.nesting--;
2217                    if (fs.nesting <= 0) {
2218                        fs.nesting = 0;
2219                        fs.aggregateTime += nowELAPSED - fs.startTime;
2220                    }
2221                    if (RECORD_ALARMS_IN_HISTORY) {
2222                        if (inflight.mWorkSource != null && inflight.mWorkSource.size() > 0) {
2223                            for (int wi=0; wi<inflight.mWorkSource.size(); wi++) {
2224                                ActivityManagerNative.noteAlarmFinish(
2225                                        pi, inflight.mWorkSource.get(wi), inflight.mTag);
2226                            }
2227                        } else {
2228                            ActivityManagerNative.noteAlarmFinish(
2229                                    pi, -1, inflight.mTag);
2230                        }
2231                    }
2232                } else {
2233                    mLog.w("No in-flight alarm for " + pi + " " + intent);
2234                }
2235                mBroadcastRefCount--;
2236                if (mBroadcastRefCount == 0) {
2237                    mWakeLock.release();
2238                    if (mInFlight.size() > 0) {
2239                        mLog.w("Finished all broadcasts with " + mInFlight.size()
2240                                + " remaining inflights");
2241                        for (int i=0; i<mInFlight.size(); i++) {
2242                            mLog.w("  Remaining #" + i + ": " + mInFlight.get(i));
2243                        }
2244                        mInFlight.clear();
2245                    }
2246                } else {
2247                    // the next of our alarms is now in flight.  reattribute the wakelock.
2248                    if (mInFlight.size() > 0) {
2249                        InFlight inFlight = mInFlight.get(0);
2250                        setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource,
2251                                inFlight.mAlarmType, inFlight.mTag, false);
2252                    } else {
2253                        // should never happen
2254                        mLog.w("Alarm wakelock still held but sent queue empty");
2255                        mWakeLock.setWorkSource(null);
2256                    }
2257                }
2258            }
2259        }
2260    }
2261}
2262