android RTC

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變量中。

  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 */

  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結構部分
  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層

  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層
  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。
發佈了42 篇原創文章 · 獲贊 16 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章