• 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.text.format.Time;
42 import android.util.Pair;
43 import android.util.Slog;
44 import android.util.TimeUtils;
45 
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.Iterator;
57 import java.util.Map;
58 import java.util.TimeZone;
59 
60 import com.android.internal.util.LocalLog;
61 
62 class AlarmManagerService extends IAlarmManager.Stub {
63     // The threshold for how long an alarm can be late before we print a
64     // warning message.  The time duration is in milliseconds.
65     private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
66 
67     private static final int RTC_WAKEUP_MASK = 1 << AlarmManager.RTC_WAKEUP;
68     private static final int RTC_MASK = 1 << AlarmManager.RTC;
69     private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << AlarmManager.ELAPSED_REALTIME_WAKEUP;
70     private static final int ELAPSED_REALTIME_MASK = 1 << AlarmManager.ELAPSED_REALTIME;
71     private static final int TIME_CHANGED_MASK = 1 << 16;
72 
73     // Alignment quantum for inexact repeating alarms
74     private static final long QUANTUM = AlarmManager.INTERVAL_FIFTEEN_MINUTES;
75 
76     private static final String TAG = "AlarmManager";
77     private static final String ClockReceiver_TAG = "ClockReceiver";
78     private static final boolean localLOGV = false;
79     private static final int ALARM_EVENT = 1;
80     private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
81 
82     private static final Intent mBackgroundIntent
83             = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
84 
85     private final Context mContext;
86 
87     private final LocalLog mLog = new LocalLog(TAG);
88 
89     private Object mLock = new Object();
90 
91     private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>();
92     private final ArrayList<Alarm> mRtcAlarms = new ArrayList<Alarm>();
93     private final ArrayList<Alarm> mElapsedRealtimeWakeupAlarms = new ArrayList<Alarm>();
94     private final ArrayList<Alarm> mElapsedRealtimeAlarms = new ArrayList<Alarm>();
95     private final IncreasingTimeOrder mIncreasingTimeOrder = new IncreasingTimeOrder();
96 
97     private int mDescriptor;
98     private int mBroadcastRefCount = 0;
99     private PowerManager.WakeLock mWakeLock;
100     private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
101     private final AlarmThread mWaitThread = new AlarmThread();
102     private final AlarmHandler mHandler = new AlarmHandler();
103     private ClockReceiver mClockReceiver;
104     private UninstallReceiver mUninstallReceiver;
105     private final ResultReceiver mResultReceiver = new ResultReceiver();
106     private final PendingIntent mTimeTickSender;
107     private final PendingIntent mDateChangeSender;
108 
109     private static final class InFlight extends Intent {
110         final PendingIntent mPendingIntent;
111         final Pair<String, ComponentName> mTarget;
112         final BroadcastStats mBroadcastStats;
113         final FilterStats mFilterStats;
114 
InFlight(AlarmManagerService service, PendingIntent pendingIntent)115         InFlight(AlarmManagerService service, PendingIntent pendingIntent) {
116             mPendingIntent = pendingIntent;
117             Intent intent = pendingIntent.getIntent();
118             mTarget = intent != null
119                     ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent())
120                     : null;
121             mBroadcastStats = service.getStatsLocked(pendingIntent);
122             FilterStats fs = mBroadcastStats.filterStats.get(mTarget);
123             if (fs == null) {
124                 fs = new FilterStats(mBroadcastStats, mTarget);
125                 mBroadcastStats.filterStats.put(mTarget, fs);
126             }
127             mFilterStats = fs;
128         }
129     }
130 
131     private static final class FilterStats {
132         final BroadcastStats mBroadcastStats;
133         final Pair<String, ComponentName> mTarget;
134 
135         long aggregateTime;
136         int count;
137         int numWakeup;
138         long startTime;
139         int nesting;
140 
FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target)141         FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target) {
142             mBroadcastStats = broadcastStats;
143             mTarget = target;
144         }
145     }
146 
147     private static final class BroadcastStats {
148         final String mPackageName;
149 
150         long aggregateTime;
151         int count;
152         int numWakeup;
153         long startTime;
154         int nesting;
155         final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
156                 = new HashMap<Pair<String, ComponentName>, FilterStats>();
157 
BroadcastStats(String packageName)158         BroadcastStats(String packageName) {
159             mPackageName = packageName;
160         }
161     }
162 
163     private final HashMap<String, BroadcastStats> mBroadcastStats
164             = new HashMap<String, BroadcastStats>();
165 
AlarmManagerService(Context context)166     public AlarmManagerService(Context context) {
167         mContext = context;
168         mDescriptor = init();
169 
170         // We have to set current TimeZone info to kernel
171         // because kernel doesn't keep this after reboot
172         String tz = SystemProperties.get(TIMEZONE_PROPERTY);
173         if (tz != null) {
174             setTimeZone(tz);
175         }
176 
177         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
178         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
179 
180         mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
181                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
182                         Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0,
183                         UserHandle.ALL);
184         Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
185         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
186         mDateChangeSender = PendingIntent.getBroadcastAsUser(context, 0, intent,
187                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
188 
189         // now that we have initied the driver schedule the alarm
190         mClockReceiver= new ClockReceiver();
191         mClockReceiver.scheduleTimeTickEvent();
192         mClockReceiver.scheduleDateChangedEvent();
193         mUninstallReceiver = new UninstallReceiver();
194 
195         if (mDescriptor != -1) {
196             mWaitThread.start();
197         } else {
198             Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
199         }
200     }
201 
finalize()202     protected void finalize() throws Throwable {
203         try {
204             close(mDescriptor);
205         } finally {
206             super.finalize();
207         }
208     }
209 
set(int type, long triggerAtTime, PendingIntent operation)210     public void set(int type, long triggerAtTime, PendingIntent operation) {
211         setRepeating(type, triggerAtTime, 0, operation);
212     }
213 
setRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)214     public void setRepeating(int type, long triggerAtTime, long interval,
215             PendingIntent operation) {
216         if (operation == null) {
217             Slog.w(TAG, "set/setRepeating ignored because there is no intent");
218             return;
219         }
220         synchronized (mLock) {
221             Alarm alarm = new Alarm();
222             alarm.type = type;
223             alarm.when = triggerAtTime;
224             alarm.repeatInterval = interval;
225             alarm.operation = operation;
226 
227             // Remove this alarm if already scheduled.
228             removeLocked(operation);
229 
230             if (localLOGV) Slog.v(TAG, "set: " + alarm);
231 
232             int index = addAlarmLocked(alarm);
233             if (index == 0) {
234                 setLocked(alarm);
235             }
236         }
237     }
238 
setInexactRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)239     public void setInexactRepeating(int type, long triggerAtTime, long interval,
240             PendingIntent operation) {
241         if (operation == null) {
242             Slog.w(TAG, "setInexactRepeating ignored because there is no intent");
243             return;
244         }
245 
246         if (interval <= 0) {
247             Slog.w(TAG, "setInexactRepeating ignored because interval " + interval
248                     + " is invalid");
249             return;
250         }
251 
252         // If the requested interval isn't a multiple of 15 minutes, just treat it as exact
253         if (interval % QUANTUM != 0) {
254             if (localLOGV) Slog.v(TAG, "Interval " + interval + " not a quantum multiple");
255             setRepeating(type, triggerAtTime, interval, operation);
256             return;
257         }
258 
259         // Translate times into the ELAPSED timebase for alignment purposes so that
260         // alignment never tries to match against wall clock times.
261         final boolean isRtc = (type == AlarmManager.RTC || type == AlarmManager.RTC_WAKEUP);
262         final long skew = (isRtc)
263                 ? System.currentTimeMillis() - SystemClock.elapsedRealtime()
264                 : 0;
265 
266         // Slip forward to the next ELAPSED-timebase quantum after the stated time.  If
267         // we're *at* a quantum point, leave it alone.
268         final long adjustedTriggerTime;
269         long offset = (triggerAtTime - skew) % QUANTUM;
270         if (offset != 0) {
271             adjustedTriggerTime = triggerAtTime - offset + QUANTUM;
272         } else {
273             adjustedTriggerTime = triggerAtTime;
274         }
275 
276         // Set the alarm based on the quantum-aligned start time
277         if (localLOGV) Slog.v(TAG, "setInexactRepeating: type=" + type + " interval=" + interval
278                 + " trigger=" + adjustedTriggerTime + " orig=" + triggerAtTime);
279         setRepeating(type, adjustedTriggerTime, interval, operation);
280     }
281 
setTime(long millis)282     public void setTime(long millis) {
283         mContext.enforceCallingOrSelfPermission(
284                 "android.permission.SET_TIME",
285                 "setTime");
286 
287         SystemClock.setCurrentTimeMillis(millis);
288     }
289 
setTimeZone(String tz)290     public void setTimeZone(String tz) {
291         mContext.enforceCallingOrSelfPermission(
292                 "android.permission.SET_TIME_ZONE",
293                 "setTimeZone");
294 
295         long oldId = Binder.clearCallingIdentity();
296         try {
297             if (TextUtils.isEmpty(tz)) return;
298             TimeZone zone = TimeZone.getTimeZone(tz);
299             // Prevent reentrant calls from stepping on each other when writing
300             // the time zone property
301             boolean timeZoneWasChanged = false;
302             synchronized (this) {
303                 String current = SystemProperties.get(TIMEZONE_PROPERTY);
304                 if (current == null || !current.equals(zone.getID())) {
305                     if (localLOGV) {
306                         Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
307                     }
308                     timeZoneWasChanged = true;
309                     SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
310                 }
311 
312                 // Update the kernel timezone information
313                 // Kernel tracks time offsets as 'minutes west of GMT'
314                 int gmtOffset = zone.getOffset(System.currentTimeMillis());
315                 setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
316             }
317 
318             TimeZone.setDefault(null);
319 
320             if (timeZoneWasChanged) {
321                 Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
322                 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
323                 intent.putExtra("time-zone", zone.getID());
324                 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
325             }
326         } finally {
327             Binder.restoreCallingIdentity(oldId);
328         }
329     }
330 
remove(PendingIntent operation)331     public void remove(PendingIntent operation) {
332         if (operation == null) {
333             return;
334         }
335         synchronized (mLock) {
336             removeLocked(operation);
337         }
338     }
339 
removeLocked(PendingIntent operation)340     public void removeLocked(PendingIntent operation) {
341         removeLocked(mRtcWakeupAlarms, operation);
342         removeLocked(mRtcAlarms, operation);
343         removeLocked(mElapsedRealtimeWakeupAlarms, operation);
344         removeLocked(mElapsedRealtimeAlarms, operation);
345     }
346 
removeLocked(ArrayList<Alarm> alarmList, PendingIntent operation)347     private void removeLocked(ArrayList<Alarm> alarmList,
348             PendingIntent operation) {
349         if (alarmList.size() <= 0) {
350             return;
351         }
352 
353         // iterator over the list removing any it where the intent match
354         Iterator<Alarm> it = alarmList.iterator();
355 
356         while (it.hasNext()) {
357             Alarm alarm = it.next();
358             if (alarm.operation.equals(operation)) {
359                 it.remove();
360             }
361         }
362     }
363 
removeLocked(String packageName)364     public void removeLocked(String packageName) {
365         removeLocked(mRtcWakeupAlarms, packageName);
366         removeLocked(mRtcAlarms, packageName);
367         removeLocked(mElapsedRealtimeWakeupAlarms, packageName);
368         removeLocked(mElapsedRealtimeAlarms, packageName);
369     }
370 
removeLocked(ArrayList<Alarm> alarmList, String packageName)371     private void removeLocked(ArrayList<Alarm> alarmList,
372             String packageName) {
373         if (alarmList.size() <= 0) {
374             return;
375         }
376 
377         // iterator over the list removing any it where the intent match
378         Iterator<Alarm> it = alarmList.iterator();
379 
380         while (it.hasNext()) {
381             Alarm alarm = it.next();
382             if (alarm.operation.getTargetPackage().equals(packageName)) {
383                 it.remove();
384             }
385         }
386     }
387 
removeUserLocked(int userHandle)388     public void removeUserLocked(int userHandle) {
389         removeUserLocked(mRtcWakeupAlarms, userHandle);
390         removeUserLocked(mRtcAlarms, userHandle);
391         removeUserLocked(mElapsedRealtimeWakeupAlarms, userHandle);
392         removeUserLocked(mElapsedRealtimeAlarms, userHandle);
393     }
394 
removeUserLocked(ArrayList<Alarm> alarmList, int userHandle)395     private void removeUserLocked(ArrayList<Alarm> alarmList, int userHandle) {
396         if (alarmList.size() <= 0) {
397             return;
398         }
399 
400         // iterator over the list removing any it where the intent match
401         Iterator<Alarm> it = alarmList.iterator();
402 
403         while (it.hasNext()) {
404             Alarm alarm = it.next();
405             if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
406                 it.remove();
407             }
408         }
409     }
410 
lookForPackageLocked(String packageName)411     public boolean lookForPackageLocked(String packageName) {
412         return lookForPackageLocked(mRtcWakeupAlarms, packageName)
413                 || lookForPackageLocked(mRtcAlarms, packageName)
414                 || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName)
415                 || lookForPackageLocked(mElapsedRealtimeAlarms, packageName);
416     }
417 
lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName)418     private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) {
419         for (int i=alarmList.size()-1; i>=0; i--) {
420             if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) {
421                 return true;
422             }
423         }
424         return false;
425     }
426 
getAlarmList(int type)427     private ArrayList<Alarm> getAlarmList(int type) {
428         switch (type) {
429             case AlarmManager.RTC_WAKEUP:              return mRtcWakeupAlarms;
430             case AlarmManager.RTC:                     return mRtcAlarms;
431             case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms;
432             case AlarmManager.ELAPSED_REALTIME:        return mElapsedRealtimeAlarms;
433         }
434 
435         return null;
436     }
437 
addAlarmLocked(Alarm alarm)438     private int addAlarmLocked(Alarm alarm) {
439         ArrayList<Alarm> alarmList = getAlarmList(alarm.type);
440 
441         int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder);
442         if (index < 0) {
443             index = 0 - index - 1;
444         }
445         if (localLOGV) Slog.v(TAG, "Adding alarm " + alarm + " at " + index);
446         alarmList.add(index, alarm);
447 
448         if (localLOGV) {
449             // Display the list of alarms for this alarm type
450             Slog.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type);
451             int position = 0;
452             for (Alarm a : alarmList) {
453                 Time time = new Time();
454                 time.set(a.when);
455                 String timeStr = time.format("%b %d %I:%M:%S %p");
456                 Slog.v(TAG, position + ": " + timeStr
457                         + " " + a.operation.getTargetPackage());
458                 position += 1;
459             }
460         }
461 
462         return index;
463     }
464 
timeToNextAlarm()465     public long timeToNextAlarm() {
466         long nextAlarm = Long.MAX_VALUE;
467         synchronized (mLock) {
468             for (int i=AlarmManager.RTC_WAKEUP;
469                     i<=AlarmManager.ELAPSED_REALTIME; i++) {
470                 ArrayList<Alarm> alarmList = getAlarmList(i);
471                 if (alarmList.size() > 0) {
472                     Alarm a = alarmList.get(0);
473                     if (a.when < nextAlarm) {
474                         nextAlarm = a.when;
475                     }
476                 }
477             }
478         }
479         return nextAlarm;
480     }
481 
setLocked(Alarm alarm)482     private void setLocked(Alarm alarm)
483     {
484         if (mDescriptor != -1)
485         {
486             // The kernel never triggers alarms with negative wakeup times
487             // so we ensure they are positive.
488             long alarmSeconds, alarmNanoseconds;
489             if (alarm.when < 0) {
490                 alarmSeconds = 0;
491                 alarmNanoseconds = 0;
492             } else {
493                 alarmSeconds = alarm.when / 1000;
494                 alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000;
495             }
496 
497             set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds);
498         }
499         else
500         {
501             Message msg = Message.obtain();
502             msg.what = ALARM_EVENT;
503 
504             mHandler.removeMessages(ALARM_EVENT);
505             mHandler.sendMessageAtTime(msg, alarm.when);
506         }
507     }
508 
509     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)510     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
511         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
512                 != PackageManager.PERMISSION_GRANTED) {
513             pw.println("Permission Denial: can't dump AlarmManager from from pid="
514                     + Binder.getCallingPid()
515                     + ", uid=" + Binder.getCallingUid());
516             return;
517         }
518 
519         synchronized (mLock) {
520             pw.println("Current Alarm Manager state:");
521             if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) {
522                 final long now = System.currentTimeMillis();
523                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
524                 pw.println(" ");
525                 pw.print("  Realtime wakeup (now=");
526                         pw.print(sdf.format(new Date(now))); pw.println("):");
527                 if (mRtcWakeupAlarms.size() > 0) {
528                     dumpAlarmList(pw, mRtcWakeupAlarms, "  ", "RTC_WAKEUP", now);
529                 }
530                 if (mRtcAlarms.size() > 0) {
531                     dumpAlarmList(pw, mRtcAlarms, "  ", "RTC", now);
532                 }
533             }
534             if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) {
535                 final long now = SystemClock.elapsedRealtime();
536                 pw.println(" ");
537                 pw.print("  Elapsed realtime wakeup (now=");
538                         TimeUtils.formatDuration(now, pw); pw.println("):");
539                 if (mElapsedRealtimeWakeupAlarms.size() > 0) {
540                     dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, "  ", "ELAPSED_WAKEUP", now);
541                 }
542                 if (mElapsedRealtimeAlarms.size() > 0) {
543                     dumpAlarmList(pw, mElapsedRealtimeAlarms, "  ", "ELAPSED", now);
544                 }
545             }
546 
547             pw.println();
548             pw.print("  Broadcast ref count: "); pw.println(mBroadcastRefCount);
549             pw.println();
550 
551             if (mLog.dump(pw, "  Recent problems", "    ")) {
552                 pw.println();
553             }
554 
555             final FilterStats[] topFilters = new FilterStats[10];
556             final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
557                 @Override
558                 public int compare(FilterStats lhs, FilterStats rhs) {
559                     if (lhs.aggregateTime < rhs.aggregateTime) {
560                         return 1;
561                     } else if (lhs.aggregateTime > rhs.aggregateTime) {
562                         return -1;
563                     }
564                     return 0;
565                 }
566             };
567             int len = 0;
568             for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
569                 BroadcastStats bs = be.getValue();
570                 for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
571                         : bs.filterStats.entrySet()) {
572                     FilterStats fs = fe.getValue();
573                     int pos = len > 0
574                             ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
575                     if (pos < 0) {
576                         pos = -pos - 1;
577                     }
578                     if (pos < topFilters.length) {
579                         int copylen = topFilters.length - pos - 1;
580                         if (copylen > 0) {
581                             System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
582                         }
583                         topFilters[pos] = fs;
584                         if (len < topFilters.length) {
585                             len++;
586                         }
587                     }
588                 }
589             }
590             if (len > 0) {
591                 pw.println("  Top Alarms:");
592                 for (int i=0; i<len; i++) {
593                     FilterStats fs = topFilters[i];
594                     pw.print("    ");
595                     if (fs.nesting > 0) pw.print("*ACTIVE* ");
596                     TimeUtils.formatDuration(fs.aggregateTime, pw);
597                     pw.print(" running, "); pw.print(fs.numWakeup);
598                     pw.print(" wakeups, "); pw.print(fs.count);
599                     pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
600                     pw.println();
601                     pw.print("      ");
602                     if (fs.mTarget.first != null) {
603                         pw.print(" act="); pw.print(fs.mTarget.first);
604                     }
605                     if (fs.mTarget.second != null) {
606                         pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
607                     }
608                     pw.println();
609                 }
610             }
611 
612             pw.println(" ");
613             pw.println("  Alarm Stats:");
614             final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
615             for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
616                 BroadcastStats bs = be.getValue();
617                 pw.print("  ");
618                 if (bs.nesting > 0) pw.print("*ACTIVE* ");
619                 pw.print(be.getKey());
620                 pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
621                         pw.print(" running, "); pw.print(bs.numWakeup);
622                         pw.println(" wakeups:");
623                 tmpFilters.clear();
624                 for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
625                         : bs.filterStats.entrySet()) {
626                     tmpFilters.add(fe.getValue());
627                 }
628                 Collections.sort(tmpFilters, comparator);
629                 for (int i=0; i<tmpFilters.size(); i++) {
630                     FilterStats fs = tmpFilters.get(i);
631                     pw.print("    ");
632                             if (fs.nesting > 0) pw.print("*ACTIVE* ");
633                             TimeUtils.formatDuration(fs.aggregateTime, pw);
634                             pw.print(" "); pw.print(fs.numWakeup);
635                             pw.print(" wakes " ); pw.print(fs.count);
636                             pw.print(" alarms:");
637                             if (fs.mTarget.first != null) {
638                                 pw.print(" act="); pw.print(fs.mTarget.first);
639                             }
640                             if (fs.mTarget.second != null) {
641                                 pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
642                             }
643                             pw.println();
644                 }
645             }
646         }
647     }
648 
dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, String prefix, String label, long now)649     private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
650             String prefix, String label, long now) {
651         for (int i=list.size()-1; i>=0; i--) {
652             Alarm a = list.get(i);
653             pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
654                     pw.print(": "); pw.println(a);
655             a.dump(pw, prefix + "  ", now);
656         }
657     }
658 
init()659     private native int init();
close(int fd)660     private native void close(int fd);
set(int fd, int type, long seconds, long nanoseconds)661     private native void set(int fd, int type, long seconds, long nanoseconds);
waitForAlarm(int fd)662     private native int waitForAlarm(int fd);
setKernelTimezone(int fd, int minuteswest)663     private native int setKernelTimezone(int fd, int minuteswest);
664 
triggerAlarmsLocked(ArrayList<Alarm> alarmList, ArrayList<Alarm> triggerList, long now)665     private void triggerAlarmsLocked(ArrayList<Alarm> alarmList,
666                                      ArrayList<Alarm> triggerList,
667                                      long now)
668     {
669         Iterator<Alarm> it = alarmList.iterator();
670         ArrayList<Alarm> repeats = new ArrayList<Alarm>();
671 
672         while (it.hasNext())
673         {
674             Alarm alarm = it.next();
675 
676             if (localLOGV) Slog.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm);
677 
678             if (alarm.when > now) {
679                 // don't fire alarms in the future
680                 break;
681             }
682 
683             // If the alarm is late, then print a warning message.
684             // Note that this can happen if the user creates a new event on
685             // the Calendar app with a reminder that is in the past. In that
686             // case, the reminder alarm will fire immediately.
687             if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) {
688                 Slog.v(TAG, "alarm is late! alarm time: " + alarm.when
689                         + " now: " + now + " delay (in seconds): "
690                         + (now - alarm.when) / 1000);
691             }
692 
693             // Recurring alarms may have passed several alarm intervals while the
694             // phone was asleep or off, so pass a trigger count when sending them.
695             if (localLOGV) Slog.v(TAG, "Alarm triggering: " + alarm);
696             alarm.count = 1;
697             if (alarm.repeatInterval > 0) {
698                 // this adjustment will be zero if we're late by
699                 // less than one full repeat interval
700                 alarm.count += (now - alarm.when) / alarm.repeatInterval;
701             }
702             triggerList.add(alarm);
703 
704             // remove the alarm from the list
705             it.remove();
706 
707             // if it repeats queue it up to be read-added to the list
708             if (alarm.repeatInterval > 0) {
709                 repeats.add(alarm);
710             }
711         }
712 
713         // reset any repeating alarms.
714         it = repeats.iterator();
715         while (it.hasNext()) {
716             Alarm alarm = it.next();
717             alarm.when += alarm.count * alarm.repeatInterval;
718             addAlarmLocked(alarm);
719         }
720 
721         if (alarmList.size() > 0) {
722             setLocked(alarmList.get(0));
723         }
724     }
725 
726     /**
727      * This Comparator sorts Alarms into increasing time order.
728      */
729     public static class IncreasingTimeOrder implements Comparator<Alarm> {
compare(Alarm a1, Alarm a2)730         public int compare(Alarm a1, Alarm a2) {
731             long when1 = a1.when;
732             long when2 = a2.when;
733             if (when1 - when2 > 0) {
734                 return 1;
735             }
736             if (when1 - when2 < 0) {
737                 return -1;
738             }
739             return 0;
740         }
741     }
742 
743     private static class Alarm {
744         public int type;
745         public int count;
746         public long when;
747         public long repeatInterval;
748         public PendingIntent operation;
749 
Alarm()750         public Alarm() {
751             when = 0;
752             repeatInterval = 0;
753             operation = null;
754         }
755 
756         @Override
toString()757         public String toString()
758         {
759             StringBuilder sb = new StringBuilder(128);
760             sb.append("Alarm{");
761             sb.append(Integer.toHexString(System.identityHashCode(this)));
762             sb.append(" type ");
763             sb.append(type);
764             sb.append(" ");
765             sb.append(operation.getTargetPackage());
766             sb.append('}');
767             return sb.toString();
768         }
769 
dump(PrintWriter pw, String prefix, long now)770         public void dump(PrintWriter pw, String prefix, long now) {
771             pw.print(prefix); pw.print("type="); pw.print(type);
772                     pw.print(" when="); TimeUtils.formatDuration(when, now, pw);
773                     pw.print(" repeatInterval="); pw.print(repeatInterval);
774                     pw.print(" count="); pw.println(count);
775             pw.print(prefix); pw.print("operation="); pw.println(operation);
776         }
777     }
778 
779     private class AlarmThread extends Thread
780     {
AlarmThread()781         public AlarmThread()
782         {
783             super("AlarmManager");
784         }
785 
run()786         public void run()
787         {
788             while (true)
789             {
790                 int result = waitForAlarm(mDescriptor);
791 
792                 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
793 
794                 if ((result & TIME_CHANGED_MASK) != 0) {
795                     remove(mTimeTickSender);
796                     mClockReceiver.scheduleTimeTickEvent();
797                     Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
798                     intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
799                             | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
800                     mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
801                 }
802 
803                 synchronized (mLock) {
804                     final long nowRTC = System.currentTimeMillis();
805                     final long nowELAPSED = SystemClock.elapsedRealtime();
806                     if (localLOGV) Slog.v(
807                         TAG, "Checking for alarms... rtc=" + nowRTC
808                         + ", elapsed=" + nowELAPSED);
809 
810                     if ((result & RTC_WAKEUP_MASK) != 0)
811                         triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
812 
813                     if ((result & RTC_MASK) != 0)
814                         triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
815 
816                     if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0)
817                         triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED);
818 
819                     if ((result & ELAPSED_REALTIME_MASK) != 0)
820                         triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED);
821 
822                     // now trigger the alarms
823                     Iterator<Alarm> it = triggerList.iterator();
824                     while (it.hasNext()) {
825                         Alarm alarm = it.next();
826                         try {
827                             if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
828                             alarm.operation.send(mContext, 0,
829                                     mBackgroundIntent.putExtra(
830                                             Intent.EXTRA_ALARM_COUNT, alarm.count),
831                                     mResultReceiver, mHandler);
832 
833                             // we have an active broadcast so stay awake.
834                             if (mBroadcastRefCount == 0) {
835                                 setWakelockWorkSource(alarm.operation);
836                                 mWakeLock.acquire();
837                             }
838                             final InFlight inflight = new InFlight(AlarmManagerService.this,
839                                     alarm.operation);
840                             mInFlight.add(inflight);
841                             mBroadcastRefCount++;
842 
843                             final BroadcastStats bs = inflight.mBroadcastStats;
844                             bs.count++;
845                             if (bs.nesting == 0) {
846                                 bs.nesting = 1;
847                                 bs.startTime = nowELAPSED;
848                             } else {
849                                 bs.nesting++;
850                             }
851                             final FilterStats fs = inflight.mFilterStats;
852                             fs.count++;
853                             if (fs.nesting == 0) {
854                                 fs.nesting = 1;
855                                 fs.startTime = nowELAPSED;
856                             } else {
857                                 fs.nesting++;
858                             }
859                             if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP
860                                     || alarm.type == AlarmManager.RTC_WAKEUP) {
861                                 bs.numWakeup++;
862                                 fs.numWakeup++;
863                                 ActivityManagerNative.noteWakeupAlarm(
864                                         alarm.operation);
865                             }
866                         } catch (PendingIntent.CanceledException e) {
867                             if (alarm.repeatInterval > 0) {
868                                 // This IntentSender is no longer valid, but this
869                                 // is a repeating alarm, so toss the hoser.
870                                 remove(alarm.operation);
871                             }
872                         } catch (RuntimeException e) {
873                             Slog.w(TAG, "Failure sending alarm.", e);
874                         }
875                     }
876                 }
877             }
878         }
879     }
880 
setWakelockWorkSource(PendingIntent pi)881     void setWakelockWorkSource(PendingIntent pi) {
882         try {
883             final int uid = ActivityManagerNative.getDefault()
884                     .getUidForIntentSender(pi.getTarget());
885             if (uid >= 0) {
886                 mWakeLock.setWorkSource(new WorkSource(uid));
887                 return;
888             }
889         } catch (Exception e) {
890         }
891 
892         // Something went wrong; fall back to attributing the lock to the OS
893         mWakeLock.setWorkSource(null);
894     }
895 
896     private class AlarmHandler extends Handler {
897         public static final int ALARM_EVENT = 1;
898         public static final int MINUTE_CHANGE_EVENT = 2;
899         public static final int DATE_CHANGE_EVENT = 3;
900 
AlarmHandler()901         public AlarmHandler() {
902         }
903 
handleMessage(Message msg)904         public void handleMessage(Message msg) {
905             if (msg.what == ALARM_EVENT) {
906                 ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
907                 synchronized (mLock) {
908                     final long nowRTC = System.currentTimeMillis();
909                     triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC);
910                     triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC);
911                     triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC);
912                     triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC);
913                 }
914 
915                 // now trigger the alarms without the lock held
916                 Iterator<Alarm> it = triggerList.iterator();
917                 while (it.hasNext())
918                 {
919                     Alarm alarm = it.next();
920                     try {
921                         alarm.operation.send();
922                     } catch (PendingIntent.CanceledException e) {
923                         if (alarm.repeatInterval > 0) {
924                             // This IntentSender is no longer valid, but this
925                             // is a repeating alarm, so toss the hoser.
926                             remove(alarm.operation);
927                         }
928                     }
929                 }
930             }
931         }
932     }
933 
934     class ClockReceiver extends BroadcastReceiver {
ClockReceiver()935         public ClockReceiver() {
936             IntentFilter filter = new IntentFilter();
937             filter.addAction(Intent.ACTION_TIME_TICK);
938             filter.addAction(Intent.ACTION_DATE_CHANGED);
939             mContext.registerReceiver(this, filter);
940         }
941 
942         @Override
onReceive(Context context, Intent intent)943         public void onReceive(Context context, Intent intent) {
944             if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
945             	scheduleTimeTickEvent();
946             } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
947                 // Since the kernel does not keep track of DST, we need to
948                 // reset the TZ information at the beginning of each day
949                 // based off of the current Zone gmt offset + userspace tracked
950                 // daylight savings information.
951                 TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
952                 int gmtOffset = zone.getOffset(System.currentTimeMillis());
953                 setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
954             	scheduleDateChangedEvent();
955             }
956         }
957 
scheduleTimeTickEvent()958         public void scheduleTimeTickEvent() {
959             Calendar calendar = Calendar.getInstance();
960             final long currentTime = System.currentTimeMillis();
961             calendar.setTimeInMillis(currentTime);
962             calendar.add(Calendar.MINUTE, 1);
963             calendar.set(Calendar.SECOND, 0);
964             calendar.set(Calendar.MILLISECOND, 0);
965 
966             // Schedule this event for the amount of time that it would take to get to
967             // the top of the next minute.
968             final long tickEventDelay = calendar.getTimeInMillis() - currentTime;
969 
970             set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay,
971                     mTimeTickSender);
972         }
973 
scheduleDateChangedEvent()974         public void scheduleDateChangedEvent() {
975             Calendar calendar = Calendar.getInstance();
976             calendar.setTimeInMillis(System.currentTimeMillis());
977             calendar.set(Calendar.HOUR, 0);
978             calendar.set(Calendar.MINUTE, 0);
979             calendar.set(Calendar.SECOND, 0);
980             calendar.set(Calendar.MILLISECOND, 0);
981             calendar.add(Calendar.DAY_OF_MONTH, 1);
982 
983             set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender);
984         }
985     }
986 
987     class UninstallReceiver extends BroadcastReceiver {
UninstallReceiver()988         public UninstallReceiver() {
989             IntentFilter filter = new IntentFilter();
990             filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
991             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
992             filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
993             filter.addDataScheme("package");
994             mContext.registerReceiver(this, filter);
995              // Register for events related to sdcard installation.
996             IntentFilter sdFilter = new IntentFilter();
997             sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
998             sdFilter.addAction(Intent.ACTION_USER_STOPPED);
999             mContext.registerReceiver(this, sdFilter);
1000         }
1001 
1002         @Override
onReceive(Context context, Intent intent)1003         public void onReceive(Context context, Intent intent) {
1004             synchronized (mLock) {
1005                 String action = intent.getAction();
1006                 String pkgList[] = null;
1007                 if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
1008                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
1009                     for (String packageName : pkgList) {
1010                         if (lookForPackageLocked(packageName)) {
1011                             setResultCode(Activity.RESULT_OK);
1012                             return;
1013                         }
1014                     }
1015                     return;
1016                 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
1017                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1018                 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
1019                     int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1020                     if (userHandle >= 0) {
1021                         removeUserLocked(userHandle);
1022                     }
1023                 } else {
1024                     if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
1025                             && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1026                         // This package is being updated; don't kill its alarms.
1027                         return;
1028                     }
1029                     Uri data = intent.getData();
1030                     if (data != null) {
1031                         String pkg = data.getSchemeSpecificPart();
1032                         if (pkg != null) {
1033                             pkgList = new String[]{pkg};
1034                         }
1035                     }
1036                 }
1037                 if (pkgList != null && (pkgList.length > 0)) {
1038                     for (String pkg : pkgList) {
1039                         removeLocked(pkg);
1040                         mBroadcastStats.remove(pkg);
1041                     }
1042                 }
1043             }
1044         }
1045     }
1046 
getStatsLocked(PendingIntent pi)1047     private final BroadcastStats getStatsLocked(PendingIntent pi) {
1048         String pkg = pi.getTargetPackage();
1049         BroadcastStats bs = mBroadcastStats.get(pkg);
1050         if (bs == null) {
1051             bs = new BroadcastStats(pkg);
1052             mBroadcastStats.put(pkg, bs);
1053         }
1054         return bs;
1055     }
1056 
1057     class ResultReceiver implements PendingIntent.OnFinished {
onSendFinished(PendingIntent pi, Intent intent, int resultCode, String resultData, Bundle resultExtras)1058         public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
1059                 String resultData, Bundle resultExtras) {
1060             synchronized (mLock) {
1061                 InFlight inflight = null;
1062                 for (int i=0; i<mInFlight.size(); i++) {
1063                     if (mInFlight.get(i).mPendingIntent == pi) {
1064                         inflight = mInFlight.remove(i);
1065                         break;
1066                     }
1067                 }
1068                 if (inflight != null) {
1069                     final long nowELAPSED = SystemClock.elapsedRealtime();
1070                     BroadcastStats bs = inflight.mBroadcastStats;
1071                     bs.nesting--;
1072                     if (bs.nesting <= 0) {
1073                         bs.nesting = 0;
1074                         bs.aggregateTime += nowELAPSED - bs.startTime;
1075                     }
1076                     FilterStats fs = inflight.mFilterStats;
1077                     fs.nesting--;
1078                     if (fs.nesting <= 0) {
1079                         fs.nesting = 0;
1080                         fs.aggregateTime += nowELAPSED - fs.startTime;
1081                     }
1082                 } else {
1083                     mLog.w("No in-flight alarm for " + pi + " " + intent);
1084                 }
1085                 mBroadcastRefCount--;
1086                 if (mBroadcastRefCount == 0) {
1087                     mWakeLock.release();
1088                     if (mInFlight.size() > 0) {
1089                         mLog.w("Finished all broadcasts with " + mInFlight.size()
1090                                 + " remaining inflights");
1091                         for (int i=0; i<mInFlight.size(); i++) {
1092                             mLog.w("  Remaining #" + i + ": " + mInFlight.get(i));
1093                         }
1094                         mInFlight.clear();
1095                     }
1096                 } else {
1097                     // the next of our alarms is now in flight.  reattribute the wakelock.
1098                     if (mInFlight.size() > 0) {
1099                         setWakelockWorkSource(mInFlight.get(0).mPendingIntent);
1100                     } else {
1101                         // should never happen
1102                         mLog.w("Alarm wakelock still held but sent queue empty");
1103                         mWakeLock.setWorkSource(null);
1104                     }
1105                 }
1106             }
1107         }
1108     }
1109 }
1110