通用模块(5)——RTC模块

本文详细解析了Android系统中设置RTC时间的内核调用流程,从用户空间的AlarmManagerService通过JNI调用到内核驱动,再到rtc-rx8010.c的具体实现。涉及的关键函数包括alarm_ioctl、rtc_set_time、rtc_read_time等,展示了内核与硬件RTC设备间的交互机制。
摘要由CSDN通过智能技术生成
参考链接:
https://blog.csdn.net/bb807777/article/details/80447747

https://blog.csdn.net/u011290127/article/details/95401602

rtc架构

kernel-3.4.39/include/linux/rtc.h
struct rtc_class_ops {
        int (*open)(struct device *);
        void (*release)(struct device *);
        int (*ioctl)(struct device *, unsigned int, unsigned long);
        int (*read_time)(struct device *, struct rtc_time *);
        int (*set_time)(struct device *, struct rtc_time *);
        int (*read_alarm)(struct device *, struct rtc_wkalrm *);
        int (*set_alarm)(struct device *, struct rtc_wkalrm *);
        int (*proc)(struct device *, struct seq_file *);
        int (*set_mmss)(struct device *, unsigned long secs);
        int (*read_callback)(struct device *, int data);
        int (*alarm_irq_enable)(struct device *, unsigned int enabled);
};

struct rtc_device
{
        struct device dev;
        struct module *owner;

        int id;
        char name[RTC_DEVICE_NAME_SIZE];

        const struct rtc_class_ops *ops;
        struct mutex ops_lock;

        struct cdev char_dev;
        unsigned long flags;

        unsigned long irq_data;
        spinlock_t irq_lock;
        wait_queue_head_t irq_queue;
        struct fasync_struct *async_queue;

        struct rtc_task *irq_task;
        spinlock_t irq_task_lock;
        int irq_freq;
        int max_user_freq;

        struct timerqueue_head timerqueue;
        struct rtc_timer aie_timer;
        struct rtc_timer uie_rtctimer;
        struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */
        int pie_enabled;
        struct work_struct irqwork;
        /* Some hardware can't support UIE mode */
        int uie_unsupported;

#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
        struct work_struct uie_task;
        struct timer_list uie_timer;
        /* Those fields are protected by rtc->irq_lock */
        unsigned int oldsecs;
        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
};
#define to_rtc_device(d) container_of(d, struct rtc_device, dev)

使用dump_stack()打印出Android设置rtc时间后,rtc内核阶段相应接口函数的调用逻辑:

log信息:
[   73.081000] [<c0015410>] (unwind_backtrace+0x0/0x134) from [<c03a5aa0>] (rx8010_set_time+0x1c/0x1ec)
[   73.091000] [<c03a5aa0>] (rx8010_set_time+0x1c/0x1ec) from [<c03a36b4>] (rtc_set_time+0x64/0xc4)
[   73.100000] [<c03a36b4>] (rtc_set_time+0x64/0xc4) from [<c045e02c>] (alarm_ioctl+0x2b4/0x618)
[   73.109000] [<c045e02c>] (alarm_ioctl+0x2b4/0x618) from [<c012c140>] (do_vfs_ioctl+0x3f8/0x5ac)
[   73.118000] [<c012c140>] (do_vfs_ioctl+0x3f8/0x5ac) from [<c012c360>] (sys_ioctl+0x6c/0x7c)
[   73.127000] [<c012c360>] (sys_ioctl+0x6c/0x7c) from [<c000ecc0>] (ret_fast_syscall+0x0/0x30)

内核驱动程序

kernel-3.4.39/drivers/rtc/rtc-rx8010.c
static struct rtc_class_ops rx8010_rtc_ops = {
        .read_time = rx8010_get_time,
        .set_time = rx8010_set_time,
        .read_alarm = rx8010_read_alarm,
        .set_alarm = rx8010_set_alarm,
        .alarm_irq_enable = rx8010_alarm_irq_enable,
};
kernel-3.4.39/drivers/rtc/interface.c
int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
{
        int err;

        err = mutex_lock_interruptible(&rtc->ops_lock);
        if (err)
                return err;

        err = __rtc_read_time(rtc, tm);
        mutex_unlock(&rtc->ops_lock);
        return err;
}
EXPORT_SYMBOL_GPL(rtc_read_time);

int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{
        int err;

        err = rtc_valid_tm(tm);
        if (err != 0)
                return err;

        err = mutex_lock_interruptible(&rtc->ops_lock);
        if (err)
                return err;

        if (!rtc->ops)
                err = -ENODEV;
        else if (rtc->ops->set_time)
                err = rtc->ops->set_time(rtc->dev.parent, tm);
        else if (rtc->ops->set_mmss) {
                unsigned long secs;
                err = rtc_tm_to_time(tm, &secs);
                if (err == 0)
                        err = rtc->ops->set_mmss(rtc->dev.parent, secs);
        } else
                err = -EINVAL;

        mutex_unlock(&rtc->ops_lock);
        /* A timer might have just expired */
        schedule_work(&rtc->irqwork);
        return err;
}
EXPORT_SYMBOL_GPL(rtc_set_time);

EXPORT_SYMBOL_GPL(rtc_read_alarm);
EXPORT_SYMBOL_GPL(rtc_set_alarm);
EXPORT_SYMBOL_GPL(rtc_initialize_alarm);
linux/kernel/kernel-3.4.39/drivers/staging/android/alarm-dev.c
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	        case ANDROID_ALARM_SET_RTC:
                if (copy_from_user(&new_rtc_time, (void __user *)arg,
                    sizeof(new_rtc_time))) {
                        rv = -EFAULT;
                        goto err1;
                }
                rtc_time_to_tm(new_rtc_time.tv_sec, &new_rtc_tm);
                rtc_dev = alarmtimer_get_rtcdev();
                rv = do_settimeofday(&new_rtc_time);
                if (rv < 0)
                        goto err1;
                if (rtc_dev)
                        rv = rtc_set_time(rtc_dev, &new_rtc_tm);
                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;
                break;

Android层jni

frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp
class AlarmImpl
{
public:
    AlarmImpl(int *fds, size_t n_fds);
    virtual ~AlarmImpl();

    virtual int set(int type, struct timespec *ts) = 0;
    virtual int setTime(struct timeval *tv) = 0;
    virtual int waitForAlarm() = 0;

protected:
    int *fds;
    size_t n_fds;
};

static jint android_server_AlarmManagerService_setKernelTime(JNIEnv*, jobject, jlong nativeData, jlong millis)
{
    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
    struct timeval tv;
    int ret;

    if (millis <= 0 || millis / 1000LL >= INT_MAX) {
        return -1;
    }

    tv.tv_sec = (time_t) (millis / 1000LL);
    tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);

    ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);

    ret = impl->setTime(&tv);

    if(ret < 0) {
        ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
        ret = -1;
    }
    return ret;
}

static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
{
    struct timezone tz;

    tz.tz_minuteswest = minswest;
    tz.tz_dsttime = 0;

    int result = settimeofday(NULL, &tz);
    if (result < 0) {
        ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
        return -1;
    } else {
        ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
    }

    return 0;
}

static JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
    {"init", "()J", (void*)android_server_AlarmManagerService_init},
    {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
    {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
    {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
    {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
    {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
};

int register_android_server_AlarmManagerService(JNIEnv* env)
{
    return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
                                    sMethods, NELEM(sMethods));
}

framework层

frameworks/base/services/java/com/android/server/AlarmManagerService.java 
frameworks/base/core/java/android/app/AlarmManager.java

下面的是直接提供给app层的API接口,它是AlarmManagerService.java的一个封装。

相关内容

操作指令

hwclock –r        显示硬件时钟与日期
hwclock –s        将系统时钟调整为与目前的硬件时钟一致。
hwclock –w       将硬件时钟调整为与目前的系统时钟一致
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值