日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android RTC 自下往上浅析

發布時間:2023/12/20 Android 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android RTC 自下往上浅析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.首先搞清楚RTC在kernel內的作用: linux系統有兩個時鐘:一個是由主板電池驅動的“Real Time Clock”也叫做RTC或者叫CMOS時鐘,硬件時鐘。當操作系統關機的時候,用這個來記錄時間,但是對于運行的系統是不用這個時間的。

另一個時間是 “System clock”也叫內核時鐘或者軟件時鐘,是由軟件根據時間中斷來進行計數的,內核時鐘在系統關機的情況下是不存在的,所以,當操作系統啟動的時候,內核時鐘是要讀取RTC時間來進行時間同步。并且在系統關機的時候將系統時間寫回RTC中進行同步。 如前所述,Linux內核與RTC進行互操作的時機只有兩個:

1) 內核在啟動時從RTC中讀取啟動時的時間與日期;

2) 內核在需要時將時間與日期回寫到RTC中。 系統啟動時,內核通過讀取RTC來初始化內核時鐘,又叫墻上時間,該時間放在xtime變量中。

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

  • 最有可能讀取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
  • void?__init?time_init(void)??
  • {??
  • ????system_timer?=?machine_desc->timer;??
  • ????system_timer->init();??
  • #ifdef?CONFIG_HAVE_SCHED_CLOCK??
  • ????sched_clock_postinit();??
  • #endif??
  • }??

  • 2.RTC結構部分
    [cpp]?view plaincopy
  • static?const?struct?rtc_class_ops?hym8563_rtc_ops?=?{??
  • ????.read_time??=?hym8563_rtc_read_time,??
  • ????.set_time???=?hym8563_rtc_set_time,??
  • ????.read_alarm?=?hym8563_rtc_read_alarm,??
  • ????.set_alarm??=?hym8563_rtc_set_alarm,??
  • ????.ioctl??????=?hym8563_rtc_ioctl,??
  • ????.proc???????=?hym8563_rtc_proc??
  • };??
  • ??
  • static?int?__devinit?hym8563_probe(struct?i2c_client?*client,?const?struct?i2c_device_id?*id)??
  • {??
  • ????int?rc?=?0;??
  • ????u8?reg?=?0;??
  • ????struct?hym8563?*hym8563;??
  • ????struct?rtc_device?*rtc?=?NULL;??
  • ????struct?rtc_time?tm_read,?tm?=?{??
  • ????????.tm_wday?=?6,??
  • ????????.tm_year?=?111,??
  • ????????.tm_mon?=?0,??
  • ????????.tm_mday?=?1,??
  • ????????.tm_hour?=?12,??
  • ????????.tm_min?=?0,??
  • ????????.tm_sec?=?0,??
  • ????};????
  • ??????
  • ????if?(!i2c_check_functionality(client->adapter,?I2C_FUNC_I2C))??
  • ????????return?-ENODEV;??
  • ??????????
  • ????hym8563?=?kzalloc(sizeof(struct?hym8563),?GFP_KERNEL);??
  • ????if?(!hym8563)?{??
  • ????????return?-ENOMEM;??
  • ????}??
  • ????gClient?=?client;?????
  • ????hym8563->client?=?client;??
  • ????mutex_init(&hym8563->mutex);??
  • ????wake_lock_init(&hym8563->wake_lock,?WAKE_LOCK_SUSPEND,?"rtc_hym8563");??
  • ????INIT_WORK(&hym8563->work,?hym8563_work_func);??
  • ????i2c_set_clientdata(client,?hym8563);??
  • ??
  • ????hym8563_init_device(client);??
  • ??
  • ????//?check?power?down???
  • ????hym8563_i2c_read_regs(client,RTC_SEC,?,1);??
  • ????if?(reg&0x80)?{??
  • ????????dev_info(&client->dev,?"clock/calendar?information?is?no?longer?guaranteed\n");??
  • ????????hym8563_set_time(client,?&tm);??
  • ????}??
  • ??
  • ????hym8563_read_datetime(client,?&tm_read);????//read?time?from?hym8563??
  • ??????
  • ????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??
  • ????{??
  • ????????hym8563_set_time(client,?&tm);??//initialize?the?hym8563???
  • ????}?????
  • ??????
  • ????if(gpio_request(client->irq,?"rtc?gpio"))??
  • ????{??
  • ????????dev_err(&client->dev,?"gpio?request?fail\n");??
  • ????????gpio_free(client->irq);??
  • ????????goto?exit;??
  • ????}??
  • ??????
  • ????hym8563->irq?=?gpio_to_irq(client->irq);??
  • ????gpio_pull_updown(client->irq,GPIOPullUp);??
  • ????if?(request_irq(hym8563->irq,?hym8563_wakeup_irq,?IRQF_TRIGGER_FALLING,?client->dev.driver->name,?hym8563)?<?0)??
  • ????{??
  • ????????printk("unable?to?request?rtc?irq\n");??
  • ????????goto?exit;??
  • ????}?????
  • ????enable_irq_wake(hym8563->irq);??
  • ??
  • ????rtc?=?rtc_device_register(client->name,?&client->dev,??
  • ??????????????????&hym8563_rtc_ops,?THIS_MODULE);??
  • ????if?(IS_ERR(rtc))?{??
  • ????????rc?=?PTR_ERR(rtc);??
  • ????????rtc?=?NULL;??
  • ????????goto?exit;??
  • ????}??
  • ????hym8563->rtc?=?rtc;??
  • ??
  • ????return?0;??
  • ??
  • exit:??
  • ????if?(rtc)??
  • ????????rtc_device_unregister(rtc);??
  • ????if?(hym8563)??
  • ????????kfree(hym8563);??
  • ????return?rc;??
  • }??

  • 看這兩個結構體,我認為就已經達到目的,第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
  • namespace?android?{??
  • ??
  • static?jint?android_server_AlarmManagerService_setKernelTimezone(JNIEnv*?env,?jobject?obj,?jint?fd,?jint?minswest)??
  • {??
  • ????struct?timezone?tz;??
  • ??
  • ????tz.tz_minuteswest?=?minswest;??
  • ????tz.tz_dsttime?=?0;??
  • ??
  • ????int?result?=?settimeofday(NULL,?&tz);??
  • ????if?(result?<?0)?{??
  • ????????LOGE("Unable?to?set?kernel?timezone?to?%d:?%s\n",?minswest,?strerror(errno));??
  • ????????return?-1;??
  • ????}?else?{??
  • ????????LOGD("Kernel?timezone?updated?to?%d?minutes?west?of?GMT\n",?minswest);??
  • ????}??
  • ??
  • ????return?0;??
  • }??
  • ??
  • static?jint?android_server_AlarmManagerService_init(JNIEnv*?env,?jobject?obj)??
  • {??
  • ????return?open("/dev/alarm",?O_RDWR);??
  • }??
  • ??
  • static?void?android_server_AlarmManagerService_close(JNIEnv*?env,?jobject?obj,?jint?fd)??
  • {??
  • ????close(fd);??
  • }??
  • ??
  • static?void?android_server_AlarmManagerService_set(JNIEnv*?env,?jobject?obj,?jint?fd,?jint?type,?jlong?seconds,?jlong?nanoseconds)??
  • {??
  • ????struct?timespec?ts;??
  • ????ts.tv_sec?=?seconds;??
  • ????ts.tv_nsec?=?nanoseconds;??
  • ??
  • ????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));??
  • ????}??
  • }??
  • ??
  • static?jint?android_server_AlarmManagerService_waitForAlarm(JNIEnv*?env,?jobject?obj,?jint?fd)??
  • {??
  • ????int?result?=?0;??
  • ??
  • ????do??
  • ????{??
  • ????????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;??
  • ????}??
  • ??
  • ????return?result;??
  • }??
  • ??
  • 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},??
  • };??
  • ??
  • int?register_android_server_AlarmManagerService(JNIEnv*?env)??
  • {??
  • ????return?jniRegisterNativeMethods(env,?"com/android/server/AlarmManagerService",??
  • ????????????????????????????????????sMethods,?NELEM(sMethods));??
  • }??
  • ??
  • }?/*?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
  • package?android.app;??
  • import?android.content.Context;??
  • import?android.content.Intent;??
  • import?android.os.RemoteException;??
  • import?android.os.ServiceManager;??
  • public?class?AlarmManager??
  • {??
  • ????public?static?final?int?RTC_WAKEUP?=?0;??
  • ????public?static?final?int?RTC?=?1;??
  • ????public?static?final?int?ELAPSED_REALTIME_WAKEUP?=?2;??
  • ????public?static?final?int?ELAPSED_REALTIME?=?3;??
  • ????private?final?IAlarmManager?mService;??
  • ????AlarmManager(IAlarmManager?service)?{??
  • ????????mService?=?service;??
  • ????}??
  • ??????
  • ????public?void?set(int?type,?long?triggerAtTime,?PendingIntent?operation)?{??
  • ????????try?{??
  • ????????????mService.set(type,?triggerAtTime,?operation);??
  • ????????}?catch?(RemoteException?ex)?{??
  • ????????}??
  • ????}??
  • ??
  • ????public?void?setRepeating(int?type,?long?triggerAtTime,?long?interval,??
  • ????????????PendingIntent?operation)?{??
  • ????????try?{??
  • ????????????mService.setRepeating(type,?triggerAtTime,?interval,?operation);??
  • ????????}?catch?(RemoteException?ex)?{??
  • ????????}??
  • ????}??
  • ??
  • ????public?static?final?long?INTERVAL_FIFTEEN_MINUTES?=?15?*?60?*?1000;??
  • ????public?static?final?long?INTERVAL_HALF_HOUR?=?2*INTERVAL_FIFTEEN_MINUTES;??
  • ????public?static?final?long?INTERVAL_HOUR?=?2*INTERVAL_HALF_HOUR;??
  • ????public?static?final?long?INTERVAL_HALF_DAY?=?12*INTERVAL_HOUR;??
  • ????public?static?final?long?INTERVAL_DAY?=?2*INTERVAL_HALF_DAY;??
  • ??????
  • ????public?void?setInexactRepeating(int?type,?long?triggerAtTime,?long?interval,??
  • ????????????PendingIntent?operation)?{??
  • ????????try?{??
  • ????????????mService.setInexactRepeating(type,?triggerAtTime,?interval,?operation);??
  • ????????}?catch?(RemoteException?ex)?{??
  • ????????}??
  • ????}??
  • ??????
  • ????public?void?cancel(PendingIntent?operation)?{??
  • ????????try?{??
  • ????????????mService.remove(operation);??
  • ????????}?catch?(RemoteException?ex)?{??
  • ????????}??
  • ????}??
  • ??
  • ????public?void?setTime(long?millis)?{??
  • ????????try?{??
  • ????????????mService.setTime(millis);??
  • ????????}?catch?(RemoteException?ex)?{??
  • ????????}??
  • ????}??
  • ??
  • ????public?void?setTimeZone(String?timeZone)?{??
  • ????????try?{??
  • ????????????mService.setTimeZone(timeZone);??
  • ????????}?catch?(RemoteException?ex)?{??
  • ????????}??
  • ????}??
  • }??

  • frameworks\base\core\java\android\app? 這個目錄下,就是系統自帶定時器的源代碼,比如Alarms.java 中:第一個導入的包就是 import android.app.AlarmManager。

    總結

    以上是生活随笔為你收集整理的Android RTC 自下往上浅析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。