zoukankan      html  css  js  c++  java
  • Netd工作流程


    http://blog.csdn.net/zhqh100/article/details/44994241


    本文为《深入理解Android Wi-Fi、NFC和GPS卷》读书笔记,Android源码为Android 5.1

    Netd进程由init进程根据init.rc的对应配置项而启动:
    android-5.1/system/core/rootdir/init.rc

    1. service netd /system/bin/netd  
    2.     class main  
    3.     socket netd stream 0660 root system  
    4.     socket dnsproxyd stream 0660 root inet  
    5.     socket mdns stream 0660 root system  
    6.     socket fwmarkd stream 0660 root inet  
    Netd启动时将创建四个TCP监听socket,其名称分别是netd、dnsproxyd、mdns和fwmarkd。
    Framework 层中的 NetworkManagementService 和 NsdService 将分别和netd及mdns监听socket建立链接并交互。
    每一个调用和域名解析相关的socket API(如 getaddrinfo 或 gethostbyname 等)的进程都会借由 dnsproxyd 监听 socket 与 netd 建立链接。
    下面开始分析Netd进程。
    android-5.1/system/netd/server/main.cpp
    1. int main() {  
    2.   
    3.     CommandListener *cl;  
    4.     NetlinkManager *nm;  
    5.     DnsProxyListener *dpl;  
    6.     MDnsSdListener *mdnsl;  
    7.     FwmarkServer* fwmarkServer;  
    8.   
    9.     ALOGI("Netd 1.0 starting");  
    10.     remove_pid_file();  
    11.   
    12.     //为Netd进程屏蔽SIGPIPE信号  
    13.     blockSigpipe();  
    14.   
    15.     //创建NetlinkManager  
    16.     if (!(nm = NetlinkManager::Instance())) {  
    17.         ALOGE("Unable to create NetlinkManager");  
    18.         exit(1);  
    19.     };  
    20.   
    21.     //创建CommandListener,它将创建名为netd的监听socket  
    22.     cl = new CommandListener();  
    23.     //设置NetlinkManager的消息发送者(Broadcaster)为CommandListener  
    24.     nm->setBroadcaster((SocketListener *) cl);  
    25.   
    26.     //启动NetlinkManager  
    27.     if (nm->start()) {  
    28.         ALOGE("Unable to start NetlinkManager (%s)", strerror(errno));  
    29.         exit(1);  
    30.     }  
    31.   
    32.     // Set local DNS mode, to prevent bionic from proxying  
    33.     // back to this service, recursively.  
    34.     //为本Netd设置环境变量 ANDROID_DNS_MODE 为local  
    35.     setenv("ANDROID_DNS_MODE""local", 1);  
    36.     //创建 DnsProxyListener,它将创建名为 dnsproxyd 的监听socket  
    37.     dpl = new DnsProxyListener(CommandListener::sNetCtrl);  
    38.     if (dpl->startListener()) {  
    39.         ALOGE("Unable to start DnsProxyListener (%s)", strerror(errno));  
    40.         exit(1);  
    41.     }  
    42.   
    43.     //创建 MDnsSdListener并启动监听,它将创建名为mdns的监听socket  
    44.     mdnsl = new MDnsSdListener();  
    45.     if (mdnsl->startListener()) {  
    46.         ALOGE("Unable to start MDnsSdListener (%s)", strerror(errno));  
    47.         exit(1);  
    48.     }  
    49.   
    50.     //创建 FwmarkServer并启动监听,它将创建名为fwmarkd的监听  
    51.     fwmarkServer = new FwmarkServer(CommandListener::sNetCtrl);  
    52.     if (fwmarkServer->startListener()) {  
    53.         ALOGE("Unable to start FwmarkServer (%s)", strerror(errno));  
    54.         exit(1);  
    55.     }  
    56.   
    57.     /* 
    58.      * Now that we're up, we can respond to commands 
    59.      */  
    60.     if (cl->startListener()) {  
    61.         ALOGE("Unable to start CommandListener (%s)", strerror(errno));  
    62.         exit(1);  
    63.     }  
    64.   
    65.     bool wrote_pid = write_pid_file();  
    66.   
    67.     while(1) {  
    68.         sleep(30); // 30 sec  
    69.         if (!wrote_pid) {  
    70.             wrote_pid = write_pid_file();  
    71.         }  
    72.     }  
    73.   
    74.     ALOGI("Netd exiting");  
    75.     remove_pid_file();  
    76.     exit(0);  
    77. }  
    Netd的main函数主要是创建几个重要成员并启动相应的工作,这四个重要成员分别如下:
    NetlinkManager:接收并处理来自Kernel的UEvent消息。这些消息经NetlinkManager解析后将借助它的Broadcaster(也就是代码中为NetlinkManager设置的CommandListener)发送给Framework层的 NetworkManagementService。
    CommandListener、DnsProxyListener、MDnsSDListener、FwmarkServer:分别创建名为netd、dnsproxyd、mdns、fwmarkServer的监听socket

    NetlinkManager分析
    NetlinkManager(以后简称NM)主要负责接收并解析来自Kernel的UEvent消息。其核心代码在start函数中,如下所示:
    1. int NetlinkManager::start() {  
    2.     //创建接收 NETLINK_KOBJECT_UEVENT 消息的socket,其值保存在mUeventSock中  
    3.     //其中, NETLINK_FORMAT_ASCII 代表UEvent消息的内容为 ASCII字符串  
    4.     if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,  
    5.          0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {  
    6.         return -1;  
    7.     }  
    8.   
    9.     //创建接收 RTMGRP_LINK 消息的socket,其值保存在 mRouteSock 中  
    10.     //其中, NETLINK_FORMAT_BINARY 代表 UEvent 消息的类型为结构体,故需要进行二进制解析  
    11.     if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE,  
    12.                                      RTMGRP_LINK |  
    13.                                      RTMGRP_IPV4_IFADDR |  
    14.                                      RTMGRP_IPV6_IFADDR |  
    15.                                      RTMGRP_IPV6_ROUTE |  
    16.                                      (1 << (RTNLGRP_ND_USEROPT - 1)),  
    17.          NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {  
    18.         return -1;  
    19.     }  
    20.   
    21.     //创建接收 NETLINK_NFLOG 消息的socket,其值保存在 mQuotaSock 中  
    22.     if ((mQuotaHandler = setupSocket(&mQuotaSock, NETLINK_NFLOG,  
    23.         NFLOG_QUOTA_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {  
    24.         ALOGE("Unable to open quota2 logging socket");  
    25.         // TODO: return -1 once the emulator gets a new kernel.  
    26.     }  
    27.   
    28.     return 0;  
    29. }  
    NM的start函数主要是向Kernel注册三个用于接收UEvent事件的socket,这三个UEvent分别对应于以下内容
    NETLINK_KOBJECT_UEVENT: 代表 kobject 事件,由于这些事件包含的信息由ASCII字符串表述,故上述代码中使用了 NETLINK_FORMAT_ASCII。 它表示将采用字符串解析的方法去解析接收到的UEvent 消息。 kobject 一般用来通知内核中某个模块的加载或卸载。对于NM来说,其关注的是 /sys/class/net下相应模块的加载或卸载消息。
    NETLINK_ROUTE:代表Kernel中routing或link改变时对应的消息。 NETLINK_ROUTE 包含很多子项,上述代码中使用了 RTMGRP_LINK 项。二者结合起来使用,表示NM希望收到网络链路断开或接通时对应的UEvent消息。由于对应UEvent消息内部封装了 nlmsghdr 等相关结构体,故上述代码使用了 NETLINK_FORMAT_BINARY来指示解析 UEvent消息时将使用二进制的解析方法。
    NETLINK_NFLOG:和2.3.6节介绍的带宽控制有关。Netd中的带宽控制可以设置一个预警值,当网络数据超过一定字节数就会触发Kernel发送一个警告。该功能属于iptables 的扩展项。值得指出的是,上述代码中有关 NETLINK_NFLOG 相关socket的设置并非所有 Kernel版本都支持。同时, NFLOG_QUOTA_GROUP 的值是直接定义在 NetlinkManager.cpp中的,而非和其他类似系统定义一样定义在系统头文件中,这也表明 NFLOG_QUOTA_GROUP 的功能比较新。
    NetlinkHandler接收到的UEvent消息会转换成一个NetlinkEvent对象。NetlinkEvent对象封装了对 UEvent消息的解析方法。对于 NETLINK_FORMAT_ASCII类型,其 parseAsciiNetlinkMessage函数会被调用,而对于 NETLINK_FORMAT_BINARY类型,其 parseBinaryNetlinkMessage 函数会被调用。
    NM处理流程的输入为一个解析后的 NetlinkEvent对象。NM完成相应工作后,其处理结果将经由 mBroadcaster对象传递给 Framework层的接收者,也就是 NetworkManagementService。
    CommandListener 从 FrameworkListener派生,而 FrameworkListener 内部有一个数组 mCommands,用来存储注册到 FrameworkListener中的命令处理对象。
    下面简单了解 NetlinkHandler 的 onEvent 函数:
    1. void NetlinkHandler::onEvent(NetlinkEvent *evt) {  
    2.     const char *subsys = evt->getSubsystem();  
    3.     if (!subsys) {  
    4.         ALOGW("No subsystem found in netlink event");  
    5.         return;  
    6.     }  
    7.   
    8.     //处理对应 NETLINK_KOBJECT_UEVENT和 NETLINK_ROUTE 的消息  
    9.     if (!strcmp(subsys, "net")) {  
    10.         int action = evt->getAction();  
    11.         const char *iface = evt->findParam("INTERFACE");//查找消息中携带的网络设备名  
    12.   
    13.         if (action == evt->NlActionAdd) {  
    14.             notifyInterfaceAdded(iface); //添加NIC(Network Interface Card)的消息  
    15.         } else if (action == evt->NlActionRemove) {  
    16.             notifyInterfaceRemoved(iface);  //NIC被移除的消息  
    17.         } else if (action == evt->NlActionChange) {  
    18.             evt->dump();  
    19.             notifyInterfaceChanged("nana"true); //NIC变化消息  
    20.         } else if (action == evt->NlActionLinkUp) { //下面两个消息来自 NETLINK_ROUTE  
    21.             notifyInterfaceLinkChanged(iface, true);    //链路启用(类此插网线)  
    22.         } else if (action == evt->NlActionLinkDown) {  
    23.             notifyInterfaceLinkChanged(iface, false);   //链路断开(类似拔网线)  
    24.         } else if (action == evt->NlActionAddressUpdated ||  
    25.                    action == evt->NlActionAddressRemoved) {  
    26.             const char *address = evt->findParam("ADDRESS");  
    27.             const char *flags = evt->findParam("FLAGS");  
    28.             const char *scope = evt->findParam("SCOPE");  
    29.             if (action == evt->NlActionAddressRemoved && iface && address) {  
    30.                 int resetMask = strchr(address, ':') ? RESET_IPV6_ADDRESSES : RESET_IPV4_ADDRESSES;  
    31.                 resetMask |= RESET_IGNORE_INTERFACE_ADDRESS;  
    32.                 if (int ret = ifc_reset_connections(iface, resetMask)) {  
    33.                     ALOGE("ifc_reset_connections failed on iface %s for address %s (%s)", iface,  
    34.                           address, strerror(ret));  
    35.                 }  
    36.             }  
    37.             if (iface && flags && scope) {  
    38.                 notifyAddressChanged(action, address, iface, flags, scope);  
    39.             }  
    40.         } else if (action == evt->NlActionRdnss) {  
    41.             const char *lifetime = evt->findParam("LIFETIME");  
    42.             const char *servers = evt->findParam("SERVERS");  
    43.             if (lifetime && servers) {  
    44.                 notifyInterfaceDnsServers(iface, lifetime, servers);  
    45.             }  
    46.         } else if (action == evt->NlActionRouteUpdated ||  
    47.                    action == evt->NlActionRouteRemoved) {  
    48.             const char *route = evt->findParam("ROUTE");  
    49.             const char *gateway = evt->findParam("GATEWAY");  
    50.             const char *iface = evt->findParam("INTERFACE");  
    51.             if (route && (gateway || iface)) {  
    52.                 notifyRouteChange(action, route, gateway, iface);  
    53.             }  
    54.         }  
    55.   
    56.     } else if (!strcmp(subsys, "qlog")) {   //对应 NETLINK_NFLOG  
    57.         const char *alertName = evt->findParam("ALERT_NAME");  
    58.         const char *iface = evt->findParam("INTERFACE");  
    59.         notifyQuotaLimitReached(alertName, iface);      //当数据量超过预警值,则会收到该通知  
    60.   
    61.     } else if (!strcmp(subsys, "xt_idletimer")) {//这和后文的idletimer有关,用于跟踪某个 NIC的工作状态,即idle或active,检测时间按秒计算  
    62.         const char *label = evt->findParam("INTERFACE");  
    63.         const char *state = evt->findParam("STATE");  
    64.         const char *timestamp = evt->findParam("TIME_NS");  
    65.         if (state)  
    66.             notifyInterfaceClassActivity(label, !strcmp("active", state), timestamp);  
    67.   
    68. #if !LOG_NDEBUG  
    69.     } else if (strcmp(subsys, "platform") && strcmp(subsys, "backlight")) {  
    70.         /* It is not a VSYNC or a backlight event */  
    71.         ALOGV("unexpected event from subsystem %s", subsys);  
    72. #endif  
    73.     }  
    74. }  
    由上边代码可知, NETLINK_KOBJECT_UEVENT和 NETLINK_ROUTE 主要反映网络设备的事件和状态,包括NIC的添加、删除和修改,以及链路的连接状态等。 NETLINK_NFLOG 用于反映设置的log是否超过配额。另外,上边代码中还处理了 xt_idletimer 的 uevent 消息,它和后文介绍的 IdleTimerCmd 有关,主要用来监视网络设备的收发工作状态。当对应设备工作或空闲时间超过设置的监控时间后, Kernel将会发送携带其状态(idle或active)的UEvent消息。
    NM创建 NetlinkHandler 后,工作便转交给 NetlinkHandler来完成,而每个 NetlinkHandler对象均会单独创建一个线程用于接收 socket 消息。当 Kernel 发送 UEvent 消息后, NetlinkHandler便从select调用中返回,然后调用其 onDataAvailable 函数,该函数内部会创建一个 NetlinkEvent 对象。 NetlinkEvent 对象根据 socket 创建时指定的解析类型去解析来自 Kernel 的UEvent消息。 最终NetlinkHandler 的 onEvent 将被调用,不同的UEvent消息将在此函数中进行分类处理。 NetlinkHandler 最终将处理结果经由 NM 内部变量 mBroadcaster 转发给 NetworkManagementService。
    Netd 中的第二个重要成员是 CommandListener(以后简称CL),其主要作用是接收来自 Framework 层 NetworkManageService 的命令。从角色来看,CL仅是一个Listener 。它在收到命令后,只是将它们转交给对应的命令处理对象去处理。 CL 内部定义了许多命令,而这些命令都有较深的背景知识。
    CL定义了11个和网络相关的Command 类。这些类均从 NetdCommand 派生。 CL 还定义了11个控制类, 这些控制类将和命令类共同完成相应的命令处理工作。
    CL创建时,需要注册自己支持的命令类:
    构造函数:
    android-5.1/system/netd/server/CommandListener.cpp
    1. CommandListener::CommandListener() :  
    2.                  FrameworkListener("netd"true) {  
    3.     registerCmd(new InterfaceCmd());//注册11个命令类对象  
    4.     registerCmd(new IpFwdCmd());  
    5.     registerCmd(new TetherCmd());  
    6.     registerCmd(new NatCmd());  
    7.     registerCmd(new ListTtysCmd());  
    8.     registerCmd(new PppdCmd());  
    9.     registerCmd(new SoftapCmd());  
    10.     registerCmd(new BandwidthControlCmd());  
    11.     registerCmd(new IdletimerControlCmd());  
    12.     registerCmd(new ResolverCmd());  
    13.     registerCmd(new FirewallCmd());  
    14.     registerCmd(new ClatdCmd());  
    15.     registerCmd(new NetworkCommand());  
    16.   
    17.     //创建对应的控制类对象  
    18.     if (!sNetCtrl)  
    19.         sNetCtrl = new NetworkController();  
    20.     if (!sTetherCtrl)  
    21.         sTetherCtrl = new TetherController();  
    22.     if (!sNatCtrl)  
    23.         sNatCtrl = new NatController();  
    24.     if (!sPppCtrl)  
    25.         sPppCtrl = new PppController();  
    26.     if (!sSoftapCtrl)  
    27.         sSoftapCtrl = new SoftapController();  
    28.     if (!sBandwidthCtrl)  
    29.         sBandwidthCtrl = new BandwidthController();  
    30.     if (!sIdletimerCtrl)  
    31.         sIdletimerCtrl = new IdletimerController();  
    32.     if (!sResolverCtrl)  
    33.         sResolverCtrl = new ResolverController();  
    34.     if (!sFirewallCtrl)  
    35.         sFirewallCtrl = new FirewallController();  
    36.     if (!sInterfaceCtrl)  
    37.         sInterfaceCtrl = new InterfaceController();  
    38.     if (!sClatdCtrl)  
    39.         sClatdCtrl = new ClatdController(sNetCtrl);  
    40.   
    41.     /* 
    42.      * This is the only time we touch top-level chains in iptables; controllers 
    43.      * should only mutate rules inside of their children chains, as created by 
    44.      * the constants above. 
    45.      * 
    46.      * Modules should never ACCEPT packets (except in well-justified cases); 
    47.      * they should instead defer to any remaining modules using RETURN, or 
    48.      * otherwise DROP/REJECT. 
    49.      */  
    50.   
    51.     // Create chains for children modules  
    52.     //初始化 iptables 中的各个Table 及相应 Chain 和 Rules  
    53.     createChildChains(V4V6, "filter""INPUT", FILTER_INPUT);  
    54.     createChildChains(V4V6, "filter""FORWARD", FILTER_FORWARD);  
    55.     createChildChains(V4V6, "filter""OUTPUT", FILTER_OUTPUT);  
    56.     createChildChains(V4V6, "raw""PREROUTING", RAW_PREROUTING);  
    57.     createChildChains(V4V6, "mangle""POSTROUTING", MANGLE_POSTROUTING);  
    58.     createChildChains(V4, "mangle""FORWARD", MANGLE_FORWARD);  
    59.     createChildChains(V4, "nat""PREROUTING", NAT_PREROUTING);  
    60.     createChildChains(V4, "nat""POSTROUTING", NAT_POSTROUTING);  
    61.   
    62.     // Let each module setup their child chains  
    63.     //netd允许OEM厂商可自定义一些规则,这些规则在 /system/bin/oem-iptables-init.sh文件中保存  
    64.     setupOemIptablesHook();  
    65.   
    66.     /* When enabled, DROPs all packets except those matching rules. */  
    67.     //初始化 iptables中的一些chain,以及初始化路由表  
    68.     sFirewallCtrl->setupIptablesHooks();  
    69.   
    70.     /* Does DROPs in FORWARD by default */  
    71.     sNatCtrl->setupIptablesHooks();  
    72.     /* 
    73.      * Does REJECT in INPUT, OUTPUT. Does counting also. 
    74.      * No DROP/REJECT allowed later in netfilter-flow hook order. 
    75.      */  
    76.     sBandwidthCtrl->setupIptablesHooks();  
    77.     /* 
    78.      * Counts in nat: PREROUTING, POSTROUTING. 
    79.      * No DROP/REJECT allowed later in netfilter-flow hook order. 
    80.      */  
    81.     sIdletimerCtrl->setupIptablesHooks();  
    82.   
    83.     //初始化时,Netd将禁止带宽控制功能  
    84.     sBandwidthCtrl->enableBandwidthControl(false);  
    85.   
    86.     if (int ret = RouteController::Init(NetworkController::LOCAL_NET_ID)) {  
    87.         ALOGE("failed to initialize RouteController (%s)", strerror(-ret));  
    88.     }  
    89. }  
    由于 CL 的间接基类也是 SocketListener,所以其工作流程和 NetlinkHandler 类似。

    CL构造函数的后半部分工作主要是利用iptables等工具创建较多的Chain和Rule,以及对某些命令控制对象进行初始化。


    DnsProxyListener 和 Android 系统中的 DNS 管理有关。
    getaddrinfo 函数分析
    android-5.1/bionic/libc/dns/net/getaddrinfo.c
    1. int  
    2. getaddrinfo(const char *hostname, const char *servname,  
    3.     const struct addrinfo *hints, struct addrinfo **res)  
    4. {  
    5.     //Android平台的特殊定制  
    6.     return android_getaddrinfofornet(hostname, servname, hints, NETID_UNSET, MARK_UNSET, res);  
    7. }  
    8. Android平台的 getaddrinfo 会调用其定制的 android_getaddrinfofornet 函数完成一些特殊操作:  
    9. int  
    10. android_getaddrinfofornet(const char *hostname, const char *servname,  
    11.     const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res)  
    12. {  
    13.     struct addrinfo sentinel;  
    14.     struct addrinfo *cur;  
    15.     int error = 0;  
    16.     struct addrinfo ai;  
    17.     struct addrinfo ai0;  
    18.     struct addrinfo *pai;  
    19.     const struct explore *ex;  
    20.     //取 ANDROID_DNS_MODE 环境变量  
    21.     //只有android-5.1/system/netd/server/main.cpp中设置了此变量:setenv("ANDROID_DNS_MODE", "local", 1);  
    22.     const char* cache_mode = getenv("ANDROID_DNS_MODE");  
    23.   
    24.     /* hostname is allowed to be NULL */  
    25.     /* servname is allowed to be NULL */  
    26.     /* hints is allowed to be NULL */  
    27.     assert(res != NULL);  
    28.     memset(&sentinel, 0, sizeof(sentinel));  
    29.     cur = &sentinel;  
    30.     pai = &ai;  
    31.     pai->ai_flags = 0;  
    32.     pai->ai_family = PF_UNSPEC;  
    33.     pai->ai_socktype = ANY;  
    34.     pai->ai_protocol = ANY;  
    35.     pai->ai_addrlen = 0;  
    36.     pai->ai_canonname = NULL;  
    37.     pai->ai_addr = NULL;  
    38.     pai->ai_next = NULL;  
    39.   
    40.     if (hostname == NULL && servname == NULL)  
    41.         return EAI_NONAME;  
    42.     if (hints) {  
    43.         /* error check for hints */  
    44.         if (hints->ai_addrlen || hints->ai_canonname ||  
    45.             hints->ai_addr || hints->ai_next)  
    46.             ERR(EAI_BADHINTS); /* xxx */  
    47.         if (hints->ai_flags & ~AI_MASK)  
    48.             ERR(EAI_BADFLAGS);  
    49.         switch (hints->ai_family) {  
    50.         case PF_UNSPEC:  
    51.         case PF_INET:  
    52. #ifdef INET6  
    53.         case PF_INET6:  
    54. #endif  
    55.             break;  
    56.         default:  
    57.             ERR(EAI_FAMILY);  
    58.         }  
    59.         memcpy(pai, hints, sizeof(*pai));  
    60.   
    61.         /* 
    62.          * if both socktype/protocol are specified, check if they 
    63.          * are meaningful combination. 
    64.          */  
    65.         if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {  
    66.             for (ex = explore; ex->e_af >= 0; ex++) {  
    67.                 if (pai->ai_family != ex->e_af)  
    68.                     continue;  
    69.                 if (ex->e_socktype == ANY)  
    70.                     continue;  
    71.                 if (ex->e_protocol == ANY)  
    72.                     continue;  
    73.                 if (pai->ai_socktype == ex->e_socktype  
    74.                  && pai->ai_protocol != ex->e_protocol) {  
    75.                     ERR(EAI_BADHINTS);  
    76.                 }  
    77.             }  
    78.         }  
    79.     }  
    80.   
    81.     /* 
    82.      * check for special cases.  (1) numeric servname is disallowed if 
    83.      * socktype/protocol are left unspecified. (2) servname is disallowed 
    84.      * for raw and other inet{,6} sockets. 
    85.      */  
    86.     if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)  
    87. #ifdef PF_INET6  
    88.      || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)  
    89. #endif  
    90.         ) {  
    91.         ai0 = *pai; /* backup *pai */  
    92.   
    93.         if (pai->ai_family == PF_UNSPEC) {  
    94. #ifdef PF_INET6  
    95.             pai->ai_family = PF_INET6;  
    96. #else  
    97.             pai->ai_family = PF_INET;  
    98. #endif  
    99.         }  
    100.         error = get_portmatch(pai, servname);  
    101.         if (error)  
    102.             ERR(error);  
    103.   
    104.         *pai = ai0;  
    105.     }  
    106.   
    107.     ai0 = *pai;  
    108.   
    109.     /* NULL hostname, or numeric hostname */  
    110.     for (ex = explore; ex->e_af >= 0; ex++) {  
    111.         *pai = ai0;  
    112.   
    113.         /* PF_UNSPEC entries are prepared for DNS queries only */  
    114.         if (ex->e_af == PF_UNSPEC)  
    115.             continue;  
    116.   
    117.         if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))  
    118.             continue;  
    119.         if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))  
    120.             continue;  
    121.         if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))  
    122.             continue;  
    123.   
    124.         if (pai->ai_family == PF_UNSPEC)  
    125.             pai->ai_family = ex->e_af;  
    126.         if (pai->ai_socktype == ANY && ex->e_socktype != ANY)  
    127.             pai->ai_socktype = ex->e_socktype;  
    128.         if (pai->ai_protocol == ANY && ex->e_protocol != ANY)  
    129.             pai->ai_protocol = ex->e_protocol;  
    130.   
    131.         if (hostname == NULL)  
    132.             error = explore_null(pai, servname, &cur->ai_next);  
    133.         else  
    134.             error = explore_numeric_scope(pai, hostname, servname,  
    135.                 &cur->ai_next);  
    136.   
    137.         if (error)  
    138.             goto free;  
    139.   
    140.         while (cur->ai_next)  
    141.             cur = cur->ai_next;  
    142.     }  
    143.   
    144.     /* 
    145.      * XXX 
    146.      * If numeric representation of AF1 can be interpreted as FQDN 
    147.      * representation of AF2, we need to think again about the code below. 
    148.      */  
    149.     if (sentinel.ai_next)  
    150.         goto good;  
    151.   
    152.     if (hostname == NULL)  
    153.         ERR(EAI_NODATA);  
    154.     if (pai->ai_flags & AI_NUMERICHOST)  
    155.         ERR(EAI_NONAME);  
    156.   
    157.         /* 
    158.          * BEGIN ANDROID CHANGES; proxying to the cache 
    159.          */  
    160.     //如果是Netd进程调用,则判断不成立,因为两个都返回0  
    161.     //如果非Netd进程调用,则判断成立  
    162.     if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {  
    163.         // we're not the proxy - pass the request to them  
    164.         return android_getaddrinfo_proxy(hostname, servname, hints, res, netid);  
    165.     }  
    166.   
    167.     /* 
    168.      * hostname as alphabetical name. 
    169.      * we would like to prefer AF_INET6 than AF_INET, so we'll make a 
    170.      * outer loop by AFs. 
    171.      */  
    172.     for (ex = explore; ex->e_af >= 0; ex++) {  
    173.         *pai = ai0;  
    174.   
    175.         /* require exact match for family field */  
    176.         if (pai->ai_family != ex->e_af)  
    177.             continue;  
    178.   
    179.         if (!MATCH(pai->ai_socktype, ex->e_socktype,  
    180.                 WILD_SOCKTYPE(ex))) {  
    181.             continue;  
    182.         }  
    183.         if (!MATCH(pai->ai_protocol, ex->e_protocol,  
    184.                 WILD_PROTOCOL(ex))) {  
    185.             continue;  
    186.         }  
    187.   
    188.         if (pai->ai_socktype == ANY && ex->e_socktype != ANY)  
    189.             pai->ai_socktype = ex->e_socktype;  
    190.         if (pai->ai_protocol == ANY && ex->e_protocol != ANY)  
    191.             pai->ai_protocol = ex->e_protocol;  
    192.   
    193.         error = explore_fqdn(pai, hostname, servname,  
    194.             &cur->ai_next, netid, mark);  
    195.   
    196.         while (cur && cur->ai_next)  
    197.             cur = cur->ai_next;  
    198.     }  
    199.   
    200.     /* XXX */  
    201.     if (sentinel.ai_next)  
    202.         error = 0;  
    203.   
    204.     if (error)  
    205.         goto free;  
    206.     if (error == 0) {  
    207.         if (sentinel.ai_next) {  
    208.  good:  
    209.             *res = sentinel.ai_next;  
    210.             return SUCCESS;  
    211.         } else  
    212.             error = EAI_FAIL;  
    213.     }  
    214.  free:  
    215.  bad:  
    216.     if (sentinel.ai_next)  
    217.         freeaddrinfo(sentinel.ai_next);  
    218.     *res = NULL;  
    219.     return error;  
    220. }  
    非Netd进程调用时,会执行函数 android_getaddrinfo_proxy
    1. static int  
    2. android_getaddrinfo_proxy(  
    3.     const char *hostname, const char *servname,  
    4.     const struct addrinfo *hints, struct addrinfo **res, unsigned netid)  
    5. {  
    6.     int sock;  
    7.     const int one = 1;  
    8.     struct sockaddr_un proxy_addr;  
    9.     FILE* proxy = NULL;  
    10.     int success = 0;  
    11.   
    12.     // Clear this at start, as we use its non-NULLness later (in the  
    13.     // error path) to decide if we have to free up any memory we  
    14.     // allocated in the process (before failing).  
    15.     *res = NULL;  
    16.   
    17.     // Bogus things we can't serialize.  Don't use the proxy.  These will fail - let them.  
    18.     if ((hostname != NULL &&  
    19.          strcspn(hostname, "  ^'"") != strlen(hostname)) ||  
    20.         (servname != NULL &&  
    21.          strcspn(servname, "  ^'"") != strlen(servname))) {  
    22.         return EAI_NODATA;  
    23.     }  
    24.   
    25.     //建立和Netd中 DnsProxyListener 的连接,将请求转发给它去执行  
    26.     sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);  
    27.     if (sock < 0) {  
    28.         return EAI_NODATA;  
    29.     }  
    30.   
    31.     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));  
    32.     memset(&proxy_addr, 0, sizeof(proxy_addr));  
    33.     proxy_addr.sun_family = AF_UNIX;  
    34.     strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd",  
    35.         sizeof(proxy_addr.sun_path));  
    36.     if (TEMP_FAILURE_RETRY(connect(sock,  
    37.                        (const struct sockaddr*) &proxy_addr,  
    38.                        sizeof(proxy_addr))) != 0) {  
    39.         close(sock);  
    40.         return EAI_NODATA;  
    41.     }  
    42.   
    43.     netid = __netdClientDispatch.netIdForResolv(netid);  
    44.   
    45.     // Send the request.  
    46.     //发送请求,处理回复等  
    47.     proxy = fdopen(sock, "r+");  
    48.     if (fprintf(proxy, "getaddrinfo %s %s %d %d %d %d %u",  
    49.             hostname == NULL ? "^" : hostname,  
    50.             servname == NULL ? "^" : servname,  
    51.             hints == NULL ? -1 : hints->ai_flags,  
    52.             hints == NULL ? -1 : hints->ai_family,  
    53.             hints == NULL ? -1 : hints->ai_socktype,  
    54.             hints == NULL ? -1 : hints->ai_protocol,  
    55.             netid) < 0) {  
    56.         goto exit;  
    57.     }  
    58.     // literal NULL byte at end, required by FrameworkListener  
    59.     if (fputc(0, proxy) == EOF ||  
    60.         fflush(proxy) != 0) {  
    61.         goto exit;  
    62.     }  
    63.   
    64.     char buf[4];  
    65.     // read result code for gethostbyaddr  
    66.     if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) {  
    67.         goto exit;  
    68.     }  
    69.   
    70.     int result_code = (int)strtol(buf, NULL, 10);  
    71.     // verify the code itself  
    72.     if (result_code != DnsProxyQueryResult ) {  
    73.         fread(buf, 1, sizeof(buf), proxy);  
    74.         goto exit;  
    75.     }  
    76.   
    77.     struct addrinfo* ai = NULL;  
    78.     struct addrinfo** nextres = res;  
    79.     while (1) {  
    80.         uint32_t addrinfo_len;  
    81.         if (fread(&addrinfo_len, sizeof(addrinfo_len),  
    82.               1, proxy) != 1) {  
    83.             break;  
    84.         }  
    85.         addrinfo_len = ntohl(addrinfo_len);  
    86.         if (addrinfo_len == 0) {  
    87.             success = 1;  
    88.             break;  
    89.         }  
    90.   
    91.         if (addrinfo_len < sizeof(struct addrinfo)) {  
    92.             break;  
    93.         }  
    94.         struct addrinfo* ai = calloc(1, addrinfo_len +  
    95.                          sizeof(struct sockaddr_storage));  
    96.         if (ai == NULL) {  
    97.             break;  
    98.         }  
    99.   
    100.         if (fread(ai, addrinfo_len, 1, proxy) != 1) {  
    101.             // Error; fall through.  
    102.             break;  
    103.         }  
    104.   
    105.         // Zero out the pointer fields we copied which aren't  
    106.         // valid in this address space.  
    107.         ai->ai_addr = NULL;  
    108.         ai->ai_canonname = NULL;  
    109.         ai->ai_next = NULL;  
    110.   
    111.         // struct sockaddr  
    112.         uint32_t addr_len;  
    113.         if (fread(&addr_len, sizeof(addr_len), 1, proxy) != 1) {  
    114.             break;  
    115.         }  
    116.         addr_len = ntohl(addr_len);  
    117.         if (addr_len != 0) {  
    118.             if (addr_len > sizeof(struct sockaddr_storage)) {  
    119.                 // Bogus; too big.  
    120.                 break;  
    121.             }  
    122.             struct sockaddr* addr = (struct sockaddr*)(ai + 1);  
    123.             if (fread(addr, addr_len, 1, proxy) != 1) {  
    124.                 break;  
    125.             }  
    126.             ai->ai_addr = addr;  
    127.         }  
    128.   
    129.         // cannonname  
    130.         uint32_t name_len;  
    131.         if (fread(&name_len, sizeof(name_len), 1, proxy) != 1) {  
    132.             break;  
    133.         }  
    134.         name_len = ntohl(name_len);  
    135.         if (name_len != 0) {  
    136.             ai->ai_canonname = (char*) malloc(name_len);  
    137.             if (fread(ai->ai_canonname, name_len, 1, proxy) != 1) {  
    138.                 break;  
    139.             }  
    140.             if (ai->ai_canonname[name_len - 1] != '') {  
    141.                 // The proxy should be returning this  
    142.                 // NULL-terminated.  
    143.                 break;  
    144.             }  
    145.         }  
    146.   
    147.         *nextres = ai;  
    148.         nextres = &ai->ai_next;  
    149.         ai = NULL;  
    150.     }  
    151.   
    152.     if (ai != NULL) {  
    153.         // Clean up partially-built addrinfo that we never ended up  
    154.         // attaching to the response.  
    155.         freeaddrinfo(ai);  
    156.     }  
    157. exit:  
    158.     if (proxy != NULL) {  
    159.         fclose(proxy);  
    160.     }  
    161.   
    162.     if (success) {  
    163.         return 0;  
    164.     }  
    165.   
    166.     // Proxy failed;  
    167.     // clean up memory we might've allocated.  
    168.     if (*res) {  
    169.         freeaddrinfo(*res);  
    170.         *res = NULL;  
    171.     }  
    172.     return EAI_NODATA;  
    173. }  
    当非Netd进程调用 getaddrinfo 时,会调用函数 android_getaddrinfo_proxy, 它将和Netd进程中的 dnsproxyd 监听 socket建立连接,然后把请求发给 DNSProxyListener去执行。当然最后还是会调回到 getaddrinfo 去执行,而此时就变成了 Netd进程的调用了,Netd进程将向指定的 DNS 服务器发起请求以解析域名。
    Android系统中通过这种方式来管理DNS的好处是,所有解析后得到的 DNS 记录都将缓存在 Netd 进程中,从而使这些信息成为一个公共的资源,最大程度做到信息共享。

    MDnsSdListener: Multicast DNS Service Discovery
    组播服务
    MDnsSdListener 对应的 Framework 层服务为 NsdService(Nsd为 Network Service Discovery的缩写)。
    MDnsSdListener的内部类 Monitor 用于和 mdnsd 后台进程通信,它将调用Bonjour AIP。
    Monitor 内部针对每个 DNSService 都会建立一个 Element 对象,该对象通过 Monitor 的 mHead 指针保存在一个list中。
    Handler 是 MDnsSdListener 注册的 Command。
    MDnsSdListener 运行过程主要可分成三步:
    1.Netd创建 MDnsSdListener对象,其内部会创建 Monitor对象,而Monitor对象将启动一个线程用于和 mdnsd通信,并接收来自Handler的请求。
    2.NsdService 启动完毕后将向 MDnsSdListener发送 "start-service"命令。
    3.NsdService 响应应用程序的请求,向 MDnsSdListener 发送其他命令,例如 "discovery" 等。Monitor将最终处理这些请求。
    先看第一步,当 MDnsSdListener 构造时,会创建一个 Monitor 对象:
    android-5.1/system/netd/server/MDnsSdListener.cpp
    1. MDnsSdListener::Monitor::Monitor() {  
    2.     mHead = NULL;  
    3.     mLiveCount = 0;  
    4.     mPollFds = NULL;  
    5.     mPollRefs = NULL;  
    6.     mPollSize = 10;  
    7.     //创建两个socket,用于接收 MDnsSdListener 对象的命令  
    8.     socketpair(AF_LOCAL, SOCK_STREAM, 0, mCtrlSocketPair);  
    9.     pthread_mutex_init(&mHeadMutex, NULL);  
    10.   
    11.     //创建线程,线程函数是 threadStart,其内部会调用 run  
    12.     pthread_create(&mThread, NULL, MDnsSdListener::Monitor::threadStart, this);  
    13.     pthread_detach(mThread);  
    14. }  
    Monitor的threadStart线程将调用其 run 函数,该函数通过 poll 方式侦听包括 mCtrlSocketPair 在内的 socket 信息。
    当 NsdService 发送 start-service 命令后, Handler 的 runCommand 将执行 Monitor 的 startService 函数:
    android-5.1/system/netd/server/MDnsSdListener.cpp
    1. int MDnsSdListener::Monitor::startService() {  
    2.     int result = 0;  
    3.     char property_value[PROPERTY_VALUE_MAX];  
    4.     pthread_mutex_lock(&mHeadMutex);  
    5.     //MDNS_SERVICE_STATUS是一个字符串,值为"init.svc.mdnsd",在 init.rc 配置文件中, mdnsd是一个service,而"init.svc.mdnsd"将记录mdnsd进程的运行状态。  
    6.     property_get(MDNS_SERVICE_STATUS, property_value, "");  
    7.     if (strcmp("running", property_value) != 0) {  
    8.         ALOGD("Starting MDNSD");  
    9.         //如果 mdnsd 的状态不为 running,则通过设置 ctl.start 命令启动 mdnsd  
    10.         property_set("ctl.start", MDNS_SERVICE_NAME);  
    11.         //如果mdnsd成功启动,则属性变为running  
    12.         wait_for_property(MDNS_SERVICE_STATUS, "running", 5);  
    13.         result = -1;  
    14.     } else {  
    15.         result = 0;  
    16.     }  
    17.     pthread_mutex_unlock(&mHeadMutex);  
    18.     return result;  
    19. }  
    startService的实现比较有趣,充分利用了init的属性控制以启动 mdnsd 进程。
    当 NsdService 发送注册服务请求时, Handler 的 serviceRegister 函数将被调用:
    android-5.1/system/netd/server/MDnsSdListener.cpp
    1. void MDnsSdListener::Handler::serviceRegister(SocketClient *cli, int requestId,  
    2.         const char *interfaceName, const char *serviceName, const char *serviceType,  
    3.         const char *domain, const char *host, int port, int txtLen, void *txtRecord) {  
    4.     if (VDBG) {  
    5.         ALOGD("serviceRegister(%d, %s, %s, %s, %s, %s, %d, %d, <binary>)", requestId,  
    6.                 interfaceName, serviceName, serviceType, domain, host, port, txtLen);  
    7.     }  
    8.     Context *context = new Context(requestId, mListener);  
    9.     DNSServiceRef *ref = mMonitor->allocateServiceRef(requestId, context);  
    10.     port = htons(port);  
    11.     if (ref == NULL) {  
    12.         ALOGE("requestId %d already in use during register call", requestId);  
    13.         cli->sendMsg(ResponseCode::CommandParameterError,  
    14.                 "RequestId already in use during register call"false);  
    15.         return;  
    16.     }  
    17.     DNSServiceFlags nativeFlags = 0;  
    18.     int interfaceInt = ifaceNameToI(interfaceName);  
    19.     //调用 Bonjour API DNSServiceRegister,并注册回调函数 MDnsSdListenerRegisterCallback  
    20.     DNSServiceErrorType result = DNSServiceRegister(ref, interfaceInt, nativeFlags, serviceName,  
    21.             serviceType, domain, host, port, txtLen, txtRecord, &MDnsSdListenerRegisterCallback,  
    22.             context);  
    23.     if (result != kDNSServiceErr_NoError) {  
    24.         ALOGE("service register request %d got an error from DNSServiceRegister %d", requestId,  
    25.                 result);  
    26.         mMonitor->freeServiceRef(requestId);  
    27.         cli->sendMsg(ResponseCode::CommandParameterError,  
    28.                 "serviceRegister request got an error from DNSServiceRegister"false);  
    29.         return;  
    30.     }  
    31.     调用 Monitor 对象进行 rescan  
    32.     mMonitor->startMonitoring(requestId);  
    33.     if (VDBG) ALOGD("serviceRegister successful");  
    34.     cli->sendMsg(ResponseCode::CommandOkay, "serviceRegister started"false);  
    35.     return;  
    36. }  
    DNSServiceRegister 内部将把请求发送给 mdnsd 去处理,处理的结果通过 MDnsSdListenerRegisterCallback 返回:
    1. void MDnsSdListenerRegisterCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* flags */,  
    2.         DNSServiceErrorType errorCode, const char *serviceName, const char * /* regType */,  
    3.         const char * /* domain */void *inContext) {  
    4.     MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);  
    5.     char *msg;  
    6.     int refNumber = context->mRefNumber;  
    7.     if (errorCode != kDNSServiceErr_NoError) {  
    8.         asprintf(&msg, "%d %d", refNumber, errorCode);  
    9.         context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationFailed, msg, false);  
    10.         if (DBG) ALOGE("register failure for %d, error= %d", refNumber, errorCode);  
    11.     } else {  
    12.         char *quotedServiceName = SocketClient::quoteArg(serviceName);  
    13.         asprintf(&msg, "%d %s", refNumber, quotedServiceName);  
    14.         free(quotedServiceName);  
    15.         //将处理结果返回给 NsdService  
    16.         context->mListener->sendBroadcast(ResponseCode::ServiceRegistrationSucceeded, msg, false);  
    17.         if (VDBG) ALOGD("register succeeded for %d as %s", refNumber, serviceName);  
    18.     }  
    19.     free(msg);  
    20. }  
    Netd的处理流程:
    1、NM接收 Kernel 的UEvent消息,然后转发给 Framework 层的客户端
    2、CL、DPL以及 MDnsSdListener 接收来自客户端的请求并处理它们。
  • 相关阅读:
    let,const及解构赋值
    开发规范
    深入理解javascript之this
    深入理解javascript之作用域
    深入理解javascript之数据存储
    深入理解javascript之定时器
    Android 多选列表对话框 setMultiChoiceItems
    Android 单选列表对话框 setSingleChoiceItems
    Android 列表对话框 setItems
    Android 警告对话框 AlertDialog
  • 原文地址:https://www.cnblogs.com/ztguang/p/12646019.html
Copyright © 2011-2022 走看看