Uevent是Android内核与用户进程进行通信的一种方式,其本质是通过netlink(通过socket)发送消息给用户进程。
本文只讲一个大概的流程,只分析通信的一个过程,不深入解析具体的数据结构和传递的参数。
关于netlink socket的通信,请参考:
https://blog.csdn.net/Sunxiaolin2016/article/details/89635302
一、Kernel发送
Uevent是在kernel中发送出来的,通过kobject_uevent_env进行发送:
kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp);
二、用户进程接收
接收过程中,使用了Linux epoll机制,对事件进行监控。
1、使用uevent_open_socket()创建netlink socket,用于监听uevent事件
//本质是打开一个netlink socket
uevent_fd = uevent_open_socket(64 * 1024, true);
2、使用epoll_create(),用于产生一个epoll的文件描述符,一个epoll文件描述符对应一个文件描述符集合
epoll_fd = epoll_create(64);
3、使用epoll_ctl(),用于控制这个集合中的成员,在内核中,epoll_ctl会将新的fd加入到一颗红黑树中加以管理
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
ALOGE("epoll_ctl failed; errno=%d", errno);
return -1;
}
4、使用epoll_wait(),用于等待集合中成员的事件发生,如果所有成员都没有I/O事件,则保持进程的睡眠状态;否则,进程会被唤醒,epoll_wait会返回所有发生的事件的信息
for ( ; ; ) {
struct epoll_event events[64];
//等待事件发生
nevents = epoll_wait(epoll_fd, events, 64, -1);
if (nevents < 0) {
ALOGE("%s: wait the event failed", __FUNCTION__);
continue;
}
for (int n = 0; n < nevents; ++n) {
//处理事件
handle_events(uevent_fd);
}
}
5、在步骤4中,事件发生后,会执行handle_events(),在handle_events()中,使用uevent_kernel_multicast_recv()去接收uevent事件
handle_events(int uevent_fd)
{
char msg[UEVENT_MSG_LEN+2];
int n;
int i;
char *cp;
//接收uevent事件
n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
if (n <= 0 || n >= UEVENT_MSG_LEN) return;
//Do something
//...
}