vold进程:

1.管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化

2.3G 4G 模块支持
G3Dev.cpp ----- usb_modeswitch -W -I …

netlink内核态和用户态使用

netlink

Netlink是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的socketAPI就可以使用netlink提供的强大功能,内核态需要使用专门的内核API来使用netlink。

netd vold 都在使用这个。

Netlink的优点:
1. 使用简便

为了使用netlink,用户仅需要在include/linux/netlink.h中增加一个新类型的netlink协议定义即可,如#defineNETLINK_MYTEST17,然后,内核和用户态应用就可以立即通过socketAPI使用该netlink协议类型进行数据交换。但系统调用需要增加新的系统调用,ioctl则需要增加设备或文件,那需要不少代码,proc文件系统则需要在/proc下添加新的文件或目录,那将使本来就混乱的/proc更加混乱。

2.异步通信

netlink是一种异步通信机制,在内核与用户态应用之间传递的消息保存在socket缓存队列中,但系统调用与ioctl则是同步通信机制。

3.模块机制

使用netlink的内核部分可以采用模块的方式实现,使用netlink的应用部分和内核部分没有编译时依赖,但系统调用就有依赖,而且新的系统调用的实现必须静态地连接到内核中,它无法在模块中实现,使用新系统调用的应用在编译时需要依赖内核。

4.支持多播

内核模块或应用可以把消息多播给一个netlink组,属于该neilink组的任何内核模块或应用都能接收到该消息,内核事件向用户态的通知机制就使用了这一特性,任何对内核事件感兴趣的应用都能收到该子系统发送的内核事件。

#define NETLINK_ROUTE	 0	/* Routing/device hook	 */
#define NETLINK_UNUSED	 1	/* Unused number	 */
#define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
#define NETLINK_FIREWALL	3	/* Firewalling hook	 */
#define NETLINK_SOCK_DIAG	4	/* socket monitoring	 */
#define NETLINK_NFLOG	 5	/* netfilter/iptables ULOG */
#define NETLINK_XFRM	 6	/* ipsec */
#define NETLINK_SELINUX	 7	/* SELinux event notifications */
#define NETLINK_ISCSI	 8	/* Open-iSCSI */
#define NETLINK_AUDIT	 9	/* auditing */
#define NETLINK_FIB_LOOKUP	10
#define NETLINK_CONNECTOR	11
#define NETLINK_NETFILTER	12	/* netfilter subsystem */
#define NETLINK_IP6_FW	 13
#define NETLINK_DNRTMSG	 14	/* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
</span>#define NETLINK_GENERIC	 16
/* leave room for NETLINK_DM (DM Events) */
#define NETLINK_SCSITRANSPORT	18	/* SCSI Transports */
#define NETLINK_ECRYPTFS	19
#define NETLINK_RDMA	 20
#define NETLINK_CRYPTO	 21	/* Crypto layer */

用户态如何使用netlink

1.创建一个netlinksocket
socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
2.设置socket的选项(可选)
setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
3.bind

使用bind()把创建的netlinksocket与netlinksocket地址绑定在一起

bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr));

其中,nladdr是sockaddr_nl结构体:

struct sockaddr_nl
{
  sa_family_t    nl_family;
  unsigned short 	nl_pad;
  __u32          nl_pid;
  __u32          nl_groups;
};

字段nl_family必须设置为AF_NETLINK或着PF_NETLINK,字段nl_pad当前没有使用,因此要总是设置为0,字段nl_pid为接收或发送消息的进程的ID,如果希望内核处理消息或多播消息,就把该字段设置为0,否则设置为处理消息的进程ID。字段nl_groups用于指定多播组,bind函数用于把调用进程加入到该字段指定的多播组,如果设置为0,表示调用者不加入任何多播组。

struct sockaddr_nl nladdr;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = getpid();
nladdr.nl_groups = 0xffffffff;
4.创建一个listener监听该socket

创建一个listener监听该socket,重写listener的onEvent函数,来完成对监听到的数据进行筛选/分类/处理。

mHandler = new NetlinkHandler(mSock);

内核态如何使用netlink

1.创建netlinksocket。
ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT,
  1, NULL, NULL, THIS_MODULE);

其中第四个参数为接收用户态消息的函数指针,为null说明为单向的,即内核不处理用户态发来的消息,只是向用户态通知内核事件。

NETLINK_KOBJECT_UEVENT是表示的接收内核uevent信息

3.向用户态上报消息

当有事件发生的时候,调用 kobject_uevent()函数,实际上最终是调用
netlink_broadcast_filtered
完成广播任务。

int netlink_unicast(struct sock *sk, struct sk_buff *skb, u32 pid, int nonblock);
void netlink_broadcast(struct sock *sk, struct sk_buff *skb, u32 pid, u32 group, int allocation);

其中,参数sk为函数netlink_kernel_create()返回的socket,参数skb存放消息,参数pid为接收消息进程的pid,参数group为接收消息的多播组。

NETD

内核检测打到网络的变化 ,向用户态通知。
比如interface add /remove, link up/down.

int NetlinkManager::start() {
    if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
         0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {
        return -1;
    }
    ...
}
 
NetlinkHandler *NetlinkManager::setupSocket(int *sock, int netlinkFamily,
    int groups, int format) {
    struct sockaddr_nl nladdr;
    int sz = 64 * 1024;
    int on = 1;
    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
    nladdr.nl_pid = getpid();
    nladdr.nl_groups = groups;
 
    if ((*sock = socket(PF_NETLINK, SOCK_DGRAM, netlinkFamily)) < 0) {
    ...}
 
    if (setsockopt(*sock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
    ...}
 
    if (setsockopt(*sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
    ...}
 
    if (bind(*sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
    ...}
 
    NetlinkHandler *handler = new NetlinkHandler(this, *sock, format);
    if (handler->start()) {
    ...}
    return handler;
}
 
int NetlinkManager::stop() {
    ...
    if (mUeventHandler->stop()) {
    ...}
 
    delete mUeventHandler;
    mUeventHandler = NULL;
 
    close(mUeventSock);
    mUeventSock = -1;
...
}

int NetlinkHandler::start() {
    return this->startListener();
}
 
int NetlinkHandler::stop() {
    return this->stopListener();
}
 
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *subsys = evt->getSubsystem();
 	 ...
if (!strcmp(subsys, "net")) {
        int action = evt->getAction();
        const char *iface = evt->findParam("INTERFACE");
 
        if (action == evt->NlActionAdd) {
            notifyInterfaceAdded(iface);
        } else if (action == evt->NlActionRemove) {
            notifyInterfaceRemoved(iface);
        } else if (action == evt->NlActionChange) {
            evt->dump();
            notifyInterfaceChanged("nana", true);
        } else if (action == evt->NlActionLinkUp) {
            notifyInterfaceLinkChanged(iface, true);
        } else if (action == evt->NlActionLinkDown) {
            notifyInterfaceLinkChanged(iface, false);
        } else if (action == evt->NlActionAddressUpdated ||
                   action == evt->NlActionAddressRemoved) {
            const char *address = evt->findParam("ADDRESS");
            const char *flags = evt->findParam("FLAGS");
            const char *scope = evt->findParam("SCOPE");
            if (iface && flags && scope) {
                notifyAddressChanged(action, address, iface, flags, scope);
            ...}
        ...}
    ...}
}

相关文章: