linux内核alarm,技术内幕:Android对Linux内核的增强 Alarm

6 09 2013

技术内幕:Android对Linux内核的增强 Alarm

Alarm(硬件时钟)

Alarm就是一个硬件时钟,前面我们已经知道它提供了一个定时器,用于把设备从睡眠状态唤醒,同时它也提供了一个在设备睡眠时仍然会运行的时钟基准。在应用层上,有关时间的应用都需要Alarm的支持,源代码位于“drivers/rtc/alarm.c”。

Alarm的设备名为“/dev/alarm”。该设备的实现非常简单,我们首先打开源码,可以看到include ,其中定义了一些Alarm的相关信息。Alarm的类型枚举如下:

enum android_alarm_type {

ANDROID_ALARM_RTC_WAKEUP,

ANDROID_ALARM_RTC,

ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,

ANDROID_ALARM_ELAPSED_REALTIME,

ANDROID_ALARM_SYSTEMTIME,

ANDROID_ALARM_TYPE_COUNT,

};

主要包括了5种类型的Alarm,_WAKEUP类型表示在触发Alarm时需要唤醒设备,反之则不需要唤醒设备;ANDROID_ALARM_RTC 类型表示在指定的某一时刻出发Alarm;ANDROID_ALARM_ELAPSED_REALTIME表示在设备启动后,流逝的时间达到总时间之后触 发Alarm;ANDROID_ALARM_SYSTEMTIME类型则表示系统时间;ANDROID_ALARM_ TYPE_COUNT则是Alram类型的计数。

注意 流逝的时间也包括设备睡眠的时间,流逝时间的计算点从它最后一次启动算起。

Alarm返回标记的枚举类型如下:

enum android_alarm_return_flags {

ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,

ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,

ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =

1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,

ANDROID_ALARM_ELAPSED_REALTIME_MASK =

1U << ANDROID_ALARM_ELAPSED_REALTIME,

ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,

ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16

};

Alarm返回标记会随着Alarm的类型而改变。最后还定义了一些宏,主要包括禁用Alarm、Alarm等待、设置Alarm等。下面我们来分析Alarm驱动的具体实现。

首先,Alarm的初始化及退出由以下三个函数来完成:

late_initcall(alarm_late_init);

module_init(alarm_init);

module_exit(alarm_exit);

其中alarm_init函数对Alarm执行初始化操作,alarm_late_init需要在初始化完成之后进行调用,最后退出时需要调用alarm_exit来销毁和卸载Alarm接口及驱动。

1.alarm_init

在初始化过程中,首先需要初始化系统时间,通过platform_driver_register函数来注册Alarm驱动的相关参数,具体如下所示:

static struct platform_driver alarm_driver = {

.suspend = alarm_suspend,

.resume = alarm_resume,

.driver = {

.name = “alarm”

}

};

该参数主要指定了当系统挂起(suspend)和唤醒(Desume)所需要实现的分别为alarm_suspend和alarm_resume,同时将Alarm设备驱动的名称设置为了“alarm”。

如果设置正确,那么继续通过如下代码来初始化SUSPEND lock,因为在使用它们之前必须执行初始化操作。

wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, “alarm”);

wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, “alarm_rtc”);

紧接着通过class_interface_register函数来注册Alarm接口信息,主要包括设备的添加和移除操作,内容如下:

static struct class_interface rtc_alarm_interface = {

.add_dev = &rtc_alarm_add_device,

.remove_dev = &rtc_alarm_remove_device,

};

如果在此过程中出现错误,那么需要销毁已经注册的SUSPEND lock,并且卸载Alarm驱动,代码如下:

wake_lock_destroy(&alarm_rtc_wake_lock);

wake_lock_destroy(&alarm_wake_lock);

platform_driver_unregister(&alarm_driver);

注意 wake lock是一种锁机制,只要有用户持有该锁,系统就无法进入休眠状态,该锁可以被用户态程序和内核获得。这个锁可以是超时的或者是没有超时的,超时的锁会在时间过期以后自动解锁。如果没有锁或者超时了,内核就会启动休眠机制进入休眠状态,后面在讲电源管理时还会进一步讲解该机制。

2.alarm_late_init

当Alarm启动之后,我们需要读取当前的RCT和系统时间,由于需要确保在这个操作过程中不被中断,或者在中断之后能告诉其他进程该过程没有读取完 成,不能被请求,因此这里需要通过spin_lock_irqsave和spin_unlock_irqrestore来对其执行锁定和解锁操作。实现代 码如下:

static int __init alarm_late_init(void)

{

unsigned long   flags;

struct timespec system_time;spin_lock_irqsave(&alarm_slock, flags);

getnstimeofday(&elapsed_rtc_delta);

ktime_get_ts(&system_time);

elapsed_rtc_delta = timespec_sub(elapsed_rtc_delta, system_time);

spin_unlock_irqrestore(&alarm_slock, flags);

ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO,

“alarm_late_init: rtc to elapsed realtime delta %ld.%09ld\n”,

elapsed_rtc_delta.tv_sec, elapsed_rtc_delta.tv_nsec);

return 0;

}

3.alarm_exit

当Alarm退出时,就需要通过class_interface_unregister函数来卸载在初始化时注册的Alarm接口,通过 wake_lock_destroy函数来销毁SUSPEND lock,以及通过platform_driver_unregister函数来卸载Alarm驱动。实现代码如下:

static void  __exit alarm_exit(void)

{

class_interface_unregister(&rtc_alarm_interface);

wake_lock_destroy(&alarm_rtc_wake_lock);

wake_lock_destroy(&alarm_wake_lock);

platform_driver_unregister(&alarm_driver);

}

4.添加和移除设备

接下来是rtc_alarm_add_device和rtc_alarm_remove_device函数的实现。添加设备时,首先将设备转换成 rtc_device类型,然后,通过misc_register函数将自己注册成为一个Misc设备。其包括的主要特性如下面的代码所示:

static struct file_operations alarm_fops = {

.owner = THIS_MODULE,

.unlocked_ioctl = alarm_ioctl,

.open = alarm_open,

.release = alarm_release,

};static struct miscdevice alarm_device = {

.minor = MISC_DYNAMIC_MINOR,

.name = “alarm”,

.fops = &alarm_fops,

};

其中alarm_device中的“.name”表示设备文件名称,而alarm_fops则定义了Alarm的常用操作,包括打开、释放和I/O控 制。这里还需要通过rtc_irq_register函数注册一个rtc_task,用来处理Alarm触发的方法,其定义如下:

static struct rtc_task alarm_rtc_task = {

.func = alarm_triggered_func

};

其中“alarm_triggered_func”则是Alarm需要触发的方法。

注意 如果在添加设备的过程中出现错误,我们需要对已经执行的操作进行释放、销毁和卸载。但是,移除一个设备时同样需要判断设备是否是Alarm设备,然后再执 行卸载等操作。另外,在处理挂起操作时,我们首先就需要对设备进行锁定,然后根据Alarm的类型执行不同的操作,同时要保存时间。

alarm_open和alarm_release的实现很简单。最后需要说明的是,对于I/O操作而言,主要需要实现:设置时间、设置RTC、获取时间、设置Alarm等待等。

本小节主要对Android中最简单的设备驱动——Alarm的实现流程进行了分析,大家应该可以自己绘制出一个流程图来了吧。对于Alarm的具体实现,大家可以参考源代码“drivers/rtc/alarm.c”中的实现方式。

Comments are currently closed.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值