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