AlarmManagerService.java revision 2ff5a73c3c39d144ef4195928000d5666d04c947
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) {
1541                    Slog.v(TAG, "sending alarm " + alarm);
1542                }
1543                alarm.operation.send(getContext(), 0,
1544                        mBackgroundIntent.putExtra(
1545                                Intent.EXTRA_ALARM_COUNT, alarm.count),
1546                        mResultReceiver, mHandler);
1547
1548                // we have an active broadcast so stay awake.
1549                if (mBroadcastRefCount == 0) {
1550                    setWakelockWorkSource(alarm.operation, alarm.workSource,
1551                            alarm.type, alarm.tag, true);
1552                    mWakeLock.acquire();
1553                }
1554                final InFlight inflight = new InFlight(AlarmManagerService.this,
1555                        alarm.operation, alarm.workSource, alarm.type, alarm.tag);
1556                mInFlight.add(inflight);
1557                mBroadcastRefCount++;
1558
1559                final BroadcastStats bs = inflight.mBroadcastStats;
1560                bs.count++;
1561                if (bs.nesting == 0) {
1562                    bs.nesting = 1;
1563                    bs.startTime = nowELAPSED;
1564                } else {
1565                    bs.nesting++;
1566                }
1567                final FilterStats fs = inflight.mFilterStats;
1568                fs.count++;
1569                if (fs.nesting == 0) {
1570                    fs.nesting = 1;
1571                    fs.startTime = nowELAPSED;
1572                } else {
1573                    fs.nesting++;
1574                }
1575                if (alarm.type == ELAPSED_REALTIME_WAKEUP
1576                        || alarm.type == RTC_WAKEUP) {
1577                    bs.numWakeup++;
1578                    fs.numWakeup++;
1579                    if (alarm.workSource != null && alarm.workSource.size() > 0) {
1580                        for (int wi=0; wi<alarm.workSource.size(); wi++) {
1581                            ActivityManagerNative.noteWakeupAlarm(
1582                                    alarm.operation, alarm.workSource.get(wi),
1583                                    alarm.workSource.getName(wi));
1584                        }
1585                    } else {
1586                        ActivityManagerNative.noteWakeupAlarm(
1587                                alarm.operation, -1, null);
1588                    }
1589                }
1590            } catch (PendingIntent.CanceledException e) {
1591                if (alarm.repeatInterval > 0) {
1592                    // This IntentSender is no longer valid, but this
1593                    // is a repeating alarm, so toss the hoser.
1594                    removeImpl(alarm.operation);
1595                }
1596            } catch (RuntimeException e) {
1597                Slog.w(TAG, "Failure sending alarm.", e);
1598            }
1599        }
1600    }
1601
1602    private class AlarmThread extends Thread
1603    {
1604        public AlarmThread()
1605        {
1606            super("AlarmManager");
1607        }
1608
1609        public void run()
1610        {
1611            ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
1612
1613            while (true)
1614            {
1615                int result = waitForAlarm(mNativeData);
1616
1617                triggerList.clear();
1618
1619                if ((result & TIME_CHANGED_MASK) != 0) {
1620                    if (DEBUG_BATCH) {
1621                        Slog.v(TAG, "Time changed notification from kernel; rebatching");
1622                    }
1623                    removeImpl(mTimeTickSender);
1624                    rebatchAllAlarms();
1625                    mClockReceiver.scheduleTimeTickEvent();
1626                    synchronized (mLock) {
1627                        mNumTimeChanged++;
1628                    }
1629                    Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
1630                    intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
1631                            | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1632                    getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
1633                }
1634
1635                synchronized (mLock) {
1636                    final long nowRTC = System.currentTimeMillis();
1637                    final long nowELAPSED = SystemClock.elapsedRealtime();
1638                    if (localLOGV) Slog.v(
1639                        TAG, "Checking for alarms... rtc=" + nowRTC
1640                        + ", elapsed=" + nowELAPSED);
1641
1642                    if (WAKEUP_STATS) {
1643                        if ((result & IS_WAKEUP_MASK) != 0) {
1644                            long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;
1645                            int n = 0;
1646                            for (WakeupEvent event : mRecentWakeups) {
1647                                if (event.when > newEarliest) break;
1648                                n++; // number of now-stale entries at the list head
1649                            }
1650                            for (int i = 0; i < n; i++) {
1651                                mRecentWakeups.remove();
1652                            }
1653
1654                            recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);
1655                        }
1656                    }
1657
1658                    boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
1659                    if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
1660                        // if there are no wakeup alarms and the screen is off, we can
1661                        // delay what we have so far until the future.
1662                        if (mPendingNonWakeupAlarms.size() == 0) {
1663                            mStartCurrentDelayTime = nowELAPSED;
1664                            mNextNonWakeupDeliveryTime = nowELAPSED
1665                                    + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2);
1666                        }
1667                        mPendingNonWakeupAlarms.addAll(triggerList);
1668                        mNumDelayedAlarms += triggerList.size();
1669                        rescheduleKernelAlarmsLocked();
1670                        updateNextAlarmClockLocked();
1671                    } else {
1672                        // now deliver the alarm intents; if there are pending non-wakeup
1673                        // alarms, we need to merge them in to the list.  note we don't
1674                        // just deliver them first because we generally want non-wakeup
1675                        // alarms delivered after wakeup alarms.
1676                        rescheduleKernelAlarmsLocked();
1677                        updateNextAlarmClockLocked();
1678                        if (mPendingNonWakeupAlarms.size() > 0) {
1679                            triggerList.addAll(mPendingNonWakeupAlarms);
1680                            Collections.sort(triggerList, mAlarmDispatchComparator);
1681                            final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
1682                            mTotalDelayTime += thisDelayTime;
1683                            if (mMaxDelayTime < thisDelayTime) {
1684                                mMaxDelayTime = thisDelayTime;
1685                            }
1686                            mPendingNonWakeupAlarms.clear();
1687                        }
1688                        deliverAlarmsLocked(triggerList, nowELAPSED);
1689                    }
1690                }
1691            }
1692        }
1693    }
1694
1695    /**
1696     * Attribute blame for a WakeLock.
1697     * @param pi PendingIntent to attribute blame to if ws is null.
1698     * @param ws WorkSource to attribute blame.
1699     */
1700    void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag,
1701            boolean first) {
1702        try {
1703            final boolean unimportant = pi == mTimeTickSender;
1704            mWakeLock.setUnimportantForLogging(unimportant);
1705            if (first || mLastWakeLockUnimportantForLogging) {
1706                mWakeLock.setHistoryTag(tag);
1707            } else {
1708                mWakeLock.setHistoryTag(null);
1709            }
1710            mLastWakeLockUnimportantForLogging = unimportant;
1711            if (ws != null) {
1712                mWakeLock.setWorkSource(ws);
1713                return;
1714            }
1715
1716            final int uid = ActivityManagerNative.getDefault()
1717                    .getUidForIntentSender(pi.getTarget());
1718            if (uid >= 0) {
1719                mWakeLock.setWorkSource(new WorkSource(uid));
1720                return;
1721            }
1722        } catch (Exception e) {
1723        }
1724
1725        // Something went wrong; fall back to attributing the lock to the OS
1726        mWakeLock.setWorkSource(null);
1727    }
1728
1729    private class AlarmHandler extends Handler {
1730        public static final int ALARM_EVENT = 1;
1731        public static final int MINUTE_CHANGE_EVENT = 2;
1732        public static final int DATE_CHANGE_EVENT = 3;
1733        public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 4;
1734
1735        public AlarmHandler() {
1736        }
1737
1738        public void handleMessage(Message msg) {
1739            if (msg.what == ALARM_EVENT) {
1740                ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
1741                synchronized (mLock) {
1742                    final long nowRTC = System.currentTimeMillis();
1743                    final long nowELAPSED = SystemClock.elapsedRealtime();
1744                    triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
1745                    updateNextAlarmClockLocked();
1746                }
1747
1748                // now trigger the alarms without the lock held
1749                for (int i=0; i<triggerList.size(); i++) {
1750                    Alarm alarm = triggerList.get(i);
1751                    try {
1752                        alarm.operation.send();
1753                    } catch (PendingIntent.CanceledException e) {
1754                        if (alarm.repeatInterval > 0) {
1755                            // This IntentSender is no longer valid, but this
1756                            // is a repeating alarm, so toss the hoser.
1757                            removeImpl(alarm.operation);
1758                        }
1759                    }
1760                }
1761            } else if (msg.what == SEND_NEXT_ALARM_CLOCK_CHANGED) {
1762                sendNextAlarmClockChanged();
1763            }
1764        }
1765    }
1766
1767    class ClockReceiver extends BroadcastReceiver {
1768        public ClockReceiver() {
1769            IntentFilter filter = new IntentFilter();
1770            filter.addAction(Intent.ACTION_TIME_TICK);
1771            filter.addAction(Intent.ACTION_DATE_CHANGED);
1772            getContext().registerReceiver(this, filter);
1773        }
1774
1775        @Override
1776        public void onReceive(Context context, Intent intent) {
1777            if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
1778                if (DEBUG_BATCH) {
1779                    Slog.v(TAG, "Received TIME_TICK alarm; rescheduling");
1780                }
1781                scheduleTimeTickEvent();
1782            } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
1783                // Since the kernel does not keep track of DST, we need to
1784                // reset the TZ information at the beginning of each day
1785                // based off of the current Zone gmt offset + userspace tracked
1786                // daylight savings information.
1787                TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
1788                int gmtOffset = zone.getOffset(System.currentTimeMillis());
1789                setKernelTimezone(mNativeData, -(gmtOffset / 60000));
1790                scheduleDateChangedEvent();
1791            }
1792        }
1793
1794        public void scheduleTimeTickEvent() {
1795            final long currentTime = System.currentTimeMillis();
1796            final long nextTime = 60000 * ((currentTime / 60000) + 1);
1797
1798            // Schedule this event for the amount of time that it would take to get to
1799            // the top of the next minute.
1800            final long tickEventDelay = nextTime - currentTime;
1801
1802            final WorkSource workSource = null; // Let system take blame for time tick events.
1803            setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
1804                    0, mTimeTickSender, true, workSource, null);
1805        }
1806
1807        public void scheduleDateChangedEvent() {
1808            Calendar calendar = Calendar.getInstance();
1809            calendar.setTimeInMillis(System.currentTimeMillis());
1810            calendar.set(Calendar.HOUR, 0);
1811            calendar.set(Calendar.MINUTE, 0);
1812            calendar.set(Calendar.SECOND, 0);
1813            calendar.set(Calendar.MILLISECOND, 0);
1814            calendar.add(Calendar.DAY_OF_MONTH, 1);
1815
1816            final WorkSource workSource = null; // Let system take blame for date change events.
1817            setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource,
1818                    null);
1819        }
1820    }
1821
1822    class InteractiveStateReceiver extends BroadcastReceiver {
1823        public InteractiveStateReceiver() {
1824            IntentFilter filter = new IntentFilter();
1825            filter.addAction(Intent.ACTION_SCREEN_OFF);
1826            filter.addAction(Intent.ACTION_SCREEN_ON);
1827            filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
1828            getContext().registerReceiver(this, filter);
1829        }
1830
1831        @Override
1832        public void onReceive(Context context, Intent intent) {
1833            synchronized (mLock) {
1834                interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
1835            }
1836        }
1837    }
1838
1839    class UninstallReceiver extends BroadcastReceiver {
1840        public UninstallReceiver() {
1841            IntentFilter filter = new IntentFilter();
1842            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1843            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1844            filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1845            filter.addDataScheme("package");
1846            getContext().registerReceiver(this, filter);
1847             // Register for events related to sdcard installation.
1848            IntentFilter sdFilter = new IntentFilter();
1849            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1850            sdFilter.addAction(Intent.ACTION_USER_STOPPED);
1851            getContext().registerReceiver(this, sdFilter);
1852        }
1853
1854        @Override
1855        public void onReceive(Context context, Intent intent) {
1856            synchronized (mLock) {
1857                String action = intent.getAction();
1858                String pkgList[] = null;
1859                if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
1860                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
1861                    for (String packageName : pkgList) {
1862                        if (lookForPackageLocked(packageName)) {
1863                            setResultCode(Activity.RESULT_OK);
1864                            return;
1865                        }
1866                    }
1867                    return;
1868                } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
1869                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1870                } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
1871                    int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1872                    if (userHandle >= 0) {
1873                        removeUserLocked(userHandle);
1874                    }
1875                } else {
1876                    if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
1877                            && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1878                        // This package is being updated; don't kill its alarms.
1879                        return;
1880                    }
1881                    Uri data = intent.getData();
1882                    if (data != null) {
1883                        String pkg = data.getSchemeSpecificPart();
1884                        if (pkg != null) {
1885                            pkgList = new String[]{pkg};
1886                        }
1887                    }
1888                }
1889                if (pkgList != null && (pkgList.length > 0)) {
1890                    for (String pkg : pkgList) {
1891                        removeLocked(pkg);
1892                        for (int i=mBroadcastStats.size()-1; i>=0; i--) {
1893                            ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
1894                            if (uidStats.remove(pkg) != null) {
1895                                if (uidStats.size() <= 0) {
1896                                    mBroadcastStats.removeAt(i);
1897                                }
1898                            }
1899                        }
1900                    }
1901                }
1902            }
1903        }
1904    }
1905
1906    private final BroadcastStats getStatsLocked(PendingIntent pi) {
1907        String pkg = pi.getCreatorPackage();
1908        int uid = pi.getCreatorUid();
1909        ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid);
1910        if (uidStats == null) {
1911            uidStats = new ArrayMap<String, BroadcastStats>();
1912            mBroadcastStats.put(uid, uidStats);
1913        }
1914        BroadcastStats bs = uidStats.get(pkg);
1915        if (bs == null) {
1916            bs = new BroadcastStats(uid, pkg);
1917            uidStats.put(pkg, bs);
1918        }
1919        return bs;
1920    }
1921
1922    class ResultReceiver implements PendingIntent.OnFinished {
1923        public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
1924                String resultData, Bundle resultExtras) {
1925            synchronized (mLock) {
1926                InFlight inflight = null;
1927                for (int i=0; i<mInFlight.size(); i++) {
1928                    if (mInFlight.get(i).mPendingIntent == pi) {
1929                        inflight = mInFlight.remove(i);
1930                        break;
1931                    }
1932                }
1933                if (inflight != null) {
1934                    final long nowELAPSED = SystemClock.elapsedRealtime();
1935                    BroadcastStats bs = inflight.mBroadcastStats;
1936                    bs.nesting--;
1937                    if (bs.nesting <= 0) {
1938                        bs.nesting = 0;
1939                        bs.aggregateTime += nowELAPSED - bs.startTime;
1940                    }
1941                    FilterStats fs = inflight.mFilterStats;
1942                    fs.nesting--;
1943                    if (fs.nesting <= 0) {
1944                        fs.nesting = 0;
1945                        fs.aggregateTime += nowELAPSED - fs.startTime;
1946                    }
1947                } else {
1948                    mLog.w("No in-flight alarm for " + pi + " " + intent);
1949                }
1950                mBroadcastRefCount--;
1951                if (mBroadcastRefCount == 0) {
1952                    mWakeLock.release();
1953                    if (mInFlight.size() > 0) {
1954                        mLog.w("Finished all broadcasts with " + mInFlight.size()
1955                                + " remaining inflights");
1956                        for (int i=0; i<mInFlight.size(); i++) {
1957                            mLog.w("  Remaining #" + i + ": " + mInFlight.get(i));
1958                        }
1959                        mInFlight.clear();
1960                    }
1961                } else {
1962                    // the next of our alarms is now in flight.  reattribute the wakelock.
1963                    if (mInFlight.size() > 0) {
1964                        InFlight inFlight = mInFlight.get(0);
1965                        setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource,
1966                                inFlight.mAlarmType, inFlight.mTag, false);
1967                    } else {
1968                        // should never happen
1969                        mLog.w("Alarm wakelock still held but sent queue empty");
1970                        mWakeLock.setWorkSource(null);
1971                    }
1972                }
1973            }
1974        }
1975    }
1976}
1977