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