android RTC

来源:互联网 发布:javascript 教程 pdf 编辑:程序博客网 时间:2024/06/05 09:47

http://blog.csdn.net/crycheng/article/details/7802502

1.首先搞清楚RTC在kernel内的作用: linux系统有两个时钟:一个是由主板电池驱动的“Real Time Clock”也叫做RTC或者叫CMOS时钟,硬件时钟。当操作系统关机的时候,用这个来记录时间,但是对于运行的系统是不用这个时间的。

另一个时间是 “System clock”也叫内核时钟或者软件时钟,是由软件根据时间中断来进行计数的,内核时钟在系统关机的情况下是不存在的,所以,当操作系统启动的时候,内核时钟是要读取RTC时间来进行时间同步。并且在系统关机的时候将系统时间写回RTC中进行同步。 如前所述,Linux内核与RTC进行互操作的时机只有两个:

1) 内核在启动时从RTC中读取启动时的时间与日期;

2) 内核在需要时将时间与日期回写到RTC中。 系统启动时,内核通过读取RTC来初始化内核时钟,又叫墙上时间,该时间放在xtime变量中。

[cpp] view plaincopy
  1. The current time of day (the wall time) is defined in kernel/timer.c:  
  2. struct timespec xtime;  
  3. The timespec data structure is defined in <linux/time.h> as:  
  4. struct timespec {  
  5.   time_t tv_sec;               /* seconds */  
  6.   long tv_nsec;                /* nanoseconds */  
  7. };  

最有可能读取RTC设置内核时钟的位置应该在arch/arm/kernel/time.c里的time_init函数内.time.c为系统的时钟驱动部分.

time_init函数会在系统初始化时,由init/main.c里的start_kernel函数内调用. ARM架构的time_init代码如下:

/* arch/arm/kernel/time.c */

[cpp] view plaincopy
  1. void __init time_init(void)  
  2. {  
  3.     system_timer = machine_desc->timer;  
  4.     system_timer->init();  
  5. #ifdef CONFIG_HAVE_SCHED_CLOCK  
  6.     sched_clock_postinit();  
  7. #endif  
  8. }  

2.RTC结构部分
[cpp] view plaincopy
  1. static const struct rtc_class_ops hym8563_rtc_ops = {  
  2.     .read_time  = hym8563_rtc_read_time,  
  3.     .set_time   = hym8563_rtc_set_time,  
  4.     .read_alarm = hym8563_rtc_read_alarm,  
  5.     .set_alarm  = hym8563_rtc_set_alarm,  
  6.     .ioctl      = hym8563_rtc_ioctl,  
  7.     .proc       = hym8563_rtc_proc  
  8. };  
  9.   
  10. static int __devinit hym8563_probe(struct i2c_client *client, const struct i2c_device_id *id)  
  11. {  
  12.     int rc = 0;  
  13.     u8 reg = 0;  
  14.     struct hym8563 *hym8563;  
  15.     struct rtc_device *rtc = NULL;  
  16.     struct rtc_time tm_read, tm = {  
  17.         .tm_wday = 6,  
  18.         .tm_year = 111,  
  19.         .tm_mon = 0,  
  20.         .tm_mday = 1,  
  21.         .tm_hour = 12,  
  22.         .tm_min = 0,  
  23.         .tm_sec = 0,  
  24.     };    
  25.       
  26.     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))  
  27.         return -ENODEV;  
  28.           
  29.     hym8563 = kzalloc(sizeof(struct hym8563), GFP_KERNEL);  
  30.     if (!hym8563) {  
  31.         return -ENOMEM;  
  32.     }  
  33.     gClient = client;     
  34.     hym8563->client = client;  
  35.     mutex_init(&hym8563->mutex);  
  36.     wake_lock_init(&hym8563->wake_lock, WAKE_LOCK_SUSPEND, "rtc_hym8563");  
  37.     INIT_WORK(&hym8563->work, hym8563_work_func);  
  38.     i2c_set_clientdata(client, hym8563);  
  39.   
  40.     hym8563_init_device(client);  
  41.   
  42.     // check power down   
  43.     hym8563_i2c_read_regs(client,RTC_SEC,®,1);  
  44.     if (reg&0x80) {  
  45.         dev_info(&client->dev, "clock/calendar information is no longer guaranteed\n");  
  46.         hym8563_set_time(client, &tm);  
  47.     }  
  48.   
  49.     hym8563_read_datetime(client, &tm_read);    //read time from hym8563  
  50.       
  51.     if(((tm_read.tm_year < 70) | (tm_read.tm_year > 137 )) | (tm_read.tm_mon == -1) | (rtc_valid_tm(&tm_read) != 0)) //if the hym8563 haven't initialized  
  52.     {  
  53.         hym8563_set_time(client, &tm);  //initialize the hym8563   
  54.     }     
  55.       
  56.     if(gpio_request(client->irq, "rtc gpio"))  
  57.     {  
  58.         dev_err(&client->dev, "gpio request fail\n");  
  59.         gpio_free(client->irq);  
  60.         goto exit;  
  61.     }  
  62.       
  63.     hym8563->irq = gpio_to_irq(client->irq);  
  64.     gpio_pull_updown(client->irq,GPIOPullUp);  
  65.     if (request_irq(hym8563->irq, hym8563_wakeup_irq, IRQF_TRIGGER_FALLING, client->dev.driver->name, hym8563) < 0)  
  66.     {  
  67.         printk("unable to request rtc irq\n");  
  68.         goto exit;  
  69.     }     
  70.     enable_irq_wake(hym8563->irq);  
  71.   
  72.     rtc = rtc_device_register(client->name, &client->dev,  
  73.                   &hym8563_rtc_ops, THIS_MODULE);  
  74.     if (IS_ERR(rtc)) {  
  75.         rc = PTR_ERR(rtc);  
  76.         rtc = NULL;  
  77.         goto exit;  
  78.     }  
  79.     hym8563->rtc = rtc;  
  80.   
  81.     return 0;  
  82.   
  83. exit:  
  84.     if (rtc)  
  85.         rtc_device_unregister(rtc);  
  86.     if (hym8563)  
  87.         kfree(hym8563);  
  88.     return rc;  
  89. }  

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

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

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

也就是说在和内核层以上的交互是通过alarm-dev.c里面的alarm_ioctl及其余的函数交互,但是在这个文件里面的rtc_set_time/rtc_get_time操作是为了设置RTC时间等的操作是调用alarm.c里面的函数,但是alarm.c驱动本身和硬件没有关系,在这里屏蔽了RTC的硬件操作,比如HYM8563的时间I2C硬件驱动操作在rtc-HYM8563.c驱动里,只需要使用 rtc_class_ops进行注册就可以了,完整的实现了硬件对平台无关性的屏蔽。

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

3.JNI层

[cpp] view plaincopy
  1. namespace android {  
  2.   
  3. static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest)  
  4. {  
  5.     struct timezone tz;  
  6.   
  7.     tz.tz_minuteswest = minswest;  
  8.     tz.tz_dsttime = 0;  
  9.   
  10.     int result = settimeofday(NULL, &tz);  
  11.     if (result < 0) {  
  12.         LOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));  
  13.         return -1;  
  14.     } else {  
  15.         LOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);  
  16.     }  
  17.   
  18.     return 0;  
  19. }  
  20.   
  21. static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj)  
  22. {  
  23.     return open("/dev/alarm", O_RDWR);  
  24. }  
  25.   
  26. static void android_server_AlarmManagerService_close(JNIEnv* env, jobject obj, jint fd)  
  27. {  
  28.     close(fd);  
  29. }  
  30.   
  31. static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds)  
  32. {  
  33.     struct timespec ts;  
  34.     ts.tv_sec = seconds;  
  35.     ts.tv_nsec = nanoseconds;  
  36.   
  37.     int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);  
  38.     if (result < 0)  
  39.     {  
  40.         LOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno));  
  41.     }  
  42. }  
  43.   
  44. static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd)  
  45. {  
  46.     int result = 0;  
  47.   
  48.     do  
  49.     {  
  50.         result = ioctl(fd, ANDROID_ALARM_WAIT);  
  51.     } while (result < 0 && errno == EINTR);  
  52.   
  53.     if (result < 0)  
  54.     {  
  55.         LOGE("Unable to wait on alarm: %s\n", strerror(errno));  
  56.         return 0;  
  57.     }  
  58.   
  59.     return result;  
  60. }  
  61.   
  62. static JNINativeMethod sMethods[] = {  
  63.      /* name, signature, funcPtr */  
  64.     {"init""()I", (void*)android_server_AlarmManagerService_init},  
  65.     {"close""(I)V", (void*)android_server_AlarmManagerService_close},  
  66.     {"set""(IIJJ)V", (void*)android_server_AlarmManagerService_set},  
  67.     {"waitForAlarm""(I)I", (void*)android_server_AlarmManagerService_waitForAlarm},  
  68.     {"setKernelTimezone""(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone},  
  69. };  
  70.   
  71. int register_android_server_AlarmManagerService(JNIEnv* env)  
  72. {  
  73.     return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",  
  74.                                     sMethods, NELEM(sMethods));  
  75. }  
  76.   
  77. /* namespace android */  

其实在JNI层这里RTC就和其余的模块一样,直接去通过打开/关闭/设置/等待等来操作节点/dev/alarm和底层进行通信,不仔细解释。

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拿来在此调用一下而已。然后包装一下,将功能实现得更完美些。

5.App层
[cpp] view plaincopy
  1. package android.app;  
  2. import android.content.Context;  
  3. import android.content.Intent;  
  4. import android.os.RemoteException;  
  5. import android.os.ServiceManager;  
  6. public class AlarmManager  
  7. {  
  8.     public static final int RTC_WAKEUP = 0;  
  9.     public static final int RTC = 1;  
  10.     public static final int ELAPSED_REALTIME_WAKEUP = 2;  
  11.     public static final int ELAPSED_REALTIME = 3;  
  12.     private final IAlarmManager mService;  
  13.     AlarmManager(IAlarmManager service) {  
  14.         mService = service;  
  15.     }  
  16.       
  17.     public void set(int type, long triggerAtTime, PendingIntent operation) {  
  18.         try {  
  19.             mService.set(type, triggerAtTime, operation);  
  20.         } catch (RemoteException ex) {  
  21.         }  
  22.     }  
  23.   
  24.     public void setRepeating(int type, long triggerAtTime, long interval,  
  25.             PendingIntent operation) {  
  26.         try {  
  27.             mService.setRepeating(type, triggerAtTime, interval, operation);  
  28.         } catch (RemoteException ex) {  
  29.         }  
  30.     }  
  31.   
  32.     public static final long INTERVAL_FIFTEEN_MINUTES = 15 * 60 * 1000;  
  33.     public static final long INTERVAL_HALF_HOUR = 2*INTERVAL_FIFTEEN_MINUTES;  
  34.     public static final long INTERVAL_HOUR = 2*INTERVAL_HALF_HOUR;  
  35.     public static final long INTERVAL_HALF_DAY = 12*INTERVAL_HOUR;  
  36.     public static final long INTERVAL_DAY = 2*INTERVAL_HALF_DAY;  
  37.       
  38.     public void setInexactRepeating(int type, long triggerAtTime, long interval,  
  39.             PendingIntent operation) {  
  40.         try {  
  41.             mService.setInexactRepeating(type, triggerAtTime, interval, operation);  
  42.         } catch (RemoteException ex) {  
  43.         }  
  44.     }  
  45.       
  46.     public void cancel(PendingIntent operation) {  
  47.         try {  
  48.             mService.remove(operation);  
  49.         } catch (RemoteException ex) {  
  50.         }  
  51.     }  
  52.   
  53.     public void setTime(long millis) {  
  54.         try {  
  55.             mService.setTime(millis);  
  56.         } catch (RemoteException ex) {  
  57.         }  
  58.     }  
  59.   
  60.     public void setTimeZone(String timeZone) {  
  61.         try {  
  62.             mService.setTimeZone(timeZone);  
  63.         } catch (RemoteException ex) {  
  64.         }  
  65.     }  
  66. }  

frameworks\base\core\java\android\app 这个目录下,就是系统自带定时器的源代码,比如Alarms.java 中:第一个导入的包就是 import android.app.AlarmManager。
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 结痂不小心抠掉怎么办 脸上肉松弛怎么办19岁 点痣留下来的疤怎么办 激光祛斑的红印怎么办 脸上疤掉了红印怎么办 痘痘发炎了红肿怎么办 脸上的斑越来越多了怎么办 点痣留下的疤痕怎么办 额头又高又大怎么办 脸太长额头太高怎么办 动车因台风停运怎么办 爸妈50了要离婚怎么办 鸿利彩票黑了钱怎么办 忘了锁屏图案怎么办 黄金被水银沾上怎么办 被股东了我该怎么办 异地恋没话题聊怎么办 谈了半年分手了怎么办 博士6年没毕业怎么办 发现孩子早恋家长应该怎么办 异地恋想嘿嘿嘿怎么办 妈妈溜冰溜大了怎么办 皮鞋被雨水泡了怎么办 老婆提出离婚我不想离怎么办 极度缺爱的人怎么办 生二胎住院大宝怎么办 爸妈偏心我该怎么办 无创21体高风险怎么办 无创检查高风险怎么办 唐氏筛查21三体高危怎么办 唐筛年龄高风险怎么办 21三体综合症高风险怎么办 朋友深陷李强365怎么办 飞机上烟瘾犯了怎么办 怀孕一个月吸烟了怎么办 烟瘾犯了没烟怎么办 押金交了不租了怎么办 买车首付款不够怎么办 双11订金不退怎么办 在商场买到假货怎么办 网上买到假手机怎么办