如何在kernel/drivers/rtc/stm32f103 rtc alarmm.c文件中添加远源码

7177人阅读
Android开发文章(2)
很久之前写的一个流程文档,从上层界面一直调用到内核的过程,最近同事跟我要,我看了下又在整理了下,纯属个人分析(不过都运行验证过),不对的请大牛指出
Alarm 调用流程,alarm的流程实现了从上层应用一直到下面driver的调用流程,下面简单阐述:
./packages/apps/DeskClock/src/com/android/deskclock/Alarms.java
./frameworks/base/core/java/android/app/AlarmManager.java
./frameworks/base/services/java/com/android/server/AlarmManagerService.java
./frameworks/base/services/jni/com_android_server_AlarmManagerService.cpp
./kernel/kernel/drivers/rtc/alarm-dev.c
./kernel/kernel/include/linux/android_alarm.h
./kernel/kernel/drivers/rtc/alarm.c
./kernel/kernel/drivers/rtc/interface.c
./kernel/kernel/drivers/rtc/rtc-pcf8563.c
./packages/apps/DeskClock/src/com/android/deskclock/AlarmReceiver.java
./kernel/arch/arm/configs/mmp2_android_defconfig
./kernel/kernel/kernel/.config& &
点击Clock 应用程序,然后设置新闹钟,会调到& Alarms.java& 里面的
public static long setAlarm(Context context, Alarm alarm) {
setNextAlert(context);
然后这里面也会调用到 &
public static void setNextAlert(final Context context) {
&&&&&&& if (!enableSnoozeAlert(context)) {
&&&&&&&&&&& Alarm alarm = calculateNextAlert(context);&& //new 一个新的alarm
&&&&&&&&&&& if (alarm != null) {
&&&&&&&&&&&&&&& enableAlert(context, alarm, alarm.time);
&&&&&&&&&&& } else {
&&&&&&&&&&&&&&& disableAlert(context);
&&&&&&&&&&& }
然后继续调用到
private static void enableAlert(Context context, final Alarm alarm, final long atTimeInMillis) {
am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);&& //这里是RTC_WAKEUP, 这就保证了即使系统睡眠了,都能唤醒,闹钟工作(android平台关机闹钟好像不行)
然后就调用到了AlarmManager.java 里面方法
&&& public void set(int type, long triggerAtTime, PendingIntent operation) {
&&&&&&& try {
&&&&&&&&&&& mService.set(type, triggerAtTime, operation);
&&&&&&& } catch (RemoteException ex) {
然后就调用到了AlarmManagerService.java& 里面方法
public void set(int type, long triggerAtTime, PendingIntent operation) {
&&&&&&& setRepeating(type, triggerAtTime, 0, operation);
然后继续调用
public void setRepeating(int type, long triggerAtTime, long interval,
&&&&&&&&&&& PendingIntent operation) {
synchronized (mLock) {
&&&&&&&&&&& Alarm alarm = new Alarm();
&&&&&&&&&&& alarm.type =
&&&&&&&&&&& alarm.when = triggerAtT
&&&&&&&&&&& alarm.repeatInterval =
&&&&&&&&&&& alarm.operation =
&&&&&&&&&&& // Remove this alarm if already scheduled.
&&&&&&&&&&& removeLocked(operation);
&&&&&&&&&&& if (localLOGV) Slog.v(TAG, &set: & + alarm);
&&&&&&&&&&& int index = addAlarmLocked(alarm);
&&&&&&&&&&& if (index == 0) {
&&&&&&&&&&&&&&& setLocked(alarm);
&&&&&&&&&&& }
然后就调用到
private void setLocked(Alarm alarm)
&&& ......
&& &set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds);&& //mDescriptor& 这里的文件是 /dev/alarm
这里就调用到jni了
private native void set(int fd, int type, long seconds, long nanoseconds);
这就调用到了com_android_server_AlarmManagerService.cpp 里面
static JNINativeMethod sMethods[] = {
&&&& /* name, signature, funcPtr */
&& &{&init&, &()I&, (void*)android_server_AlarmManagerService_init},
&& &{&close&, &(I)V&, (void*)android_server_AlarmManagerService_close},
&& &{&set&, &(IIJJ)V&, (void*)android_server_AlarmManagerService_set},
&&& {&waitForAlarm&, &(I)I&, (void*)android_server_AlarmManagerService_waitForAlarm},
&&& {&setKernelTimezone&, &(II)I&, (void*)android_server_AlarmManagerService_setKernelTimezone},
set 对应的是android_server_AlarmManagerService_set, 具体是
static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds)
#if HAVE_ANDROID_OS
&&& ts.tv_sec =
&&& ts.tv_nsec =
&& &int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);
&& &if (result & 0)
&&&&&&& LOGE(&Unable to set alarm to %lld.%09lld: %s\n&, seconds, nanoseconds, strerror(errno));
然后ioctl 就调用到了alarm-dev.c
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
&& &case ANDROID_ALARM_SET(0):
&& &&& &if (copy_from_user(&new_alarm_time, (void __user *)arg,
&& &&& &&&& sizeof(new_alarm_time))) {
&& &&& &&& &rv = -EFAULT;
&& &&& &&& &goto err1;
from_old_alarm_set:
&& &&& &spin_lock_irqsave(&alarm_slock, flags);
&& &&& &pr_alarm(IO, &alarm %d set %ld.%09ld\n&, alarm_type,
&& &&& &&& &new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
&& &&& &alarm_enabled |= alarm_type_
&& &&& &alarm_start_range(&alarms[alarm_type],
&& &&& &&& &timespec_to_ktime(new_alarm_time),
&& &&& &&& &timespec_to_ktime(new_alarm_time));
&& &&& &spin_unlock_irqrestore(&alarm_slock, flags);
&& &&& &if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
&& &&& &&&& && cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
&& &&& &&& &
&& &&& &/* fall though */
case ANDROID_ALARM_SET_RTC:
&& &&& &if (copy_from_user(&new_rtc_time, (void __user *)arg,
&& &&& &&&& sizeof(new_rtc_time))) {
&& &&& &&& &rv = -EFAULT;
&& &&& &&& &goto err1;
&& &&& &rv = alarm_set_rtc(new_rtc_time);
&& &&& &spin_lock_irqsave(&alarm_slock, flags);
&& &&& &alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
&& &&& &wake_up(&alarm_wait_queue);
&& &&& &spin_unlock_irqrestore(&alarm_slock, flags);
&& &&& &if (rv & 0)
&& &&& &&& &goto err1;
然后这边就调用到了alarm_start_range& 设置闹钟,&& alarm_set_rtc& 设置RTC
这两个函数在 android_alarm.h 声明,在 alarm.c 里实现
这是android_alarm.h 里面的声明
void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end);
int alarm_try_to_cancel(struct alarm *alarm);
int alarm_cancel(struct alarm *alarm);
ktime_t alarm_get_elapsed_realtime(void);
/* set rtc while preserving elapsed realtime */
int alarm_set_rtc(const struct timespec ts);
下面看alarm.c 里面实现:
int alarm_set_rtc(struct timespec new_time)
ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
alarm.c& 里面实现了 alarm_suspend& alarm_resume 函数
就是如果系统没有suspend的时候,设置闹钟并不会往rtc 芯片的寄存器上写数据,因为不需要唤醒系统,所以闹钟数据时间什么的就通过上层写到设备文件/dev/alarm
里面就可以了,AlarmThread 会不停的去轮寻下一个时间有没有闹钟,直接从设备文件 /dev/alarm 里面读取
第二种,系统要是进入susupend的话,alarm 的alarm_suspend& 就会写到下层的rtc芯片的寄存器上去, 然后即使系统suspend之后,闹钟通过rtc 也能唤醒系统
这里就调用到了interface.c 里面&& //这里面 int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 差不多 也是跟下面一样
int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
&& &err = rtc-&ops-&set_time(rtc-&dev.parent, tm);
然后set_time 就看到具体的是那个RTC芯片,这边我们是rtc-pcf8563.c
static const struct rtc_class_ops pcf8563_rtc_ops = {
&& &.read_time&& &= pcf8563_rtc_read_time,
&& &.set_time&& &= pcf8563_rtc_set_time,
&& &.read_alarm&& &= pcf8563_rtc_read_alarm,
&& &.set_alarm&& &= pcf8563_rtc_set_alarm,
然后就到了
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
&& &unsigned char buf[TIME_NUM];
&& &ret = data_calc(buf, tm, TIME_NUM);
&& &if (ret & 0)
&& &ret = i2c_smbus_write_i2c_block_data(pcf8563_info-&client, PCF8563_RTC_SEC, TIME_NUM, buf);& //这边就调用i2c统一接口,往pcf8563rtc芯片寄存器里面写出数据
到此,闹钟时间就已经写到rtc 芯片的寄存器里面,第二个参数就是寄存器的名字,后面的buf就是要写入的时间,rtc芯片是额外供电的,所以系统suspend之后,系统kernel都关了,但是rtc里面还有电,寄存器里面数据还是有的(掉电就会丢失数据),所以闹钟到了,通过硬件中断机制就可以唤醒系统。
上面那个rtc下面有几十个rtc芯片驱动代码,没有结构基本一样,都有基本操作函数,注册函数,都是对各自芯片上特有的寄存器操作,为什么调用的是pcf8563rtc呢?这个要看你系统用的是那个芯片,这个可以通过./kernel/kernel/kernel/.config& 查看,这边的pcf8563rtc& 是当前系统正在使用的芯片型号 &
# CONFIG_RTC_DRV_ISL1208 is not set
# CONFIG_RTC_DRV_X1205 is not set
CONFIG_RTC_DRV_PCF8563=y
# CONFIG_RTC_DRV_PCF8583 is not set
# CONFIG_RTC_DRV_M41T80 is not set
下面是系统唤醒之后,闹钟怎么工作的流程,简单阐述
系统没有suspend的话直接走下面流程,如果suspend的话会被RTC唤醒,然后还是走下面的流程
&private class AlarmThread extends Thread
&&&&&&& public AlarmThread()
&&&&&&&&&&& super(&AlarmManager&);
&&&&&&& public void run()
&& &&&& while (true)
&&&&&&&&&&& {
&& &&& &int result = waitForAlarm(mDescriptor); //这里调用jni调用static jint android_server_AlarmManagerService_waitForAlarm,主要还是对 /dev/alarm& 操作
&& &&& &....
&& &&& &Alarm alarm = it.next();
&&&&&&&&&&&&&&&&&&&&&&& try {
&&&&&&&&&&&&&&&&&&&&&&&&&&& if (localLOGV) Slog.v(TAG, &sending alarm & + alarm);
&&&&&&&&&&&&&&&&&&&&&&&&&&& alarm.operation.send(mContext, 0,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& mBackgroundIntent.putExtra(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Intent.EXTRA_ALARM_COUNT, alarm.count),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& mResultReceiver, mHandler);
&& &&& &....
static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd)
#if HAVE_ANDROID_OS
&& &int result = 0;
&& &&& &result = ioctl(fd, ANDROID_ALARM_WAIT);
&& &} while (result & 0 && errno == EINTR);
&& &if (result & 0)
&&&&&&& LOGE(&Unable to wait on alarm: %s\n&, strerror(errno));
&&&&&&& return 0;
AlarmManagerService& 里面有个AlarmThread& 会一直轮询 /dev/alarm文件,如果打开失败就直接返回,成功就会做一些动作,比如查找时间最近的
alarm,比如睡眠被闹钟唤醒的时候,这边就发一个intent出去,然后在AlarmReceiver.java里面弹出里面会收到就会调用下面的
&& &&& &context.startActivity(alarmAlert);
然后弹出alarm& 这个界面
&&&&&&& Class c = AlarmAlert.
其中public class AlarmAlert extends AlarmAlertFullScreen& 所以系统睡眠之后被alarm唤醒弹出的alarm就是这边start的
public class AlarmReceiver extends BroadcastReceiver {
&&& /** If the alarm is older than STALE_WINDOW, ignore.& It
&&&&&&& is probably the result of a time or timezone change */
&&& private final static int STALE_WINDOW = 30 * 60 * 1000;
&&& @Override
&&& public void onReceive(Context context, Intent intent) {
&& &.........
&&&&&&& Intent alarmAlert = new Intent(context, c);
&&&&&&& alarmAlert.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm);
&&&&&&& alarmAlert.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
&&&&&&&&&&&&&&& | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
&&&&&&& context.startActivity(alarmAlert);
&& &........
到这里alarm 就显示出来了
我个人添加的log,验证了流程,suspend和不suspend的时候alarm的区别跟上面说的一样
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:34859次
排名:千里之外
评论:25条博客访问: 2634348
博文数量: 664
博客积分: 13321
博客等级: 上将
技术积分: 8525
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Android平台
作者:邹南,讲师。
在中,定时alarm功能是很常用的,现在来分析下怎么实现的,这里将采用自下而上的方式讲解。
arm: cortex-a8
&&&&&&&&Board: FS_S5PC100
&&&&&&&&: 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的情况下也会计时,当然要有后备电池的供电才可能。
计时器只要你配置好BCD寄存器即可,也就是填入当前的时间,年月日,时分秒。星期这些数据即可。当然在填写之前应该先将控制器寄存器使能。
定时器和计时器不同的地方在于,定时器的值寄存器填写的是触发中断的时间,当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 module *
&&&&&&&&&&&&&&&&char name[RTC_DEVICE_NAME_SIZE];
&&&&&&&&const struct rtc_class_ops *
&&&&&&&&&&&&&&&&struct mutex ops_
&&&&&&&&struct cdev char_
&&&&&&&&&&&&&&&&
&&&&&&&&unsigned long irq_
&&&&&&&&&&&&&&&&spinlock_t irq_
&&&&&&&&&&&&&&&&wait_queue_head_t irq_
&&&&&&&&&&&&&&&&struct fasync_struct *async_
&&&&&&&&struct rtc_task *irq_
&&&&&&&&&&&&&&&&spinlock_t irq_task_
&&&&&&&&&&&&&&&&int irq_
&&&&&&&&&&&&&&&&int max_user_
&&&&&&&&#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
&&&&&&&&&&&&&&&&struct work_struct uie_
&&&&&&&&&&&&&&&&struct timer_list uie_
&&&&&&&&&&&&&&&&/* Those fields are protected by rtc->irq_lock */
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&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)
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&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就是按照特定写法的版的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实现过来的接口。呵呵。
packages/apps/AlarmClock/src/com/android/alarmclock/ 这个目录下,就是系统自带定时器的源代码,比如Alarms.java 中:第一个导入的包就是
import android.app.AlarmM 怎样,到现在是否感受到了android从下至上分析的快感?
************************************************************************************************************************************************************************
很久之前写的一个流程文档,从上层界面一直调用到内核的过程,最近同事跟我要,我看了下又在整理了下,纯属个人分析(不过都运行验证过),不对的请大牛指出
Alarm 调用流程,alarm的流程实现了从上层应用一直到下面driver的调用流程,下面简单阐述:
./packages/apps/DeskClock/src/com/android/deskclock/Alarms.java
./frameworks/base/core/java/android/app/AlarmManager.java
./frameworks/base/services/java/com/android/server/AlarmManagerService.java
./frameworks/base/services/jni/com_android_server_AlarmManagerService.cpp
./kernel/kernel/drivers/rtc/alarm-dev.c
./kernel/kernel/include/linux/android_alarm.h
./kernel/kernel/drivers/rtc/alarm.c
./kernel/kernel/drivers/rtc/interface.c
./kernel/kernel/drivers/rtc/rtc-pcf8563.c
./packages/apps/DeskClock/src/com/android/deskclock/AlarmReceiver.java
./kernel/arch/arm/configs/mmp2_android_defconfig
./kernel/kernel/kernel/.config& &
点击Clock 应用程序,然后设置新闹钟,会调到& Alarms.java& 里面的
public static long setAlarm(Context context, Alarm alarm) {
setNextAlert(context);
然后这里面也会调用到 &
public static void setNextAlert(final Context context) {
&&&&&&& if (!enableSnoozeAlert(context)) {
&&&&&&&&&&& Alarm alarm = calculateNextAlert(context);&& //new 一个新的alarm
&&&&&&&&&&& if (alarm != null) {
&&&&&&&&&&&&&&& enableAlert(context, alarm, alarm.time);
&&&&&&&&&&& } else {
&&&&&&&&&&&&&&& disableAlert(context);
&&&&&&&&&&& }
然后继续调用到&
private static void enableAlert(Context context, final Alarm alarm, final long atTimeInMillis) {
am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);&& //这里是RTC_WAKEUP, 这就保证了即使系统睡眠了,都能唤醒,闹钟工作(android平台关机闹钟好像不行)
然后就调用到了AlarmManager.java 里面方法
&&& public void set(int type, long triggerAtTime, PendingIntent operation) {
&&&&&&& try {
&&&&&&&&&&& mService.set(type, triggerAtTime, operation);
&&&&&&& } catch (RemoteException ex) {
然后就调用到了AlarmManagerService.java& 里面方法
public void set(int type, long triggerAtTime, PendingIntent operation) {
&&&&&&& setRepeating(type, triggerAtTime, 0, operation);
然后继续调用
public void setRepeating(int type, long triggerAtTime, long interval,&
&&&&&&&&&&& PendingIntent operation) {
synchronized (mLock) {
&&&&&&&&&&& Alarm alarm = new Alarm();
&&&&&&&&&&& alarm.type =
&&&&&&&&&&& alarm.when = triggerAtT
&&&&&&&&&&& alarm.repeatInterval =
&&&&&&&&&&& alarm.operation =
&&&&&&&&&&& // Remove this alarm if already scheduled.
&&&&&&&&&&& removeLocked(operation);
&&&&&&&&&&& if (localLOGV) Slog.v(TAG, "set: " + alarm);
&&&&&&&&&&& int index = addAlarmLocked(alarm);
&&&&&&&&&&& if (index == 0) {
&&&&&&&&&&&&&&& setLocked(alarm);
&&&&&&&&&&& }
然后就调用到
private void setLocked(Alarm alarm)
&&& ......
&& &set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds);&& //mDescriptor& 这里的文件是 /dev/alarm
这里就调用到jni了
private native void set(int fd, int type, long seconds, long nanoseconds);
这就调用到了com_android_server_AlarmManagerService.cpp 里面
static JNINativeMethod sMethods[] = {
&&&& /* name, signature, funcPtr */
&& &{"init", "()I", (void*)android_server_AlarmManagerService_init},
&& &{"close", "(I)V", (void*)android_server_AlarmManagerService_close},
&& &{"set", "(IIJJ)V", (void*)android_server_AlarmManagerService_set},
&&& {"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm},
&&& {"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
set 对应的是android_server_AlarmManagerService_set, 具体是
static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds)
#if HAVE_ANDROID_OS
&&& ts.tv_sec =
&&& ts.tv_nsec =
&& &int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);
&& &if (result < 0)
&&&&&&& LOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno));
然后ioctl 就调用到了alarm-dev.c
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
&& &case ANDROID_ALARM_SET(0):
&& &&& &if (copy_from_user(&new_alarm_time, (void __user *)arg,
&& &&& &&&& sizeof(new_alarm_time))) {
&& &&& &&& &rv = -EFAULT;
&& &&& &&& &goto err1;
from_old_alarm_set:
&& &&& &spin_lock_irqsave(&alarm_slock, flags);
&& &&& &pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
&& &&& &&& &new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
&& &&& &alarm_enabled |= alarm_type_
&& &&& &alarm_start_range(&alarms[alarm_type],
&& &&& &&& &timespec_to_ktime(new_alarm_time),
&& &&& &&& &timespec_to_ktime(new_alarm_time));
&& &&& &spin_unlock_irqrestore(&alarm_slock, flags);
&& &&& &if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
&& &&& &&&& && cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
&& &&& &&& &
&& &&& &/* fall though */
case ANDROID_ALARM_SET_RTC:
&& &&& &if (copy_from_user(&new_rtc_time, (void __user *)arg,
&& &&& &&&& sizeof(new_rtc_time))) {
&& &&& &&& &rv = -EFAULT;
&& &&& &&& &goto err1;
&& &&& &rv = alarm_set_rtc(new_rtc_time);
&& &&& &spin_lock_irqsave(&alarm_slock, flags);
&& &&& &alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
&& &&& &wake_up(&alarm_wait_queue);
&& &&& &spin_unlock_irqrestore(&alarm_slock, flags);
&& &&& &if (rv < 0)
&& &&& &&& &goto err1;
然后这边就调用到了alarm_start_range& 设置闹钟,&& alarm_set_rtc& 设置RTC
这两个函数在 android_alarm.h 声明,在 alarm.c 里实现
这是android_alarm.h 里面的声明
void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end);
int alarm_try_to_cancel(struct alarm *alarm);
int alarm_cancel(struct alarm *alarm);
ktime_t alarm_get_elapsed_realtime(void);
/* set rtc while preserving elapsed realtime */
int alarm_set_rtc(const struct timespec ts);
下面看alarm.c 里面实现:
int alarm_set_rtc(struct timespec new_time)
ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
alarm.c& 里面实现了 alarm_suspend& alarm_resume 函数
就是如果系统没有suspend的时候,设置闹钟并不会往rtc 芯片的寄存器上写数据,因为不需要唤醒系统,所以闹钟数据时间什么的就通过上层写到设备文件/dev/alarm
里面就可以了,AlarmThread 会不停的去轮寻下一个时间有没有闹钟,直接从设备文件 /dev/alarm 里面读取
第二种,系统要是进入susupend的话,alarm 的alarm_suspend& 就会写到下层的rtc芯片的寄存器上去, 然后即使系统suspend之后,闹钟通过rtc 也能唤醒系统
这里就调用到了interface.c 里面&& //这里面 int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 差不多 也是跟下面一样
int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
&& &err = rtc->ops->set_time(rtc->dev.parent, tm);
然后set_time 就看到具体的是那个RTC芯片,这边我们是rtc-pcf8563.c
static const struct rtc_class_ops pcf8563_rtc_ops = {
&& &.read_time&& &= pcf8563_rtc_read_time,
&& &.set_time&& &= pcf8563_rtc_set_time,
&& &.read_alarm&& &= pcf8563_rtc_read_alarm,
&& &.set_alarm&& &= pcf8563_rtc_set_alarm,
然后就到了
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
&& &unsigned char buf[TIME_NUM];
&& &ret = data_calc(buf, tm, TIME_NUM);
&& &if (ret < 0)
&& &ret = i2c_smbus_write_i2c_block_data(pcf8563_info->client, PCF8563_RTC_SEC, TIME_NUM, buf);& //这边就调用i2c统一接口,往pcf8563rtc芯片寄存器里面写出数据
到此,闹钟时间就已经写到rtc 芯片的寄存器里面,第二个参数就是寄存器的名字,后面的buf就是要写入的时间,rtc芯片是额外供电的,所以系统suspend之后,系统kernel都关了,但是rtc里面还有电,寄存器里面数据还是有的(掉电就会丢失数据),所以闹钟到了,通过硬件中断机制就可以唤醒系统。
上面那个rtc下面有几十个rtc芯片驱动代码,没有结构基本一样,都有基本操作函数,注册函数,都是对各自芯片上特有的寄存器操作,为什么调用的是pcf8563rtc呢?这个要看你系统用的是那个芯片,这个可以通过./kernel/kernel/kernel/.config& 查看,这边的pcf8563rtc& 是当前系统正在使用的芯片型号 &
# CONFIG_RTC_DRV_ISL1208 is not set
# CONFIG_RTC_DRV_X1205 is not set
CONFIG_RTC_DRV_PCF8563=y
# CONFIG_RTC_DRV_PCF8583 is not set
# CONFIG_RTC_DRV_M41T80 is not set
下面是系统唤醒之后,闹钟怎么工作的流程,简单阐述
系统没有suspend的话直接走下面流程,如果suspend的话会被RTC唤醒,然后还是走下面的流程
&private class AlarmThread extends Thread
&&&&&&& public AlarmThread()
&&&&&&&&&&& super("AlarmManager");
&&&&&&& public void run()
&&&&&&& {&
&& &&&& while (true)
&&&&&&&&&&& {
&& &&& &int result = waitForAlarm(mDescriptor); //这里调用jni调用static jint android_server_AlarmManagerService_waitForAlarm,主要还是对 /dev/alarm& 操作
&& &&& &....
&& &&& &Alarm alarm = it.next();
&&&&&&&&&&&&&&&&&&&&&&& try {
&&&&&&&&&&&&&&&&&&&&&&&&&&& if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
&&&&&&&&&&&&&&&&&&&&&&&&&&& alarm.operation.send(mContext, 0,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& mBackgroundIntent.putExtra(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Intent.EXTRA_ALARM_COUNT, alarm.count),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& mResultReceiver, mHandler);
&& &&& &....
static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd)
#if HAVE_ANDROID_OS
&& &int result = 0;
&& &&& &result = ioctl(fd, ANDROID_ALARM_WAIT);
&& &} while (result < 0 && errno == EINTR);
&& &if (result < 0)
&&&&&&& LOGE("Unable to wait on alarm: %s\n", strerror(errno));
&&&&&&& return 0;
AlarmManagerService& 里面有个AlarmThread& 会一直轮询 /dev/alarm文件,如果打开失败就直接返回,成功就会做一些动作,比如查找时间最近的
alarm,比如睡眠被闹钟唤醒的时候,这边就发一个intent出去,然后在AlarmReceiver.java里面弹出里面会收到就会调用下面的
&& &&& &context.startActivity(alarmAlert);
然后弹出alarm& 这个界面
&&&&&&& Class c = AlarmAlert.
其中public class AlarmAlert extends AlarmAlertFullScreen& 所以系统睡眠之后被alarm唤醒弹出的alarm就是这边start的
public class AlarmReceiver extends BroadcastReceiver {
&&& /** If the alarm is older than STALE_WINDOW, ignore.& It
&&&&&&& is probably the result of a time or timezone change */
&&& private final static int STALE_WINDOW = 30 * 60 * 1000;
&&& @Override
&&& public void onReceive(Context context, Intent intent) {
&& &.........
&&&&&&& Intent alarmAlert = new Intent(context, c);
&&&&&&& alarmAlert.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm);
&&&&&&& alarmAlert.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
&&&&&&&&&&&&&&& | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
&&&&&&& context.startActivity(alarmAlert);
&& &........
到这里alarm 就显示出来了
我个人添加的log,验证了流程,suspend和不suspend的时候alarm的区别跟上面说的一样
阅读(5204) | 评论(0) | 转发(1) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。

我要回帖

更多关于 stm32f103 rtc alarm 的文章

 

随机推荐