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