android alarm driver &framework 關鍵流程

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章