前言
写博客大概就是从 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);