前言:
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)的分析可以參見如下兩篇別人的博文:
http://blog.csdn.net/walkingman321/article/details/6133171
http://blog.csdn.net/walkingman321/article/details/6151172
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)的相關說明,請參見如下博文:
http://blog.csdn.net/cstk502/article/details/6579231
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函數
未完待續。