在android中,定时alarm功能是很常用的,现在来分析下怎么实现的,这里将采用自下而上的方式讲解。

arm: cortex-a8
Board: FS_S5PC100
Linux: 2.6.29
Android: 2.1

1、 RTC控制器

1.1 feature

实时时钟(RTC)单元可以通过备用电池供电,因此,即使系统电源关闭,它也可以继续工作。RTC 可以通过STRB/LDRB 指令将8 位BCD 码数据送至CPU。这些BCD 数据包括秒,分,时,日期,星期,月和年。RTC 单元通过一个外部的32.768KHz晶振提供时钟。RTC具有定时报警的功能。RTC 控制器功能说明:

时钟数据采用BCD 编码
能够对闰年的年月日进行自动处理
具有告警功能,当系统处于关机状态时,能产生告警中断;
具有独立的电源输入
提供毫秒级时钟中断,该中断可用于作为嵌入式操作系统的内核时钟

1.2 register description

(1) RTC 中断挂起寄存器

(2) RTC控制器寄存器

(3)RTC报警使能寄存器

(4) alarm 值寄存器 (SEC/MIN/HOUR/ DATE/DAY/MON/YEAR)

(5)BCD值寄存器(SEC/MIN/HOUR/ DATE/DAY/MON/YEAR)

1.3 如何program?

从上图可以看到RTC有三个功能块,一个是计时器,一个是定时器,一个是“嘀嗒”产生器,后两个都可以产生中断,前者只要配置后,在power-off的情况下也会计时,当然要有后备电池的供电才可能。

1.计时器

计时器只要你配置好BCD寄存器即可,也就是填入当前的时间,年月日,时分秒。星期这些数据即可。当然在填写之前应该先将控制器寄存器使能。

2.定时器

定时器和计时器不同的地方在于,定时器的值寄存器填写的是触发中断的时间,当BCD计时器的值增加到定时器的值时,就会产生一个中断。该中断可以再掉电模式下或者是普通模式。

3.“嘀嗒”产生器

该部分功能是为OS所提供的功能,初始化后就可以,该值可提供给RTOS。

2、 linux driver

上面只是把RTC硬件给过了一遍,现在往上升一级,开始看下linux下是如何driver一个RTC的。假设你的linux kernel source code的主目录名字为LINUX。

先关注一个目录:LINUX/driver/rtc/

在该目录下,有一堆以rtc-为前缀的文件,这些文件都是各种板子上用的rtc底层驱动代码,我们要看的只有3个,rtc-s3c.c ,alarm.c, alarm-dev.c 。

看下第一个,rtc-s3c.c 是三星产的arm芯片所专用的一个rtc驱动,要说专用也不为过,看看编写者就知道了,看看怎么实现:

它用的是平台设备驱动,

static struct platform_driver s3c2410_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = __devexit_p(s3c_rtc_remove),
.suspend = s3c_rtc_suspend,
.resume = s3c_rtc_resume,
.driver = {
.name = "s3c2410-rtc",
.owner = THIS_MODULE,
},
};

static const struct rtc_class_ops s3c_rtcops = {
.open = s3c_rtc_open,
.release = s3c_rtc_release,
.ioctl = s3c_rtc_ioctl,
.read_time = s3c_rtc_gettime,
.set_time = s3c_rtc_settime,
.read_alarm = s3c_rtc_getalarm,
.set_alarm = s3c_rtc_setalarm,
.irq_set_freq = s3c_rtc_setfreq,
.irq_set_state = s3c_rtc_setpie,
.proc = s3c_rtc_proc,
};

看这两个结构体,我认为就已经达到目的,第一个结构体是平台设备中的driver部分,也就是s3c_rtc_probe,是个很重要的函数,在这里面,第二个结构体被顺利注册进rtc子系统。Rtc的所用到的结构体被定义在,LINUX/include/linux/rtc.h里面。

struct rtc_device
{
struct device dev;
struct module *owner;

int id;
char name[RTC_DEVICE_NAME_SIZE];

const struct rtc_class_ops *ops;
struct mutex ops_lock;

struct cdev char_dev;
unsigned long flags;

unsigned long irq_data;
spinlock_t irq_lock;
wait_queue_head_t irq_queue;
struct fasync_struct *async_queue;

struct rtc_task *irq_task;
spinlock_t irq_task_lock;
int irq_freq;
int max_user_freq;
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
struct work_struct uie_task;
struct timer_list uie_timer;
/* Those fields are protected by rtc->irq_lock */
unsigned int oldsecs;
unsigned int uie_irq_active:1;
unsigned int stop_uie_polling:1;
unsigned int uie_task_active:1;
unsigned int uie_timer_active:1;
#endif
};

这个结构体是核心部分,内核中就是靠它传递信息,不管在哪使用,都要靠它间接的调用底层信息。比如在alarm.c 中。

alarm_ioctl这个函数中,多次使用了rtc_set_time/rtc_get_time,这些函数虽然是定义在rtc目录下的interface.c 中,但实质还是rtc-s3c.c中结构体 rtc_class_ops所指过去的函数。

那么我可以告诉你了,为什么多了一个alarm.c ,因为在android中它为了使得平台无关性提高,因此大量的增加过渡代码层,HAL就是这种性质的存在。alarm.c在用户空间中会多一个/dev/alarm 节点,而rtc-s3c.c 会产生/dev/rtc这样的节点。

Android在HAL层中,是对/dev/alarm这个结点进行操作。

3、JNI 的实现

直接看代码

static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj)
{
return open("/dev/alarm", O_RDWR);
}

static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong nanoseconds)
{
struct timespec ts;
ts.tv_sec = NANOSECONDS_TO_SECONDS(nanoseconds);
ts.tv_nsec = nanoseconds - SECONDS_TO_NANOSECONDS(ts.tv_sec);

int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);

}

static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"init", "()I", (void*)android_server_AlarmManagerService_init},
{"close", "(I)V", (void*)android_server_AlarmManagerService_close},
{"set", "(IIJ)V", (void*)android_server_AlarmManagerService_set},
};

颜色部分说明了一个问题,那就是android也就那么回事,JNI就是按照特定写法的JAVA版的linux c应用程序。完事。如果你觉得不是这么回事,那么你就有事了,去复习复习linux文件IO,看看如何用一个文件描述符打开设备,操作设备等等。

4、 framework层

frameworks/base/services/java/com/android/server/AlarmManagerService.java
frameworks/base/core/java/android/app/AlarmManager.java

下面的是直接提供给app层的API接口,它是AlarmManagerService.java的一个封装。

这里只是简单的解释下service到底在此做什么了。

其实也没做什么,仅仅是把上面分析的JNI拿来在此调用一下而已。然后包装一下,将功能实现得更完美些。

下面是 AlarmManagerService这个类中摘出来的小段:

private native int init();
private native void close(int fd);
private native void set(int fd, int type, long nanoseconds);
private native int waitForAlarm(int fd);
private native int setKernelTimezone(int fd, int minuteswest);

这些就是JNI实现过来的接口。呵呵。

5、APP层

packages/apps/AlarmClock/src/com/android/alarmclock/ 这个目录下,就是系统自带定时器的源代码,比如Alarms.java 中:第一个导入的包就是 import android.app.AlarmManager; 怎样,到现在是否感受到了android从下至上分析的快感?


更多相关文章

  1. Android:实现定时器 Handler的postDelayed(Runnable, long)方法
  2. android用户界面之AlarmManager教程实例汇
  3. Android逆向世界之一:smali文件
  4. [Android] 利用Handler实现定时器功能
  5. android用户界面之AlarmManager教程实例汇
  6. android用户界面之AlarmManager教程实例汇
  7. android 定时器(Handler Timer Thread AlarmManager CountDownTi
  8. android 定时器的实现
  9. android电池(五):电池 充电IC(PM2301)驱动分析篇

随机推荐

  1. Android启动流程分析(十二) SystemServer
  2. Android深入浅出系列课程---Lesson1 AAF1
  3. Android常见布局简述
  4. Android之NDK开发
  5. Android(安卓)入门教程:安装 Android(安卓
  6. 《宅男的android开发指南》(翻译)--1
  7. Android设备获取wifi下的ipv6地址
  8. View类xml属性、方法
  9. Android体系结构
  10. Android(安卓)分页组件