Android Uevend 流程介绍

本文详细解析了ueventd服务的工作流程,包括在init程序中的启动过程,解析ueventd.rc配置文件,初始化设备节点,以及通过netlink与内核通信处理设备热插拔事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

写博客大概就是从 txt 中复制粘贴到 csdn 中,排版感觉是够呛了

代码流程汇总

service ueventd /sbin/ueventd
    class core
    critical

// 配置文件路径:system\core\rootdir\ueventd.rc


 这个程序是在 init  程序中启动的,有趣的是,这个程序也即 init 程序本身 
在 init 开始处,会判断执行哪一个代码分支  
main()
    1. 如上所述:
            /init
            /sbin/ueventd-->/init
            /sbin/watchdogd-->/init
        这里就是根据启动路径判断进入哪一个 main 函数

    2. 遍历解析 /ueventd.rc 文件    
    ueventd_parse_config_file("/ueventd.rc");

    3. 初始化各设备节点等
    device_init();
        1> 创建与内核 socket 通信 
        device_fd = uevent_open_socket(256*1024, true);
            使用 netlink 直接跟内核通信?
            s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
            setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz));
            setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
            bind(s, (struct sockaddr *) &addr, sizeof(addr)

        2> 判断 /dev/.coldboot_done 文件是否存在,若不存在,表示第一次,遍历检查 
            /sys/class 
            /sys/block 
            /sys/devices 
            下面的 uevent 属性文件,往里面写入 add 字符,接着创建新文件的标志打开 /dev/.coldboot_done 
            表示已经执行过 coldboot
                 coldboot(const char *path)
                    // 打开相对于 dfd 所对应路径下的 uevent 文件
                    fd = openat(dfd, "uevent", O_WRONLY);

                    /* 往 uevent 文件中写入 add, 模拟设备插入事件 */
                    write(fd, "add\n", 4);

                    /* 处理模拟的设备插入事件*/
                    handle_device_fd();
                        /* 接收内核送来的 event 事件 */
                        n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)

                        // 创建设备节点 
                        handle_device_event(&uevent);
                            make_device(devpath, path, block, major, minor, (const char **)links);

                        // 写固件进去
                        handle_firmware_event(&uevent);


    4. /* 死循环 */
        /* 处理 uevent 数据,相当于 Linux 的 PC 发行版上 udev 规则对 uevent 的处理 */       
        handle_device_fd();            
            // 创建设备节点 
            handle_device_event(&uevent);

            // 写固件进去
            handle_firmware_event(&uevent);

附:内核的 uevent 事件上报的实现流程

// mdev 机制与原理 
/dev 目录文件自动创建与 medv 机制原理:
    class_device_create
        class_device_register
            class_device_add
                kobject_uevent(&class_dev->kobj, KOBJ_ADD);
                    kobject_uevent_env(kobj, action, NULL);

                        // action_string = "add";
                        action_string = action_to_string(action);

                        /* 分配保存环境变量的内存 */
                        /* environment values */
                        buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
                        
                        /* 设置环境变量 */
                        envp [i++] = scratch;
                        scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
                        envp [i++] = scratch;
                        scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
                        envp [i++] = scratch;
                        scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
                        
                        // 如果定义使用网络,则使用 netlink 发送给用户程序处理 
                        #if defined(CONFIG_NET)
                            /* send netlink message */
                            if (uevent_sock) {
                                struct sk_buff *skb;
                                size_t len;

                                /* allocate message with the maximum possible size */
                                len = strlen(action_string) + strlen(devpath) + 2;
                                skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL);
                                if (skb) {
                                    /* add header */
                                    scratch = skb_put(skb, len);
                                    sprintf(scratch, "%s@%s", action_string, devpath);

                                    /* copy keys to our continuous event payload buffer */
                                    for (i = 2; envp[i]; i++) {
                                        len = strlen(envp[i]) + 1;
                                        scratch = skb_put(skb, len);
                                        strcpy(scratch, envp[i]);
                                    }

                                    NETLINK_CB(skb).dst_group = 1;

                                    ////////////////////////////////////////////
                                    // netlink 广播
                                    netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
                                }
                            }
                        #endif


                        /* 调用应用程序: 比如 mdev */
                        /* 启动脚本 echo /sbin/mdev > /proc/sys/kernel/hotplug 
                         * 设置了 uevent_helper 为“/sbin/mdev”
                         */
                        
                        argv [0] = uevent_helper;  // 指向路径 = "/sbin/mdev"
                                    // char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
                        argv [1] = (char *)subsystem;
                        argv [2] = NULL;
                        
                        // 调用用户空间的程序
                        call_usermodehelper (argv[0], argv, envp, 0);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值