android alarm driver &framework 关键流程

来源:互联网 发布:在线课堂软件 编辑:程序博客网 时间:2024/05/28 04:54

android alarm driver如下:
alarm-dev.c@\kernel\drivers\staging\android

static int __init alarm_dev_init(void){    int err;    int i;    err = misc_register(&alarm_device);    if (err)        return err;    alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm,            ALARM_REALTIME, devalarm_alarmhandler);    hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt,            CLOCK_REALTIME, HRTIMER_MODE_ABS);    alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm,            ALARM_BOOTTIME, devalarm_alarmhandler);    hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt,            CLOCK_BOOTTIME, HRTIMER_MODE_ABS);    hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt,            CLOCK_MONOTONIC, HRTIMER_MODE_ABS);    for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {        alarms[i].type = i;        if (!is_wakeup(i))            alarms[i].u.hrt.function = devalarm_hrthandler;    }    wakeup_source_init(&alarm_wake_lock, "alarm");    return 0;}

driver init主要做了三件事,
1. 注册android alarm 设备:alarm_device。
2. 向linux alarm子系统注册alarm处理函数devalarm_alarmhandler,如果是允许唤醒系统的alarm,还会注册devalarm_hrthandler。当系统linux alarm到期时, 会回调这两个handler处理。
3. 初始化alarm 的wakeup source。

再细看handler里的处理:

static void devalarm_triggered(struct devalarm *alarm){    unsigned long flags;    uint32_t alarm_type_mask = 1U << alarm->type;    alarm_dbg(INT, "%s: type %d\n", __func__, alarm->type);    spin_lock_irqsave(&alarm_slock, flags);    if (alarm_enabled & alarm_type_mask) {        __pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */        alarm_enabled &= ~alarm_type_mask;        alarm_pending |= alarm_type_mask;        wake_up(&alarm_wait_queue);    }    spin_unlock_irqrestore(&alarm_slock, flags);}

主要做了一个动作是唤醒alarm的等待队列alarm_wait_queue, 后面分析再看如何与这里对接 。

先看上层AlarmManagerService初始化的函数,
主要有两步, 一是call native init, 二是启动thread一直等alarm消息:

public AlarmManagerService(Context context) {        mContext = context;        mDescriptor = init();....        if (mDescriptor != -1) {            mWaitThread.start();        } else {            Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");        }    }

其中AlarmManagerService是由System_server init时new出来:
initAndLoop()@SystemServer.java

            Slog.i(TAG, "Alarm Manager");            alarm = new AlarmManagerService(context);            ServiceManager.addService(Context.ALARM_SERVICE, alarm);

init对应初始化,完成alarm设备打开:
com_android_server_AlarmManagerService.cpp@ \frameworks\base\services\jni

static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj){    return open("/dev/alarm", O_RDWR);}

mwaitThread start后,一直循环block等待alarm driver消息, :

   public void run()        {            ArrayList<Alarm> triggerList = new ArrayList<Alarm>();            while (true)            {                int result = waitForAlarm(mDescriptor);

native实现 :

static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd){    int result = 0;    do    {        result = ioctl(fd, ANDROID_ALARM_WAIT);    } while (result < 0 && errno == EINTR);    if (result < 0)    {        ALOGE("Unable to wait on alarm: %s\n", strerror(errno));        return 0;    }    return result;}

ioctl对应driver逻辑:

static long alarm_do_ioctl(struct file *file, unsigned int cmd,                            struct timespec *ts){...    case ANDROID_ALARM_WAIT:        rv = alarm_wait();        break;

alarm_wait实现 如下, 此处会一直wait等待wake up alarm_wait_queue状态 , 就接上了最开始提到的向linux alarm子系统注册的alarm handler来wakeup的地方. 从而完成了具体alarm到期事件 向framework的通知 。

static int alarm_wait(void){    unsigned long flags;    int rv = 0;    spin_lock_irqsave(&alarm_slock, flags);    alarm_dbg(IO, "alarm wait\n");    if (!alarm_pending && wait_pending) {        __pm_relax(&alarm_wake_lock);        wait_pending = 0;    }    spin_unlock_irqrestore(&alarm_slock, flags);    rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);    if (rv)        return rv;    spin_lock_irqsave(&alarm_slock, flags);    rv = alarm_pending;    wait_pending = 1;    alarm_pending = 0;    spin_unlock_irqrestore(&alarm_slock, flags);    return rv;}
0 0