Android5.0 vold-註冊過程(下)

Hly_Coder發表於2016-11-30

概述

這篇文章主要講解的是,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) {...}複製程式碼

用流程圖來表示如下:

Android5.0 vold-註冊過程(下)
_regester_2.jpeg

kernel/driver

無論是socket還是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的資料結構中,以方便有資料的時候好知道通知哪

總結

用流程圖來看,如下:

Android5.0 vold-註冊過程(下)
_regester_3.jpeg

相關文章