First, the calling process alarm
1. alarm setup process
frameworks/base/core/java/android/app/AlarmManager.java
public void set(@AlarmType int type, long triggerAtMillis, PendingIntent operation) { setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, operation, null, null, null, null, null); } private void setImpl(@AlarmType int type, long triggerAtMillis, long windowMillis,long intervalMillis, int flags, PendingIntent operation, final OnAlarmListener listener,String listenerTag, Handler targetHandler, WorkSource workSource,AlarmClockInfo alarmClock) { mService.set(mPackageName, type, triggerAtMillis, windowMillis, intervalMillis, flags, operation, recipientWrapper, listenerTag, workSource, alarmClock); } frameworks/base/services/core/java/com/android/server/AlarmManagerService.java private final IBinder mService = new IAlarmManager.Stub() { @Override public void set(String callingPackage, int type, long triggerAtTime, long windowLength, long interval, int flags, PendingIntent operation, IAlarmListener directReceiver, String listenerTag, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock) { setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver, listenerTag, flags, workSource, alarmClock, callingUid, callingPackage); } } void setImpl(int type, long triggerAtTime, long windowLength, long interval, PendingIntent operation, IAlarmListener directReceiver, String listenerTag, int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage) { setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed, interval, operation, directReceiver, listenerTag, flags, true, workSource, alarmClock, callingUid, callingPackage); } } private void setImplLocked(int type, long when, long whenElapsed, long windowLength, long maxWhen, long interval, PendingIntent operation, IAlarmListener directReceiver, String listenerTag, int flags, boolean doValidate, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage) { Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval, operation, directReceiver, listenerTag, workSource, flags, alarmClock, callingUid, callingPackage); setImplLocked(a, false, doValidate); } } private void setImplLocked(Alarm a, boolean rebatching, boolean doValidate) { rescheduleKernelAlarmsLocked(); } void rescheduleKernelAlarmsLocked() { setLocked(ELAPSED_REALTIME, nextNonWakeup); } private void setLocked(int type, long when) { final int result = set(mNativeData, type, alarmSeconds, alarmNanoseconds); } private native int set(long nativeData, int type, long seconds, long nanoseconds);
frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp
static const JNINativeMethod sMethods[] = { {"set", "(JIJJ)I", (void*)android_server_AlarmManagerService_set}, } static jint android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds) { const int result = impl->set(type, &ts); } int AlarmImpl::set(int type, struct timespec *ts) { return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL); }
By setting the kernel system call time:
SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, const struct itimerspec __user *, utmr, struct itimerspec __user *, otmr)
2. Android by poll upper've been listening ararm, upon receipt of the notification, the corresponding event distribution.
public class AlarmManager { public static final int RTC_WAKEUP = 0; public static final int RTC = 1; public static final int ELAPSED_REALTIME_WAKEUP = 2; public static final int ELAPSED_REALTIME = 3; } private class AlarmThread extends Thread { public AlarmThread() { super("AlarmManager"); } public void run() { ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); while (true) { int result = waitForAlarm(mNativeData); deliverAlarmsLocked(); } } }
Only type 0 or type 2 alarm customers wake-up system. You can find wake-up alarm system according to printing information, such as
09-19 15:00:05.968 813 952 D AlarmManager: sending alarm.type = 2, action = com.android.providers.calendar.intent.CalendarProvider2, cn = ComponentInfo{com.android.providers.calendar/com.android.providers.calendar.CalendarProviderBroadcastReceiver}, operation = PendingIntent{3eaf5c8: PendingIntentRecord{29dc661 com.android.providers.calendar broadcastIntent}} 09-19 15:01:46.941 813 952 D AlarmManager: sending alarm.type = 0, action = null, cn = ComponentInfo{cn.showmac.vsimservice/cn.jpush.android.service.AlarmReceiver}, operation = PendingIntent{ec569d7: PendingIntentRecord{c33696d cn.showmac.vsimservice broadcastIntent}}
Second, the system calls the function function set timerfd
1. man timerfd_create
NAME timerfd_create, timerfd_settime, timerfd_gettime - timers that notify via file descriptors SYNOPSIS #include <sys/timerfd.h> int timerfd_create(int clockid, int flags); int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value); int timerfd_gettime(int fd, struct itimerspec *curr_value);
2. Use the demo
#include <sys/timerfd.h> #include <time.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <stdint.h> /* Definition of uint64_t */ #define handle_error(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) static void print_elapsed_time(void) { static struct timespec start; static int first_call = 1; struct timespec curr; int secs, nsecs; if (first_call) { first_call = 0; if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) { handle_error("clock_gettime"); } } if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1) { handle_error("clock_gettime"); } secs = curr.tv_sec - start.tv_sec; nsecs = curr.tv_nsec - start.tv_nsec; if (nsecs < 0) { secs--; nsecs += 1000000000; } printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000); } int main(int argc, char *argv[]) { struct itimerspec new_value; int max_exp, fd; struct timespec now; uint64_t exp, tot_exp; ssize_t s; if ((argc != 2) && (argc != 4)) { fprintf(stderr, "%s init-secs [interval-secs max-exp]\n", argv[0]); exit(EXIT_FAILURE); } if (clock_gettime(CLOCK_REALTIME, &now) == -1) { handle_error("clock_gettime"); } /* Create a CLOCK_REALTIME absolute timer with initial expiration and interval as specified in command line */ new_value.it_value.tv_sec = now.tv_sec + atoi(argv[1]); new_value.it_value.tv_nsec = now.tv_nsec; if (argc == 2) { new_value.it_interval.tv_sec = 0; max_exp = 1; } else { new_value.it_interval.tv_sec = atoi(argv[2]); max_exp = atoi(argv[3]); } new_value.it_interval.tv_nsec = 0; /* begin use these functions */ fd = timerfd_create(CLOCK_REALTIME, 0); if (fd == -1) handle_error("timerfd_create"); if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1) handle_error("timerfd_settime"); print_elapsed_time(); printf("timer started\n"); for (tot_exp = 0; tot_exp < max_exp;) { s = read(fd, &exp, sizeof(uint64_t)); if (s != sizeof(uint64_t)) handle_error("read"); tot_exp += exp; print_elapsed_time (); the printf ( " Read:% LLU; LLU Total =% \ n- " , (unsigned Long Long ) exp, (unsigned Long Long ) tot_exp); } Exit (of EXIT_SUCCESS); } / * $. 3. 1 ./pp The first timer 100 @ 3s, after the notification once every one second. 0.000: Timer Started 3.002: Read:. 1;. 1 Total = 4.001: Read:. 1; 2 Total = 5.000: Read:. 1;. 3 Total = 6.001: Read:. 1; Total =. 4 ^ the Z [. 1] + the Stopped ./pp 100. 1. 3 $ FG ./pp. 3. 1 100 21.808: Read: 15; // the Ctrl + Total =. 19 is suspended after the Z app, app not receive the notification. 22.000: read: 1; total = 20 23.001: read: 1; total=21 ^C */
Three, RTC clock
1. alarm timer underlayer using rtc
//kernel/time/alarmtimer.c static const struct dev_pm_ops alarmtimer_pm_ops = { .suspend = alarmtimer_suspend, }; static struct platform_driver alarmtimer_driver = { .driver = { .name = "alarmtimer", .pm = &alarmtimer_pm_ops, }, };
Four, Android system, some use
1. Battery status update
static void wakealarm_set_interval(int interval) { itval.it_interval.tv_sec = interval; itval.it_interval.tv_nsec = 0; itval.it_value.tv_sec = interval; itval.it_value.tv_nsec = 0; timerfd_settime(wakealarm_fd, 0, &itval, NULL); } void healthd_battery_update_internal(bool charger_online) { // Fast wake interval when on charger (watch for overheat); // slow wake interval when on battery (watch for drained battery). int ? new_wake_interval = charger_online healthd_config.periodic_chores_interval_fast // charging 1min rtc wakeup time : healthd_config.periodic_chores_interval_slow; // wake-up time 10min rtc non-rechargeable }