轉(zhuǎn)載請標(biāo)明出處:http://www.reibang.com/users/183339cdc7ae/latest_articles
概述
這篇文章主要講解的是市埋,kernel/drvier是如何通過netlink發(fā)送uevent到userspace的黎泣,以及netlink協(xié)議在kernel中的注冊過程
相關(guān)文章
Android5.0 vold-整體架構(gòu)
Android5.0 vold-啟動過程
Android5.0 vold-注冊過程(上)
NetlinkManager
由之前的文章可以知道,netlinkManager可以接受從kernel/drvier發(fā)送過來的uevent信息缤谎,這里我們來看下它是如何接受消息的
監(jiān)聽
當(dāng)native vold啟動的時候抒倚,會創(chuàng)建NetlinkManager,然后調(diào)用setupSocket方法
這里會使用socket這個接口來創(chuàng)建netlink,然后就可以接聽從kernel發(fā)過來的消息了
先假設(shè)大家都知道什么是netlinke坷澡,以及其使用方法. 不知道什么是netlink以及和socket區(qū)別的可以看這里,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托呕,都有一個服務(wù)端和客服端,上面只是一個客服端,這里我們來看看服務(wù)端是如何啟動的以及如何發(fā)消息的
netlink協(xié)議注冊
這里core_initcall方法项郊,是kernel啟動的時候會首先加載的模塊
netlink_proto_init該方法除了做一些數(shù)據(jù)結(jié)構(gòu)馅扣,對象實例化外,還向socket中進(jìn)行了注冊
這樣着降,當(dāng)userspace使用socket接口傳入netlink協(xié)議的時候就會調(diào)用到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封裝
我們一般向用戶空間發(fā)送uevent消息的時候差油,不是直接使用af_netlink模塊中的方法,而是使用kernel中有一個類似的工具類kobject_uevent來發(fā)送
我們來看看kobject_uevent模塊是如何加載的
這里postcore_initcall是在core_initcall方法后加載的模塊
會調(diào)用到ops里面的init方法任洞,該方法會向af_netlink中進(jìn)行注冊
這里重點是netlink_kernel_create方法蓄喇,如果想要自己進(jìn)行封裝,也就是對函數(shù)netlink_kernel_create進(jìn)行封裝
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發(fā)送
當(dāng)我們的驅(qū)動程序檢測到事件,如:sd卡/otg插拔等交掏,會調(diào)用kobject_uevent.c中kobject_uevent方法
其中action就是add或者remove之類的動作
最后kobject_uevent_env方法調(diào)用到af_netlink模塊中妆偏,通知注冊監(jiān)聽了uevent事件的進(jìn)程
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進(jìn)行注冊
這樣楼眷,當(dāng)用戶空間使用socket這個接口,并且傳入netlink這個協(xié)議的時候熊尉,就可以找到af_netlink模塊
當(dāng)我們使用了socket這個接口后,還會調(diào)用bind方法掌腰,該方法會將pid,gid插入到af_netlink的數(shù)據(jù)結(jié)構(gòu)中狰住,以方便有數(shù)據(jù)的時候好知道通知哪
總結(jié)
用流程圖來看,如下: