转载请标明出处:http://www.jianshu.com/users/183339cdc7ae/latest_articles
概述
这篇文章主要讲解的是,kernel/drvier是如何通过netlink发送uevent到userspace的,以及netlink协议在kernel中的注册过程
相关文章
Android5.0 vold-整体架构
Android5.0 vold-启动过程
Android5.0 vold-注册过程(上)
NetlinkManager
由之前的文章可以知道,netlinkManager可以接受从kernel/drvier发送过来的uevent信息,这里我们来看下它是如何接受消息的
监听
当native vold启动的时候,会创建NetlinkManager,然后调用setupSocket方法
这里会使用socket这个接口来创建netlink,然后就可以接听从kernel发过来的消息了
先假设大家都知道什么是netlinke,以及其使用方法. 不知道什么是netlink以及和socket区别的可以看这里,socket, netlink
NetlinkHandler *NetlinkManager::setupSocket(int *sock, int netlinkFamily, int groups, int format) {
...
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = getpid();
nladdr.nl_groups = groups;
if ((*sock = socket(PF_NETLINK, SOCK_DGRAM, netlinkFamily)) < 0) {...}
...
if (bind(*sock, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0) {...}
用流程图来表示如下:
kernel/driver
无论是socket还是netlink,都有一个服务端和客服端,上面只是一个客服端,这里我们来看看服务端是如何启动的以及如何发消息的
netlink协议注册
这里core_initcall方法,是kernel启动的时候会首先加载的模块
netlink_proto_init该方法除了做一些数据结构,对象实例化外,还向socket中进行了注册
这样,当userspace使用socket接口传入netlink协议的时候就会调用到af_netlink模块中
core_initcall(netlink_proto_init);
...
staticint__init netlink_proto_init(void)
{
...
interr = proto_register(&netlink_proto, 0);
...
}
FilePath : kernel/net/netlink/af_netlink.c
kobject_uevent封装
我们一般向用户空间发送uevent消息的时候,不是直接使用af_netlink模块中的方法,而是使用kernel中有一个类似的工具类kobject_uevent来发送
我们来看看kobject_uevent模块是如何加载的
这里postcore_initcall是在core_initcall方法后加载的模块
会调用到ops里面的init方法,该方法会向af_netlink中进行注册
这里重点是netlink_kernel_create方法,如果想要自己进行封装,也就是对函数netlink_kernel_create进行封装
postcore_initcall(kobject_uevent_init);
static int __init kobject_uevent_init(void) {
return register_pernet_subsys(&uevent_net_ops);
}
static struct pernet_operations uevent_net_ops = {
.init = uevent_net_init,
.exit = uevent_net_exit,
};
static int uevent_net_init(struct net *net) {
...
ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, &cfg);
...
return 0;
}
FilePath : kernel/lib/kobject_uevent.c
kobject_uevent发送
当我们的驱动程序检测到事件,如:sd卡/otg插拔等,会调用kobject_uevent.c中kobject_uevent方法
其中action就是add或者remove之类的动作
最后kobject_uevent_env方法调用到af_netlink模块中,通知注册监听了uevent事件的进程
int kobject_uevent(struct kobject *kobj, enum kobject_action action) {
return kobject_uevent_env(kobj, action, NULL);
}
File : kernel/lib/kobject_uevent.c
用户socket接口注册
由之前可以知道,af_netlink启动的时候,会向socket进行注册
这样,当用户空间使用socket这个接口,并且传入netlink这个协议的时候,就可以找到af_netlink模块
当我们使用了socket这个接口后,还会调用bind方法,该方法会将pid,gid插入到af_netlink的数据结构中,以方便有数据的时候好知道通知哪
总结
用流程图来看,如下: