vold进程:
1.管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化
2.3G 4G 模块支持
G3Dev.cpp ----- usb_modeswitch -W -I ....
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);
...}
...}
...}
}