NETD
一、NETD解读
1.1、NETD的作用
Netd是Android系统中专门负责网络管理和控制的后台daemon程序,其功能主要分三大块:
- 设置防火墙(Firewall)、网络地址转换(NAT)、带宽控制、无线网卡软接入点(Soft Access Point)控制,网络设备绑定(Tether)等。
- Android系统中DNS信息的缓存和管理。
- 网络服务搜索(Net Service Discovery,简称NSD)功能,包括服务注册(Service Registration)、服务搜索(Service Browse)和服务名解析(Service Resolve)等。
Netd的工作流程和Vold类似[1],其工作可分成两部分:
- Netd接收并处理来自Framework层中NetworkManagementService或NsdService的命令。这些命令最终由Netd中对应的Command对象去处理。
- Net接收并解析来自Kernel的UEvent消息,然后再转发给Framework层中对应Service去处理。
Netd位于Framework层和Kernel层之间,它是Android系统中网络相关消息和命令转发及处理的中枢模块。
1.2 NETD的工作流程
Netd进程由init进程根据init.rc的对应配置项而启动。通过命令行可以看到:
service netd /system/bin/netd
class main
socket netd stream 0660 root system
socket dnsproxyd stream 0660 root inet
socket mdns stream 0660 root system
socket fwmarkd stream 0660 root inet
Netd启动时将创建三个TCP监听socket,其名称分别为”netd”,”dnsproxyd”,”mdns”和“fwmarked”。
Framework层中的NetworkManagementService和NsdService将分别和”netd”及”mdns”监听socket建立链接并交互。
每一个调用和域名解析相关的socket API(如getaddrinfo或gethostbyname等)的进程都会借由”dnsproxyd”监听socket与netd建立链接。
fwmarkd 和底层kernel交互,防火墙firewall会对进来的包做标记。
1.2.1 main函数分析
Netd进程的入口函数是其main函数,代码如下所示:
int main() {
CommandListener *cl;
NetlinkManager *nm;
DnsProxyListener *dpl;
MDnsSdListener *mdnsl;
ALOGI("Netd 1.0 starting");
//为Netd进程屏蔽SIGPIPE信号
blockSigpipe();
//创建NetlinkManager
if (!(nm = NetlinkManager::Instance())) {
ALOGE("Unable to create NetlinkManager");
exit(1);
};
//创建CommandListener,它将创建名为"netd"的监听socket
cl = new CommandListener();
//设置NetlinkManager的消息发送者(Broadcaster)为CommandListener。
nm->setBroadcaster((SocketListener *) cl);
//启动NetlinkManager
if (nm->start()) {
ALOGE("Unable to start NetlinkManager (%s)", strerror(errno));
exit(1);
}
//Netd设置环境变量ANDROID_DNS_MODE为"local"
// Set local DNS mode, to prevent bionic from proxying
// back to this service, recursively.
setenv("ANDROID_DNS_MODE", "local", 1);
//创建DnsProxyListener,它将创建名为"dnsproxyd"的监听socket
dpl = new DnsProxyListener();
dpl->startListener();
//创建MDnsSdListener并启动监听,它将创建名为"mdns"的监听socket
mdnsl = new MDnsSdListener();
mdnsl->startListener();
cl->startListener();
while(1) {
sleep(1000);
}
exit(0);
}
Netd的main函数非常简单,主要是创建几个重要成员并启动相应的工作,这几个重要成员分别是:
- NetlinkManager:它将接收并处理来自Kernel的UEvent消息。这些消息经NetlinkManager解析后将借助它的Broadcaster(也就是代码中为NetlinkManager设置的CommandListener)发送给Framework层的NetworkManagementService。
- CommandListener、DnsProxyListener、MDnsSdListener:分别创建名为”netd”、”dnsproxyd”、”mdns”的监听socket,并处理来客户端的命令。
1.2.2 NetlinkManager分析
1、NetlinkManager主要负责接收并解析来自Kernel的UEvent消息。其核心代码在start函数中:
int NetlinkManager::start() {
//创建接收NETLINK_KOBJECT_UEVENT消息的socket,其值保存在mUeventSock中
//其中,NETLINK_FORMAT_ASCII代表UEvent消息的内容为ASCII字符串
if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII, false)) == NULL) {
return -1;
}
//创建接收RTMGPR_LINK消息的socket,其值保存在mRouteSock中
//其中,NETLINK_FORMAT_BINARY代表UEvent消息的类型为结构体,故需要进行二进制解析
if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE,
RTMGRP_LINK |
RTMGRP_IPV4_IFADDR |
RTMGRP_IPV6_IFADDR |
RTMGRP_IPV6_ROUTE |
(1 << (RTNLGRP_ND_USEROPT - 1)),
NetlinkListener::NETLINK_FORMAT_BINARY, false)) == NULL) {
return -1;
}
//创建接收NETLINK_NFLOG消息的socket,其值保存在mQuotaSock中
if ((mQuotaHandler = setupSocket(&mQuotaSock, NETLINK_NFLOG,
NFLOG_QUOTA_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY, false)) == NULL) {
ALOGE("Unable to open quota socket");
// TODO: return -1 once the emulator gets a new kernel.
}
//创建接收NETLINK_NETFILTER消息的socket,其值保存在mStrictSock中
if ((mStrictHandler = setupSocket(&mStrictSock, NETLINK_NETFILTER,
0, NetlinkList