• Linux内核 RTC时间架构


    上一篇文章我们给大家讲解了基于瑞芯微rk3568平台芯片hym8563驱动的移植,本文给大家详细讲解Linux内核的时间子系统。

    Linux驱动|rtc-hym8563移植笔记

    一、Linux 时间操作命令 :date、hwclock

    Linux时间有两个: 系统时间(Wall Time), RTC时间

    1)系统时间(WT):

    由Linux系统软件维持的时间,通过Linux命令date查看:

    rk3568_r:/ # date
    Wed Sep 21 03:05:21 GMT 2022
    
    • 1
    • 2

    获取到的就是系统时间。

    2)RTC时间:

    这个时间来自我们设备上的RTC芯片,通过Linux命令hwclock 可以读取:

    rk3568_r:/ # hwclock
    Wed Sep 21 03:05:24 2022  0.000000 seconds
    
    • 1
    • 2

    我们通过man查看date和hwclock的介绍:

    命令说明

    1)date
    DESCRIPTION
           Display the current time in the given FORMAT, or set the system date.
    
    • 1
    • 2
    2)hwclock
    DESCRIPTION
           hwclock  is  a tool for accessing the Hardware Clock.  It can: display the Hardware
           Clock time; set the Hardware Clock to a specified time; set the Hardware Clock from
           the  System  Clock;  set  the  System Clock from the Hardware Clock; compensate for
           Hardware Clock drift; correct the System Clock timescale; set  the  kernel's  time‐
           zone,  NTP  timescale,  and  epoch  (Alpha  only);  compare the System and Hardware
           Clocks; and predict future Hardware Clock values based on its drift rate.
    
           Since v2.26 important changes were made to the --hctosys function and the  --direc‐
           tisa  option,  and  a  new  option  --update-drift was added.  See their respective
           descriptions below.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    接下来,通过代码看下两者的关系。

    二、RTC时间框架

    框架如图:

    从该架构可得:

    Hardware:提供时间信息(time&alarm),通过一定的接口(比如I2C)和RTC Driver进行交互
    Driver:  完成硬件的访问功能,提供访问接口,以驱动的形式驻留在系统
    class.c:驱动注册方式由class.c:文件提供。驱动注册成功后会构建rtc_device结构体表征的rtc设备,并把rtc芯片的操作方式存放到rtc设备的ops成员中
    interface.c:文件屏蔽硬件相关的细节,向上提供统一的获取/设置时间或Alarm的接口
    rtc-lib.c:文件提供通用的时间操作函数,如rtc_time_to_tm、rtc_valid_tm等
    rtc-dev.c:文件在/dev/目录下创建设备节点供应用层访问,如open、read、ioctl等,访问方式填充到file_operations结构体中
    hctosys.c/rtc-sys.c/rtc-proc.c:将硬件时钟写给 wall time
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    下面我们从底层往上层来一步步分析。

    1、rtc_class_ops 填充

    驱动主要工作是填充 rtc_class_ops结构体,结构体描述了RTC芯片能够提供的所有操作方式:

    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);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    实现:

    static const struct rtc_class_ops hym8563_rtc_ops = {
    	.read_time		= hym8563_rtc_read_time,
    	.set_time		= hym8563_rtc_set_time,
    	.alarm_irq_enable	= hym8563_rtc_alarm_irq_enable,
    	.read_alarm		= hym8563_rtc_read_alarm,
    	.set_alarm		= hym8563_rtc_set_alarm,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注册:

    	hym8563->rtc = devm_rtc_device_register(&client->dev, client->name,
    						&hym8563_rtc_ops, THIS_MODULE);
    
    • 1
    • 2

    成功的话log:

    [    0.758774] hym8563_probe()---565----
    [    0.760651] rtc-hym8563 5-0051: rtc information is invalid
    [    0.761666] hym8563_rtc_read_time()---115----1--
    [    0.761681] hym8563_rtc_set_time()---129----1--
    [    0.764235] hym8563_rtc_read_time()---115----1--
    [    0.766425] hym8563_rtc_read_time()---115----1--
    [    0.767439] hym8563_rtc_read_time()---115----1--
    [    0.767619] rtc-hym8563 5-0051: rtc core: registered hym8563 as rtc0
    [    0.768634] hym8563_rtc_read_time()---115----1--
    [    0.768661] rtc-hym8563 5-0051: setting system clock to 2021-01-01 12:00:00 UTC (1609502400)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    从log可得
    5-0051: 5表示I2C通道5,0051表示从设备地址
    rtc0 :注册的rtc设备为rtc0

    2、class.c和RTC驱动注册

    class.c文件在RTC驱动注册之前开始得到运行:

    static int __init rtc_init(void)
    {
        rtc_class = class_create(THIS_MODULE, "rtc");
        rtc_class->suspend = rtc_suspend;
        rtc_class->resume = rtc_resume;
        rtc_dev_init();
        rtc_sysfs_init(rtc_class);
        return 0;
    }
    subsys_initcall(rtc_init);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    函数功能:

    • 1、创建名为rtc的class
    • 2、提供PM相关接口suspend/resume
    • 3、rtc_dev_init():动态申请/dev/rtcN的设备号
    • 4、rtc_sysfs_init():rtc类具有的device_attribute属性

    3、RTC驱动注册函数devm_rtc_device_register():

    drivers/class.c
    struct rtc_device *devm_rtc_device_register(struct device *dev,
    					const char *name,
    					const struct rtc_class_ops *ops,
    					struct module *owner)
    {
    	struct rtc_device **ptr, *rtc;
    
    	ptr = devres_alloc(devm_rtc_device_release, sizeof(*ptr), GFP_KERNEL);
    	if (!ptr)
    		return ERR_PTR(-ENOMEM);
    
    	rtc = rtc_device_register(name, dev, ops, owner);
    	if (!IS_ERR(rtc)) {
    		*ptr = rtc;
    		devres_add(dev, ptr);
    	} else {
    		devres_free(ptr);
    	}
    
    	return rtc;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    rtc_device_register()定义如下

    struct rtc_device *rtc_device_register(const char *name, struct device *dev,
                        const struct rtc_class_ops *ops,
                        struct module *owner)
    {
        struct rtc_device *rtc;
        struct rtc_wkalrm alrm;
        int id, err;
        
        // 1、Linux支持多个RTC设备,所以需要为每一个设备分配一个ID
        // 对应与/dev/rtc0,/dev/rtc1,,,/dev/rtcN
        id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
     
        // 2、创建rtc_device设备(对象)并执行初始化
        rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
        rtc->id = id;
        rtc->ops = ops; // 2.1 对应RTC驱动填充的test_rtc_ops
        rtc->owner = owner;
        rtc->irq_freq = 1;
        rtc->max_user_freq = 64;
        rtc->dev.parent = dev;
        rtc->dev.class = rtc_class;// 2.2 rtc_init()创建的rtc_class
        rtc->dev.release = rtc_device_release;
     
        // 2.3 rtc设备中相关锁、等待队列的初始化
        mutex_init(&rtc->ops_lock);
        spin_lock_init(&rtc->irq_lock);
        spin_lock_init(&rtc->irq_task_lock);
        init_waitqueue_head(&rtc->irq_queue);
     
        // 2.4 Init timerqueue:我们都知道,手机等都是可以设置多个闹钟的
        timerqueue_init_head(&rtc->timerqueue);
        INIT_WORK(&rtc->irqwork, rtc_timer_do_work);
        // 2.5 Init aie timer:alarm interrupt enable,RTC闹钟中断
        rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc);
        // 2.6 Init uie timer:update interrupt,RTC更新中断
        rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc);
        /* Init pie timer:periodic interrupt,RTC周期性中断 */
        hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        rtc->pie_timer.function = rtc_pie_update_irq;
        rtc->pie_enabled = 0;
     
        /* Check to see if there is an ALARM already set in hw */
        err = __rtc_read_alarm(rtc, &alrm);
     
        // 3、如果RTC芯片中设置了有效的Alarm,则初始化:加入到rtc->timerqueue队列中
        if (!err && !rtc_valid_tm(&alrm.time))
            rtc_initialize_alarm(rtc, &alrm);
     
        // 4、根据name参数设置rtc的name域
        strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
        // 5、设置rtc的dev成员中的name域
        dev_set_name(&rtc->dev, "rtc%d", id);
     
        // 6、/dev/rtc0的rtc作为字符设备进行初始化
        // rtc_dev_prepare-->cdev_init(&rtc->char_dev, &rtc_dev_fops);
        rtc_dev_prepare(rtc);
     
        // 7、添加rtc设备到系统
        err = device_register(&rtc->dev);
     
        // 8、rtc设备作为字符设备添加到系统
        // rtc_dev_add_devicec-->dev_add(&rtc->char_dev, rtc->dev.devt, 1)
        // 然后就存在/dev/rtc0了
        rtc_dev_add_device(rtc);
        rtc_sysfs_add_device(rtc);
        // 9、/proc/rtc
        rtc_proc_add_device(rtc);
     
        dev_info(dev, "rtc core: registered %s as %s\n",
                rtc->name, dev_name(&rtc->dev));
     
        return rtc;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    有了 /dev/rtc0后,应用层就可以通过 open/read/ioctl操作RTC设备了,对应与内核的file_operations:

    static const struct file_operations rtc_dev_fops = {
        .owner        = THIS_MODULE,
        .llseek        = no_llseek,
        .read        = rtc_dev_read,
        .poll        = rtc_dev_poll,
        .unlocked_ioctl    = rtc_dev_ioctl,
        .open        = rtc_dev_open,
        .release    = rtc_dev_release,
        .fasync        = rtc_dev_fasync,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4、硬件抽象层interface.c

    硬件抽象,即屏蔽具体的硬件细节,为上层用户提供统一的调用接口,使用者无需关心这些接口是怎么实现的。
    以RTC访问为例,抽象的实现位于interface.c文件,其实现基于class.c中创建的rtc_device设备。
    实现原理,以rtc_set_time为例:

    drivers/interface.c
    int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
    {
        int err;
        // 1、参数检测
        err = rtc_valid_tm(tm);
     
        err = mutex_lock_interruptible(&rtc->ops_lock);
        if (err)
            return err;
     
        // 2、调用rtc_device中ops结构体的函数指针
        // ops结构体的函数指针已经在RTC驱动中被赋值
        if (!rtc->ops)
            err = -ENODEV;
        else if (rtc->ops->set_time)
            err = rtc->ops->set_time(rtc->dev.parent, tm);
        mutex_unlock(&rtc->ops_lock);
        /* A timer might have just expired */
        schedule_work(&rtc->irqwork);
        return err;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    5、rtc在sysfs文件系统中的呈现

    之前曾建立过名为rtc的class:

    rtc_class = class_create(THIS_MODULE, "rtc");
    
    • 1

    查看之:

    # ls /sys/class/rtc/                                    
    rtc0
    # ls -l /sys/class/rtc/                                 
    lrwxrwxrwx 1 root root 0 2021-01-01 12:00 rtc0 -> ../../devices/platform/fe5e0000.i2c/i2c-5/5-0051/rtc/rtc0
    
    • 1
    • 2
    • 3
    • 4

    我们系统中只有一个RTC,所以编号为rtc0。

    同时发现rtc0文件为指向/sys/devices/platform/fe5e0000.i2c/i2c-5/5-0051/rtc/rtc0的符号链接,

    RTC芯片是I2C接口,所以rtc0挂载在I2C的总线上,总线控制器地址fe5e0000,控制器编号为5,RTC芯片作为slave端地址为0x51。

    rtc0 设备属性:

    drivers/rtc-sysfs.c
    void __init rtc_sysfs_init(struct class *rtc_class)
    {
    	rtc_class->dev_attrs = rtc_attrs;
    }
    static struct attribute *rtc_attrs[] = {
    	&dev_attr_name.attr,
    	&dev_attr_date.attr,
    	&dev_attr_time.attr,
    	&dev_attr_since_epoch.attr,
    	&dev_attr_max_user_freq.attr,
    	&dev_attr_hctosys.attr,
    	NULL,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    对应文件系统中的文件节点:

    rk3568_r:/sys/class/rtc # cd rtc0/
    rk3568_r:/sys/class/rtc/rtc0 # ls -l
    total 0
    -r--r--r-- 1 root root 4096 2022-09-21 03:56 date
    -r--r--r-- 1 root root 4096 2022-09-21 03:56 dev
    lrwxrwxrwx 1 root root    0 2022-09-21 03:56 device -> ../../../5-0051
    -r--r--r-- 1 root root 4096 2021-01-01 12:00 hctosys
    -rw-r--r-- 1 root root 4096 2022-09-21 03:56 max_user_freq
    -r--r--r-- 1 root root 4096 2022-09-21 03:56 name
    drwxr-xr-x 2 root root    0 2021-01-01 12:00 power
    -r--r--r-- 1 root root 4096 2022-09-21 03:56 since_epoch
    lrwxrwxrwx 1 root root    0 2022-09-21 03:56 subsystem -> ../../../../../../../class/rtc
    -r--r--r-- 1 root root 4096 2022-09-21 03:56 time
    -rw-r--r-- 1 root root 4096 2021-01-01 12:00 uevent
    -rw-r--r-- 1 root root 4096 2022-09-21 03:56 wakealarm
    drwxr-xr-x 2 root root    0 2021-01-01 12:00 wakeup8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    6、rtc在proc文件系统中的呈现

    之前曾rtc0设备加入到了/proc

    drivers/class.c
    rtc_device_register()
    {
    	--->rtc_proc_add_device(rtc);
    }
    void rtc_proc_add_device(struct rtc_device *rtc)
    {
    	if (is_rtc_hctosys(rtc))
    		proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    查看之:

    # cat /proc/driver/rtc                                       
    rtc_time        : 03:59:11
    rtc_date        : 2022-09-21
    alrm_time       : 12:00:00
    alrm_date       : 2021-01-02
    alarm_IRQ       : no
    alrm_pending    : no
    update IRQ enabled      : no
    periodic IRQ enabled    : no
    periodic IRQ frequency  : 1
    max user IRQ frequency  : 64
    24hr            : yes
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    信息来源:

    rtc_proc_fops
    	-->rtc_proc_open
    		-->rtc_proc_show
    
    • 1
    • 2
    • 3

    三、WT时间和RTC时间同步问题

    1)

    WT时间来自于RTC时间,流程是:

    上电-->RTC驱动加载-->从RTC同步时间到WT时间
    
    • 1

    对应驱动代码:

    hctosys.c (drivers\rtc)
    static int __init rtc_hctosys(void)
    {
    	......
        struct timespec tv = {
            .tv_nsec = NSEC_PER_SEC >> 1,
        };
        
        err = rtc_read_time(rtc, &tm);
        err = do_settimeofday(&tv);
        dev_info(rtc->dev.parent,
            "setting system clock to "
            "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
            tm.tm_hour, tm.tm_min, tm.tm_sec,
            (unsigned int) tv.tv_sec);
        ......
    }
    late_initcall(rtc_hctosys);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    late_initcall说明系统在启动流程的后面才会调用该函数去同步时间。

    2)瑞芯微时间操作

    在瑞芯微的系统中,安卓部分程序其实最终也是依赖**/sys/class/rtc/rtc0** 下的文件节点实现时间管理功能的。

    安卓程序会通过AlarmImpl::getTime、AlarmImpl::setTime()方法来获得和设置RTC时间:

    frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp 
    
    • 1
    122 int AlarmImpl::getTime(int type, struct itimerspec *spec)
    123 {
    124     if (static_cast<size_t>(type) > ANDROID_ALARM_TYPE_COUNT) {
    125         errno = EINVAL;
    126         return -1;
    127     }
    128 
    129     return timerfd_gettime(fds[type], spec);
    130 }
    131 
    132 int AlarmImpl::setTime(struct timeval *tv)
    133 {
    134     struct rtc_time rtc;
    135     struct tm tm, *gmtime_res;
    136     int fd;
    137     int res;
    138 
    139     res = settimeofday(tv, NULL);
    140     if (res < 0) {
    141         ALOGV("settimeofday() failed: %s\n", strerror(errno));
    142         return -1;
    143     }
    144 
    145     if (rtc_id < 0) {
    146         ALOGV("Not setting RTC because wall clock RTC was not found");
    147         errno = ENODEV;
    148         return -1;
    149     }
    150 
    151     android::String8 rtc_dev = String8::format("/dev/rtc%d", rtc_id);
    152     fd = open(rtc_dev.string(), O_RDWR);
    153     if (fd < 0) {
    154         ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno));
    155         return res;
    156     }
    157 
    158     gmtime_res = gmtime_r(&tv->tv_sec, &tm);
    159     if (!gmtime_res) {
    160         ALOGV("gmtime_r() failed: %s\n", strerror(errno));
    161         res = -1;
    162         goto done;
    163     }
    164 
    165     memset(&rtc, 0, sizeof(rtc));
    166     rtc.tm_sec = tm.tm_sec;
    167     rtc.tm_min = tm.tm_min;
    168     rtc.tm_hour = tm.tm_hour;
    169     rtc.tm_mday = tm.tm_mday;
    170     rtc.tm_mon = tm.tm_mon;
    171     rtc.tm_year = tm.tm_year;
    172     rtc.tm_wday = tm.tm_wday;
    173     rtc.tm_yday = tm.tm_yday;
    174     rtc.tm_isdst = tm.tm_isdst;
    175     res = ioctl(fd, RTC_SET_TIME, &rtc);                                                                                                                                                                                                                  
    176     if (res < 0)
    177         ALOGV("RTC_SET_TIME ioctl failed: %s\n", strerror(errno));
    178 done:
    179     close(fd);
    180     return res;
    181 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    系统上电后,会先读取文件hctosys中的值,来决定是否将RTC时间写入到wall time:

    255 static const char rtc_sysfs[] = "/sys/class/rtc";
    256 
    257 static bool rtc_is_hctosys(unsigned int rtc_id)
    258 {
    259     android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",
    260             rtc_sysfs, rtc_id);
    261     FILE *file = fopen(hctosys_path.string(), "re");
    262     if (!file) {
    263         ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));
    264         return false;
    265     }
    266 
    267     unsigned int hctosys;
    268     bool ret = false;
    269     int err = fscanf(file, "%u", &hctosys);
    270     if (err == EOF)
    271         ALOGE("failed to read from %s: %s", hctosys_path.string(),
    272                 strerror(errno));
    273     else if (err == 0)
    274         ALOGE("%s did not have expected contents", hctosys_path.string());
    275     else
    276         ret = hctosys;
    277 
    278     fclose(file);
    279     return ret;
    280 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    269行,就是读取文件hctosys中的值,值为1则允许rtc时间写入到wall time,为0或者其他错误则不允许。

    因为rtc只要有纽扣电池供电,就会有计时功能,

    这是就是为什么,我们的设备关机并重启后,仍然能够显示正确的时间的原因。

    【注意目录/sys/class/rtc/下文件是需要有访问权限的】
    瑞芯微对文件权限的控制由以下文件提供:

    device/rockchip/common/sepolicy/vendor/genfs_contexts
    
    • 1


    只需要按照对应的格式增加对应文件信息即可。

    四、欢迎交流

    一口君建立了瑞芯微的技术交流群,

    大家工作中用到瑞芯微系列soc的,可以一起交流,

    加群后台留言即可。

  • 相关阅读:
    uniapp集成Android原生sdk
    视频翻译字幕的软件哪个好?看完你就知道了
    xargs如何保留文本中的引号
    【深入浅出 Yarn 架构与实现】2-4 Yarn 基础库 - 状态机库
    攻防世界_MISC之碎纸机11
    十六、 代码校验(3)
    2023 百度之星(夏日漫步 + 跑步问题)
    从风险评估到应急救援,实景三维为抗震减灾提供精细化决策依据
    为共创行业解决方案寻找黄金合作伙伴,百数低代码服务商模式在等您
    Java面试干货:关于数组查找的几个常用实现算法
  • 原文地址:https://blog.csdn.net/daocaokafei/article/details/127002067