alarm系统调用过程

Posted hellokitty2

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了alarm系统调用过程相关的知识,希望对你有一定的参考价值。

一、alarm的调用过程

1. alarm设置过程

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);
}

通过系统调用设置内核时间:

SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, const struct itimerspec __user *, utmr, struct itimerspec __user *, otmr)

 

2. Android上层通过poll一直在监听ararm,接收到通知后,将相应的事件进行分发。

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();
        }
    }
 }

只有type类型为0或者2的alarm客户唤醒系统。可以根据打印信息查找唤醒系统的闹钟,如

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}}

 

二、系统调用函数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. 使用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]
", 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
");

    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();
        printf("read: %llu; total=%llu
", (unsigned long long) exp, (unsigned long long) tot_exp);
    }

    exit(EXIT_SUCCESS);
}

/*
$ ./pp 3 1 100  //第一次定时3s,之后每1秒通知1次。
0.000: timer started
3.002: read: 1; total=1
4.001: read: 1; total=2
5.000: read: 1; total=3
6.001: read: 1; total=4
^Z
[1]+  Stopped                 ./pp 3 1 100
$ fg
./pp 3 1 100
21.808: read: 15; total=19  //Ctrl+Z后app被挂起了,app就收不到通知了。
22.000: read: 1; total=20
23.001: read: 1; total=21
^C
*/

 

三、RTC时钟

1. alarm底层使用的是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,
    },
};

 

四、Android系统中的一些使用

1. 电池状态更新

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  //充电时1min rtc唤醒一次
                                        : healthd_config.periodic_chores_interval_slow; //非充电时10min rtc唤醒一次
}

 

以上是关于alarm系统调用过程的主要内容,如果未能解决你的问题,请参考以下文章

alarm函数

android alarm timer 哪个好

为啥 alarm() 导致 fgets() 停止等待?

Android设置取消系统闹钟

Linux下实现定时器Timer的几种方法

Linux时间子系统之二:Alarm Timer