AlarmManagerService.java revision 864d42eb96a9127b7d2f10ad11e709c24b4b4304
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                    false, 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            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
1234                mNextWakeup = firstWakeup.start;
1235                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
1236            }
1237            if (firstBatch != firstWakeup) {
1238                nextNonWakeup = firstBatch.start;
1239            }
1240        }
1241        if (mPendingNonWakeupAlarms.size() > 0) {
1242            if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) {
1243                nextNonWakeup = mNextNonWakeupDeliveryTime;
1244            }
1245        }
1246        if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) {
1247            mNextNonWakeup = nextNonWakeup;
1248            setLocked(ELAPSED_REALTIME, nextNonWakeup);
1249        }
1250    }
1251
1252    private void removeLocked(PendingIntent operation) {
1253        boolean didRemove = false;
1254        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1255            Batch b = mAlarmBatches.get(i);
1256            didRemove |= b.remove(operation);
1257            if (b.size() == 0) {
1258                mAlarmBatches.remove(i);
1259            }
1260        }
1261
1262        if (didRemove) {
1263            if (DEBUG_BATCH) {
1264                Slog.v(TAG, "remove(operation) changed bounds; rebatching");
1265            }
1266            rebatchAllAlarmsLocked(true);
1267            rescheduleKernelAlarmsLocked();
1268            updateNextAlarmClockLocked();
1269        }
1270    }
1271
1272    void removeLocked(String packageName) {
1273        boolean didRemove = false;
1274        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1275            Batch b = mAlarmBatches.get(i);
1276            didRemove |= b.remove(packageName);
1277            if (b.size() == 0) {
1278                mAlarmBatches.remove(i);
1279            }
1280        }
1281
1282        if (didRemove) {
1283            if (DEBUG_BATCH) {
1284                Slog.v(TAG, "remove(package) changed bounds; rebatching");
1285            }
1286            rebatchAllAlarmsLocked(true);
1287            rescheduleKernelAlarmsLocked();
1288            updateNextAlarmClockLocked();
1289        }
1290    }
1291
1292    void removeUserLocked(int userHandle) {
1293        boolean didRemove = false;
1294        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
1295            Batch b = mAlarmBatches.get(i);
1296            didRemove |= b.remove(userHandle);
1297            if (b.size() == 0) {
1298                mAlarmBatches.remove(i);
1299            }
1300        }
1301
1302        if (didRemove) {
1303            if (DEBUG_BATCH) {
1304                Slog.v(TAG, "remove(user) changed bounds; rebatching");
1305            }
1306            rebatchAllAlarmsLocked(true);
1307            rescheduleKernelAlarmsLocked();
1308            updateNextAlarmClockLocked();
1309        }
1310    }
1311
1312    void interactiveStateChangedLocked(boolean interactive) {
1313        if (mInteractive != interactive) {
1314            mInteractive = interactive;
1315            final long nowELAPSED = SystemClock.elapsedRealtime();
1316            if (interactive) {
1317                if (mPendingNonWakeupAlarms.size() > 0) {
1318                    final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
1319                    mTotalDelayTime += thisDelayTime;
1320                    if (mMaxDelayTime < thisDelayTime) {
1321                        mMaxDelayTime = thisDelayTime;
1322                    }
1323                    deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED);
1324                    mPendingNonWakeupAlarms.clear();
1325                }
1326                if (mNonInteractiveStartTime > 0) {
1327                    long dur = nowELAPSED - mNonInteractiveStartTime;
1328                    if (dur > mNonInteractiveTime) {
1329                        mNonInteractiveTime = dur;
1330                    }
1331                }
1332            } else {
1333                mNonInteractiveStartTime = nowELAPSED;
1334            }
1335        }
1336    }
1337
1338    boolean lookForPackageLocked(String packageName) {
1339        for (int i = 0; i < mAlarmBatches.size(); i++) {
1340            Batch b = mAlarmBatches.get(i);
1341            if (b.hasPackage(packageName)) {
1342                return true;
1343            }
1344        }
1345        return false;
1346    }
1347
1348    private void setLocked(int type, long when) {
1349        if (mNativeData != 0) {
1350            // The kernel never triggers alarms with negative wakeup times
1351            // so we ensure they are positive.
1352            long alarmSeconds, alarmNanoseconds;
1353            if (when < 0) {
1354                alarmSeconds = 0;
1355                alarmNanoseconds = 0;
1356            } else {
1357                alarmSeconds = when / 1000;
1358                alarmNanoseconds = (when % 1000) * 1000 * 1000;
1359            }
1360
1361            set(mNativeData, type, alarmSeconds, alarmNanoseconds);
1362        } else {
1363            Message msg = Message.obtain();
1364            msg.what = ALARM_EVENT;
1365
1366            mHandler.removeMessages(ALARM_EVENT);
1367            mHandler.sendMessageAtTime(msg, when);
1368        }
1369    }
1370
1371    private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
1372            String prefix, String label, long nowRTC, long nowELAPSED, SimpleDateFormat sdf) {
1373        for (int i=list.size()-1; i>=0; i--) {
1374            Alarm a = list.get(i);
1375            pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
1376                    pw.print(": "); pw.println(a);
1377            a.dump(pw, prefix + "  ", nowRTC, nowELAPSED, sdf);
1378        }
1379    }
1380
1381    private static final String labelForType(int type) {
1382        switch (type) {
1383        case RTC: return "RTC";
1384        case RTC_WAKEUP : return "RTC_WAKEUP";
1385        case ELAPSED_REALTIME : return "ELAPSED";
1386        case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
1387        default:
1388            break;
1389        }
1390        return "--unknown--";
1391    }
1392
1393    private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
1394            String prefix, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) {
1395        for (int i=list.size()-1; i>=0; i--) {
1396            Alarm a = list.get(i);
1397            final String label = labelForType(a.type);
1398            pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
1399                    pw.print(": "); pw.println(a);
1400            a.dump(pw, prefix + "  ", nowRTC, nowELAPSED, sdf);
1401        }
1402    }
1403
1404    private native long init();
1405    private native void close(long nativeData);
1406    private native void set(long nativeData, int type, long seconds, long nanoseconds);
1407    private native int waitForAlarm(long nativeData);
1408    private native int setKernelTime(long nativeData, long millis);
1409    private native int setKernelTimezone(long nativeData, int minuteswest);
1410
1411    boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
1412            final long nowRTC) {
1413        boolean hasWakeup = false;
1414        // batches are temporally sorted, so we need only pull from the
1415        // start of the list until we either empty it or hit a batch
1416        // that is not yet deliverable
1417        while (mAlarmBatches.size() > 0) {
1418            Batch batch = mAlarmBatches.get(0);
1419            if (batch.start > nowELAPSED) {
1420                // Everything else is scheduled for the future
1421                break;
1422            }
1423
1424            // We will (re)schedule some alarms now; don't let that interfere
1425            // with delivery of this current batch
1426            mAlarmBatches.remove(0);
1427
1428            final int N = batch.size();
1429            for (int i = 0; i < N; i++) {
1430                Alarm alarm = batch.get(i);
1431                alarm.count = 1;
1432                triggerList.add(alarm);
1433
1434                // Recurring alarms may have passed several alarm intervals while the
1435                // phone was asleep or off, so pass a trigger count when sending them.
1436                if (alarm.repeatInterval > 0) {
1437                    // this adjustment will be zero if we're late by
1438                    // less than one full repeat interval
1439                    alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval;
1440
1441                    // Also schedule its next recurrence
1442                    final long delta = alarm.count * alarm.repeatInterval;
1443                    final long nextElapsed = alarm.whenElapsed + delta;
1444                    setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
1445                            maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
1446                            alarm.repeatInterval, alarm.operation, batch.standalone, true,
1447                            alarm.workSource, alarm.alarmClock, alarm.userId);
1448                }
1449
1450                if (alarm.wakeup) {
1451                    hasWakeup = true;
1452                }
1453
1454                // We removed an alarm clock. Let the caller recompute the next alarm clock.
1455                if (alarm.alarmClock != null) {
1456                    mNextAlarmClockMayChange = true;
1457                }
1458            }
1459        }
1460
1461        // This is a new alarm delivery set; bump the sequence number to indicate that
1462        // all apps' alarm delivery classes should be recalculated.
1463        mCurrentSeq++;
1464        calculateDeliveryPriorities(triggerList);
1465        Collections.sort(triggerList, mAlarmDispatchComparator);
1466
1467        if (localLOGV) {
1468            for (int i=0; i<triggerList.size(); i++) {
1469                Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i));
1470            }
1471        }
1472
1473        return hasWakeup;
1474    }
1475
1476    /**
1477     * This Comparator sorts Alarms into increasing time order.
1478     */
1479    public static class IncreasingTimeOrder implements Comparator<Alarm> {
1480        public int compare(Alarm a1, Alarm a2) {
1481            long when1 = a1.when;
1482            long when2 = a2.when;
1483            if (when1 - when2 > 0) {
1484                return 1;
1485            }
1486            if (when1 - when2 < 0) {
1487                return -1;
1488            }
1489            return 0;
1490        }
1491    }
1492
1493    private static class Alarm {
1494        public final int type;
1495        public final boolean wakeup;
1496        public final PendingIntent operation;
1497        public final String  tag;
1498        public final WorkSource workSource;
1499        public int count;
1500        public long when;
1501        public long windowLength;
1502        public long whenElapsed;    // 'when' in the elapsed time base
1503        public long maxWhen;        // also in the elapsed time base
1504        public long repeatInterval;
1505        public final AlarmManager.AlarmClockInfo alarmClock;
1506        public final int userId;
1507        public PriorityClass priorityClass;
1508
1509        public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
1510                long _interval, PendingIntent _op, WorkSource _ws,
1511                AlarmManager.AlarmClockInfo _info, int _userId) {
1512            type = _type;
1513            wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
1514                    || _type == AlarmManager.RTC_WAKEUP;
1515            when = _when;
1516            whenElapsed = _whenElapsed;
1517            windowLength = _windowLength;
1518            maxWhen = _maxWhen;
1519            repeatInterval = _interval;
1520            operation = _op;
1521            tag = makeTag(_op, _type);
1522            workSource = _ws;
1523            alarmClock = _info;
1524            userId = _userId;
1525        }
1526
1527        public static String makeTag(PendingIntent pi, int type) {
1528            return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
1529                    ? "*walarm*:" : "*alarm*:");
1530        }
1531
1532        @Override
1533        public String toString() {
1534            StringBuilder sb = new StringBuilder(128);
1535            sb.append("Alarm{");
1536            sb.append(Integer.toHexString(System.identityHashCode(this)));
1537            sb.append(" type ");
1538            sb.append(type);
1539            sb.append(" when ");
1540            sb.append(when);
1541            sb.append(" ");
1542            sb.append(operation.getTargetPackage());
1543            sb.append('}');
1544            return sb.toString();
1545        }
1546
1547        public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED,
1548                SimpleDateFormat sdf) {
1549            final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
1550            pw.print(prefix); pw.print("tag="); pw.println(tag);
1551            pw.print(prefix); pw.print("type="); pw.print(type);
1552                    pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
1553                            nowELAPSED, pw);
1554                    if (isRtc) {
1555                        pw.print(" when="); pw.print(sdf.format(new Date(when)));
1556                    } else {
1557                        pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw);
1558                    }
1559                    pw.println();
1560            pw.print(prefix); pw.print("window="); pw.print(windowLength);
1561                    pw.print(" repeatInterval="); pw.print(repeatInterval);
1562                    pw.print(" count="); pw.println(count);
1563            pw.print(prefix); pw.print("operation="); pw.println(operation);
1564        }
1565    }
1566
1567    void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) {
1568        final int numBatches = batches.size();
1569        for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) {
1570            Batch b = batches.get(nextBatch);
1571            if (b.start > nowELAPSED) {
1572                break;
1573            }
1574
1575            final int numAlarms = b.alarms.size();
1576            for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) {
1577                Alarm a = b.alarms.get(nextAlarm);
1578                WakeupEvent e = new WakeupEvent(nowRTC,
1579                        a.operation.getCreatorUid(),
1580                        a.operation.getIntent().getAction());
1581                mRecentWakeups.add(e);
1582            }
1583        }
1584    }
1585
1586    long currentNonWakeupFuzzLocked(long nowELAPSED) {
1587        long timeSinceOn = nowELAPSED - mNonInteractiveStartTime;
1588        if (timeSinceOn < 5*60*1000) {
1589            // If the screen has been off for 5 minutes, only delay by at most two minutes.
1590            return 2*60*1000;
1591        } else if (timeSinceOn < 30*60*1000) {
1592            // If the screen has been off for 30 minutes, only delay by at most 15 minutes.
1593            return 15*60*1000;
1594        } else {
1595            // Otherwise, we will delay by at most an hour.
1596            return 60*60*1000;
1597        }
1598    }
1599
1600    boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) {
1601        if (mInteractive) {
1602            return false;
1603        }
1604        if (mLastAlarmDeliveryTime <= 0) {
1605            return false;
1606        }
1607        if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime > nowELAPSED) {
1608            // This is just a little paranoia, if somehow we have pending non-wakeup alarms
1609            // and the next delivery time is in the past, then just deliver them all.  This
1610            // avoids bugs where we get stuck in a loop trying to poll for alarms.
1611            return false;
1612        }
1613        long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime;
1614        return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED);
1615    }
1616
1617    void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) {
1618        mLastAlarmDeliveryTime = nowELAPSED;
1619        for (int i=0; i<triggerList.size(); i++) {
1620            Alarm alarm = triggerList.get(i);
1621            try {
1622                if (localLOGV) {
1623                    Slog.v(TAG, "sending alarm " + alarm);
1624                }
1625                alarm.operation.send(getContext(), 0,
1626                        mBackgroundIntent.putExtra(
1627                                Intent.EXTRA_ALARM_COUNT, alarm.count),
1628                        mResultReceiver, mHandler);
1629
1630                // we have an active broadcast so stay awake.
1631                if (mBroadcastRefCount == 0) {
1632                    setWakelockWorkSource(alarm.operation, alarm.workSource,
1633                            alarm.type, alarm.tag, true);
1634                    mWakeLock.acquire();
1635                }
1636                final InFlight inflight = new InFlight(AlarmManagerService.this,
1637                        alarm.operation, alarm.workSource, alarm.type, alarm.tag);
1638                mInFlight.add(inflight);
1639                mBroadcastRefCount++;
1640
1641                final BroadcastStats bs = inflight.mBroadcastStats;
1642                bs.count++;
1643                if (bs.nesting == 0) {
1644                    bs.nesting = 1;
1645                    bs.startTime = nowELAPSED;
1646                } else {
1647                    bs.nesting++;
1648                }
1649                final FilterStats fs = inflight.mFilterStats;
1650                fs.count++;
1651                if (fs.nesting == 0) {
1652                    fs.nesting = 1;
1653                    fs.startTime = nowELAPSED;
1654                } else {
1655                    fs.nesting++;
1656                }
1657                if (alarm.type == ELAPSED_REALTIME_WAKEUP
1658                        || alarm.type == RTC_WAKEUP) {
1659                    bs.numWakeup++;
1660                    fs.numWakeup++;
1661                    if (alarm.workSource != null && alarm.workSource.size() > 0) {
1662                        for (int wi=0; wi<alarm.workSource.size(); wi++) {
1663                            ActivityManagerNative.noteWakeupAlarm(
1664                                    alarm.operation, alarm.workSource.get(wi),
1665                                    alarm.workSource.getName(wi));
1666                        }
1667                    } else {
1668                        ActivityManagerNative.noteWakeupAlarm(
1669                                alarm.operation, -1, null);
1670                    }
1671                }
1672            } catch (PendingIntent.CanceledException e) {
1673                if (alarm.repeatInterval > 0) {
1674                    // This IntentSender is no longer valid, but this
1675                    // is a repeating alarm, so toss the hoser.
1676                    removeImpl(alarm.operation);
1677                }
1678            } catch (RuntimeException e) {
1679                Slog.w(TAG, "Failure sending alarm.", e);
1680            }
1681        }
1682    }
1683
1684    private class AlarmThread extends Thread
1685    {
1686        public AlarmThread()
1687        {
1688            super("AlarmManager");
1689        }
1690
1691        public void run()
1692        {
1693            ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
1694
1695            while (true)
1696            {
1697                int result = waitForAlarm(mNativeData);
1698
1699                triggerList.clear();
1700
1701                if ((result & TIME_CHANGED_MASK) != 0) {
1702                    if (DEBUG_BATCH) {
1703                        Slog.v(TAG, "Time changed notification from kernel; rebatching");
1704                    }
1705                    removeImpl(mTimeTickSender);
1706                    rebatchAllAlarms();
1707                    mClockReceiver.scheduleTimeTickEvent();
1708                    synchronized (mLock) {
1709                        mNumTimeChanged++;
1710                    }
1711                    Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
1712                    intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
1713                            | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1714                    getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
1715                }
1716
1717                synchronized (mLock) {
1718                    final long nowRTC = System.currentTimeMillis();
1719                    final long nowELAPSED = SystemClock.elapsedRealtime();
1720                    if (localLOGV) Slog.v(
1721                        TAG, "Checking for alarms... rtc=" + nowRTC
1722                        + ", elapsed=" + nowELAPSED);
1723
1724                    if (WAKEUP_STATS) {
1725                        if ((result & IS_WAKEUP_MASK) != 0) {
1726                            long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
1727                            int n = 0;
1728                            for (WakeupEvent event : mRecentWakeups) {
1729                                if (event.when > newEarliest) break;
1730                                n++; // number of now-stale entries at the list head
1731                            }
1732                            for (int i = 0; i < n; i++) {
1733                                mRecentWakeups.remove();
1734                            }
1735
1736                            recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);
1737                        }
1738                    }
1739
1740                    boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
1741                    if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
1742                        // if there are no wakeup alarms and the screen is off, we can
1743                        // delay what we have so far until the future.
1744                        if (mPendingNonWakeupAlarms.size() == 0) {
1745                            mStartCurrentDelayTime = nowELAPSED;
1746                            mNextNonWakeupDeliveryTime = nowELAPSED
1747                                    + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2);
1748                        }
1749                        mPendingNonWakeupAlarms.addAll(triggerList);
1750                        mNumDelayedAlarms += triggerList.size();
1751                        rescheduleKernelAlarmsLocked();
1752                        updateNextAlarmClockLocked();
1753                    } else {
1754                        // now deliver the alarm intents; if there are pending non-wakeup
1755                        // alarms, we need to merge them in to the list.  note we don't
1756                        // just deliver them first because we generally want non-wakeup
1757                        // alarms delivered after wakeup alarms.
1758                        rescheduleKernelAlarmsLocked();
1759                        updateNextAlarmClockLocked();
1760                        if (mPendingNonWakeupAlarms.size() > 0) {
1761                            calculateDeliveryPriorities(mPendingNonWakeupAlarms);
1762                            triggerList.addAll(mPendingNonWakeupAlarms);
1763                            Collections.sort(triggerList, mAlarmDispatchComparator);
1764                            final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
1765                            mTotalDelayTime += thisDelayTime;
1766                            if (mMaxDelayTime < thisDelayTime) {
1767                                mMaxDelayTime = thisDelayTime;
1768                            }
1769                            mPendingNonWakeupAlarms.clear();
1770                        }
1771                        deliverAlarmsLocked(triggerList, nowELAPSED);
1772                    }
1773                }
1774            }
1775        }
1776    }
1777
1778    /**
1779     * Attribute blame for a WakeLock.
1780     * @param pi PendingIntent to attribute blame to if ws is null.
1781     * @param ws WorkSource to attribute blame.
1782     */
1783    void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag,
1784            boolean first) {
1785        try {
1786            final boolean unimportant = pi == mTimeTickSender;
1787            mWakeLock.setUnimportantForLogging(unimportant);
1788            if (first || mLastWakeLockUnimportantForLogging) {
1789                mWakeLock.setHistoryTag(tag);
1790            } else {
1791                mWakeLock.setHistoryTag(null);
1792            }
1793            mLastWakeLockUnimportantForLogging = unimportant;
1794            if (ws != null) {
1795                mWakeLock.setWorkSource(ws);
1796                return;
1797            }
1798
1799            final int uid = ActivityManagerNative.getDefault()
1800                    .getUidForIntentSender(pi.getTarget());
1801            if (uid >= 0) {
1802                mWakeLock.setWorkSource(new WorkSource(uid));
1803                return;
1804            }
1805        } catch (Exception e) {
1806        }
1807
1808        // Something went wrong; fall back to attributing the lock to the OS
1809        mWakeLock.setWorkSource(null);
1810    }
1811
1812    private class AlarmHandler extends Handler {
1813        public static final int ALARM_EVENT = 1;
1814        public static final int MINUTE_CHANGE_EVENT = 2;
1815        public static final int DATE_CHANGE_EVENT = 3;
1816        public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 4;
1817
1818        public AlarmHandler() {
1819        }
1820
1821        public void handleMessage(Message msg) {
1822            if (msg.what == ALARM_EVENT) {
1823                ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
1824                synchronized (mLock) {
1825                    final long nowRTC = System.currentTimeMillis();
1826                    final long nowELAPSED = SystemClock.elapsedRealtime();
1827                    triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
1828                    updateNextAlarmClockLocked();
1829                }
1830
1831                // now trigger the alarms without the lock held
1832                for (int i=0; i<triggerList.size(); i++) {
1833                    Alarm alarm = triggerList.get(i);
1834                    try {
1835                        alarm.operation.send();
1836                    } catch (PendingIntent.CanceledException e) {
1837                        if (alarm.repeatInterval > 0) {
1838                            // This IntentSender is no longer valid, but this
1839                            // is a repeating alarm, so toss the hoser.
1840                            removeImpl(alarm.operation);
1841                        }
1842                    }
1843                }
1844            } else if (msg.what == SEND_NEXT_ALARM_CLOCK_CHANGED) {
1845                sendNextAlarmClockChanged();
1846            }
1847        }
1848    }
1849
1850    class ClockReceiver extends BroadcastReceiver {
1851        public ClockReceiver() {
1852            IntentFilter filter = new IntentFilter();
1853            filter.addAction(Intent.ACTION_TIME_TICK);
1854            filter.addAction(Intent.ACTION_DATE_CHANGED);
1855            getContext().registerReceiver(this, filter);
1856        }
1857
1858        @Override
1859        public void onReceive(Context context, Intent intent) {
1860            if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
1861                if (DEBUG_BATCH) {
1862                    Slog.v(TAG, "Received TIME_TICK alarm; rescheduling");
1863                }
1864                scheduleTimeTickEvent();
1865            } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
1866                // Since the kernel does not keep track of DST, we need to
1867                // reset the TZ information at the beginning of each day
1868                // based off of the current Zone gmt offset + userspace tracked
1869                // daylight savings information.
1870                TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
1871                int gmtOffset = zone.getOffset(System.currentTimeMillis());
1872                setKernelTimezone(mNativeData, -(gmtOffset / 60000));
1873                scheduleDateChangedEvent();
1874            }
1875        }
1876
1877        public void scheduleTimeTickEvent() {
1878            final long currentTime = System.currentTimeMillis();
1879            final long nextTime = 60000 * ((currentTime / 60000) + 1);
1880
1881            // Schedule this event for the amount of time that it would take to get to
1882            // the top of the next minute.
1883            final long tickEventDelay = nextTime - currentTime;
1884
1885            final WorkSource workSource = null; // Let system take blame for time tick events.
1886            setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
1887                    0, mTimeTickSender, true, workSource, null);
1888        }
1889
1890        public void scheduleDateChangedEvent() {
1891            Calendar calendar = Calendar.getInstance();
1892            calendar.setTimeInMillis(System.currentTimeMillis());
1893            calendar.set(Calendar.HOUR, 0);
1894            calendar.set(Calendar.MINUTE, 0);
1895            calendar.set(Calendar.SECOND, 0);
1896            calendar.set(Calendar.MILLISECOND, 0);
1897            calendar.add(Calendar.DAY_OF_MONTH, 1);
1898
1899            final WorkSource workSource = null; // Let system take blame for date change events.
1900            setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource,
1901                    null);
1902        }
1903    }
1904
1905    class InteractiveStateReceiver extends BroadcastReceiver {
1906        public InteractiveStateReceiver() {
1907            IntentFilter filter = new IntentFilter();
1908            filter.addAction(Intent.ACTION_SCREEN_OFF);
1909            filter.addAction(Intent.ACTION_SCREEN_ON);
1910            filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
1911            getContext().registerReceiver(this, filter);
1912        }
1913
1914        @Override
1915        public void onReceive(Context context, Intent intent) {
1916            synchronized (mLock) {
1917                interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
1918            }
1919        }
1920    }
1921
1922    class UninstallReceiver extends BroadcastReceiver {
1923        public UninstallReceiver() {
1924            IntentFilter filter = new IntentFilter();
1925            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1926            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1927            filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1928            filter.addDataScheme("package");
1929            getContext().registerReceiver(this, filter);
1930             // Register for events related to sdcard installation.
1931            IntentFilter sdFilter = new IntentFilter();
1932            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1933            sdFilter.addAction(Intent.ACTION_USER_STOPPED);
1934            getContext().registerReceiver(this, sdFilter);
1935        }
1936
1937        @Override
1938        public void onReceive(Context context, Intent intent) {
1939            synchronized (mLock) {
1940                String action = intent.getAction();
1941                String pkgList[] = null;
1942                if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
1943                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
1944                    for (String packageName : pkgList) {
1945                        if (lookForPackageLocked(packageName)) {
1946                            setResultCode(Activity.RESULT_OK);
1947                            return;
1948                        }
1949                    }
1950                    return;
1951                } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
1952                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1953                } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
1954                    int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1955                    if (userHandle >= 0) {
1956                        removeUserLocked(userHandle);
1957                    }
1958                } else {
1959                    if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
1960                            && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1961                        // This package is being updated; don't kill its alarms.
1962                        return;
1963                    }
1964                    Uri data = intent.getData();
1965                    if (data != null) {
1966                        String pkg = data.getSchemeSpecificPart();
1967                        if (pkg != null) {
1968                            pkgList = new String[]{pkg};
1969                        }
1970                    }
1971                }
1972                if (pkgList != null && (pkgList.length > 0)) {
1973                    for (String pkg : pkgList) {
1974                        removeLocked(pkg);
1975                        mPriorities.remove(pkg);
1976                        for (int i=mBroadcastStats.size()-1; i>=0; i--) {
1977                            ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
1978                            if (uidStats.remove(pkg) != null) {
1979                                if (uidStats.size() <= 0) {
1980                                    mBroadcastStats.removeAt(i);
1981                                }
1982                            }
1983                        }
1984                    }
1985                }
1986            }
1987        }
1988    }
1989
1990    private final BroadcastStats getStatsLocked(PendingIntent pi) {
1991        String pkg = pi.getCreatorPackage();
1992        int uid = pi.getCreatorUid();
1993        ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid);
1994        if (uidStats == null) {
1995            uidStats = new ArrayMap<String, BroadcastStats>();
1996            mBroadcastStats.put(uid, uidStats);
1997        }
1998        BroadcastStats bs = uidStats.get(pkg);
1999        if (bs == null) {
2000            bs = new BroadcastStats(uid, pkg);
2001            uidStats.put(pkg, bs);
2002        }
2003        return bs;
2004    }
2005
2006    class ResultReceiver implements PendingIntent.OnFinished {
2007        public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
2008                String resultData, Bundle resultExtras) {
2009            synchronized (mLock) {
2010                InFlight inflight = null;
2011                for (int i=0; i<mInFlight.size(); i++) {
2012                    if (mInFlight.get(i).mPendingIntent == pi) {
2013                        inflight = mInFlight.remove(i);
2014                        break;
2015                    }
2016                }
2017                if (inflight != null) {
2018                    final long nowELAPSED = SystemClock.elapsedRealtime();
2019                    BroadcastStats bs = inflight.mBroadcastStats;
2020                    bs.nesting--;
2021                    if (bs.nesting <= 0) {
2022                        bs.nesting = 0;
2023                        bs.aggregateTime += nowELAPSED - bs.startTime;
2024                    }
2025                    FilterStats fs = inflight.mFilterStats;
2026                    fs.nesting--;
2027                    if (fs.nesting <= 0) {
2028                        fs.nesting = 0;
2029                        fs.aggregateTime += nowELAPSED - fs.startTime;
2030                    }
2031                } else {
2032                    mLog.w("No in-flight alarm for " + pi + " " + intent);
2033                }
2034                mBroadcastRefCount--;
2035                if (mBroadcastRefCount == 0) {
2036                    mWakeLock.release();
2037                    if (mInFlight.size() > 0) {
2038                        mLog.w("Finished all broadcasts with " + mInFlight.size()
2039                                + " remaining inflights");
2040                        for (int i=0; i<mInFlight.size(); i++) {
2041                            mLog.w("  Remaining #" + i + ": " + mInFlight.get(i));
2042                        }
2043                        mInFlight.clear();
2044                    }
2045                } else {
2046                    // the next of our alarms is now in flight.  reattribute the wakelock.
2047                    if (mInFlight.size() > 0) {
2048                        InFlight inFlight = mInFlight.get(0);
2049                        setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource,
2050                                inFlight.mAlarmType, inFlight.mTag, false);
2051                    } else {
2052                        // should never happen
2053                        mLog.w("Alarm wakelock still held but sent queue empty");
2054                        mWakeLock.setWorkSource(null);
2055                    }
2056                }
2057            }
2058        }
2059    }
2060}
2061