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