前言:
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函数
未完待续。