提供做网站费用,网站开发素材,凡科建站收费,wordpress优化网站打开速度1.首先搞清楚RTC在kernel内的作用: linux系统有两个时钟#xff1a;一个是由主板电池驱动的“Real Time Clock”也叫做RTC或者叫CMOS时钟#xff0c;硬件时钟。当操作系统关机的时候#xff0c;用这个来记录时间#xff0c;但是对于运行的系统是不用这个时间的。 另一个时间… 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 (reg0x80) { 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 havent 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。