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