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