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