1. 程式人生 > >Android Alarm驅動原始碼分析(Alarm.c)

Android Alarm驅動原始碼分析(Alarm.c)

 

前言:

Android在Linux Kernel的基礎上增加了很多的驅動程式,Alarm驅動是其中最簡單的一個,整個檔案只有500多行。作為驅動程式碼分析的一系列文章的開始,我試圖仔細的分析此驅動的幾乎所有函式程式碼,希望籍此作為溫習Android驅動原始碼一個良好的開端。

Android的增加了一個Alarm驅動,在kernel_root/driver/rtc/alarm.c檔案中實現。Android希望提供一種遞增的時鐘(monotonic ),此時鐘應基於硬體,使得Android的應用程式能夠在裝置進入休眠狀態的時候,仍然執行或者喚醒裝置,以此達到節電的目的。

1.概況

1.1 實現機理

Android Alarm基於硬體時鐘,執行在硬中斷中。但他本身沒有實現硬體RTC的驅動,它是基於Linux高精度時鐘hrtimer來實現的。

Linux高精度時鐘的實現在kernel_root/kernel/Hrtimer.c檔案中。

關於此部分(高精度時鐘hrtimer)的分析可以參見如下兩篇別人的博文:

1.2實現方式

Alarm.c在Linux Kernel中註冊了一個平臺裝置(最終註冊了一個RTC裝置,儲存在變數static struct rtc_device *alarm_rtc_dev;中),裝置節點為/dev/alarm。

使用者空間的程式通過fopen開啟此節點還獲得控制控制代碼,然後通過ioctrl來向此驅動程式傳送請求。

如下檔案直接使用了此驅動:

android_root/system/core/toolbox/alarm.c

android_root/frameworks/base/serices/jni/com_android_server_AlarmManagerService.cpp

android_root/system/core/toolbox/Date.c

android_root/frameworks/base/cmds/runtime/Main_runtime.cpp

android_root/frameworks/base/libs/utils/SystemClock.cpp

android_root/system/core/toolbox/Uptime.c

1.3使用Alarm驅動的Demo程式碼

如果你需要直接操作此驅動,可以參考上面檔案中的使用方法。

如下示例摘自SystemClock.cpp:

#if HAVE_ANDROID_OS
    fd = open("/dev/alarm", O_RDWR);
    if(fd < 0) {
        LOGW("Unable to open alarm driver: %s\n", strerror(errno));
        return -1;
    }
    ts.tv_sec = tv.tv_sec;
    ts.tv_nsec = tv.tv_usec * 1000;
    res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
    if(res < 0) {
        LOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
        ret = -1;
    }
    close(fd);
#else
    if (settimeofday(&tv, NULL) != 0) {
        LOGW("Unable to set clock to %d.%d: %s\n",
            (int) tv.tv_sec, (int) tv.tv_usec, strerror(errno));
        ret = -1;
    }
#endif

2.驅動程式碼分析

2.1 主要函式清單

alarm_start_hrtimer 工具函式,alarm驅動的其他函式通過此函式為對應型別(android_alarm_type)的Alarm建立一個hrtimer定時器。

alarm_ioctl alarm驅動的ioctl函式,上層程式碼通過此介面向驅動程式傳送操作請求。

alarm_open

alarm_release

alarm_timer_triggered

alarm_triggered_func

alarm_suspend

alarm_resume

rtc_alarm_add_device

rtc_alarm_remove_device

alarm_late_init 驅動的後置初始化函式,在alarm_init後執行(參見本節的備註)。

alarm_init 驅動的初始化函式

alarm_exit 驅動的退出函式

備註: 關於Linux驅動程式的啟動順序(alarm_init 和alarm_late_init)的相關說明,請參見如下博文:

2.2 alarm_start_hrtimer 函式

 程式碼及註釋如下:

static void alarm_start_hrtimer(enum android_alarm_type alarm_type)
{
 struct timespec hr_alarm_time;
 if (!(alarm_enabled & (1U << alarm_type))) //根據掩碼alarm_enabled來判斷此型別的enabled.
  return;
 hr_alarm_time = alarm_time[alarm_type]; //儲存該型別的timespec到區域性變數
 if (alarm_type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP ||
     alarm_type == ANDROID_ALARM_ELAPSED_REALTIME)
  set_normalized_timespec(&hr_alarm_time,  //設定時間格式
   hr_alarm_time.tv_sec + elapsed_rtc_delta.tv_sec,
   hr_alarm_time.tv_nsec + elapsed_rtc_delta.tv_nsec);

//記錄日誌,當前版本已經Disable了這個巨集,所以不會有日誌出現。
 ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_FLOW,
  "alarm start hrtimer %d at %ld.%09ld\n",
  alarm_type, hr_alarm_time.tv_sec, hr_alarm_time.tv_nsec);

//為alarm_timer[alarm_type]新增一個hrtimer, 如果alarm_timer[alarm_type]已經存在一個hrtimer,則先刪除然後再新增一個新的。請檢視hrtimer.c中hrtimer_start_range_ns函式的實現。
 hrtimer_start(&alarm_timer[alarm_type],
        timespec_to_ktime(hr_alarm_time), HRTIMER_MODE_ABS);
}

總結:此函式最終為alarm_type型別在陣列alarm_timer[alarm_type]上建立了一個hrtimer.

2.3 alarm_init函式

未完待續。