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