在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实现定时器功能
  2. Android中定时器的3种实现方法
  3. Android之计时器(Chronometer)的用法
  4. 浅入浅出Android(012):Android下的计时器
  5. android 定时器(Handler Timer Thread AlarmManager CountDownTi
  6. android 定时器,每秒变换一次图片!
  7. Android 设置合理的定时器隔一段时间执行某段程序
  8. Chronometer android计时器组件Chronometer的使用,android通话时
  9. Android中实现计时器的功能

随机推荐

  1. 加快 Node.js 应用的启动速度
  2. 基于Springboot docker jenkins 自动化部
  3. MongoDB 4.X CRUD的基本操作说明
  4. 镜像格式:从 Knoppix 到 OCI-Image-v2
  5. 最热门的Linux桌面操作系统前十名
  6. 用一文了解 Kubernetes
  7. 使用阿里云镜像搭建 npm 私有镜像仓库
  8. Docker 镜像制作:针对不同语言的精简策略
  9. CentOS环境下快速安装软件
  10. Maven 无法下载依赖包的问题