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函式
未完待續。