Android源码笔记--网络

Posted ljt2724960661

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android源码笔记--网络相关的知识,希望对你有一定的参考价值。

                android网络管理的核心是ConnectivityService 和 NetworkManagerService服务.ConnectivityService主要提供网络连接管理服务,NetworkManagementService主要提供物理网络管理服务。此外还有NetworkPolicyMangerService和NetworkStatsService服务,  NetworkPolicyMangerService服务维护各种网络使用策略。NetworkStatsService服务提供查询网络传输统计信息。

 1  管理各种网络设备-Netd守护进程
    Netd全程是Network Daemon,主要作用是管理各种网络设备。Netd是一个守护进程,通过init进程启动,它在init.rc中的服务定义如下:

service netd /system/bin/netd
    socket netd stream 0660 root system
    socket dnsproxyd stream 0660 root inet

1.1 Netd的框架

Netd模块的源代码位于目录system/netd中,我们先看看它的入口函数,代码如下:

 /system/netd/server/main.cpp
  
  int main() 
	   for (const auto& sock :
         DNSPROXYLISTENER_SOCKET_NAME, FwmarkServer::SOCKET_NAME, MDnsSdListener::SOCKET_NAME) 
        setCloseOnExec(sock);
    
	
	   NetlinkManager *nm = NetlinkManager::Instance();
	   
	       if (nm == nullptr) 
        ALOGE("Unable to create NetlinkManager");
        exit(1);
    ;

    gCtls = new android::net::Controllers();
    gCtls->init();
	
	    setenv("ANDROID_DNS_MODE", "local", 1);
    // Note that only call initDnsResolver after gCtls initializing.
    if (!initDnsResolver()) 
        ALOGE("Unable to init resolver");
        exit(1);
    

    MDnsSdListener mdnsl;
	
	 FwmarkServer fwmarkServer(&gCtls->netCtrl, &gCtls->eventReporter, &gCtls->trafficCtrl);
    if (fwmarkServer.startListener()) 
        ALOGE("Unable to start FwmarkServer (%s)", strerror(errno));
        exit(1);
    
	
	 // Now that netd is ready to process commands, advertise service availability for HAL clients.
	     sp<NetdHwService> mHwSvc(new NetdHwService());
	       if ((ret = mHwSvc->start()) != android::OK) 
        ALOGE("Unable to start NetdHwService: %d", ret);
        exit(1);
    
	      IPCThreadState::self()->joinThreadPool()
	   
	  exit(0);
	

         通过NetlinkManager 来监听内核的Netlink Socket,然后读取内核发送的uevent,这些uevent最后会在NetlinkHander对象的onEventO函数中得到处理。

        netd.rc文件中netd申明了3个socket,因此,mainO函数中创建了3个FrameworkListenter对象: FwmarkServer、DnsProxyListener和MdnsSdListener,分别监听这3个socket.

1.2 处理net类型的uevent 

        从内核发送过来的 uevent 最终会在NetlinkHandler 的onEvent()函数中处理,这些uevent是内核监测到硬件或驱动发生了变化后发出的。下面是onEvent()函数的代码:

 /system/netd/server/NetlinkHandler.cpp
  
  void NetlinkHandler::onEvent(NetlinkEvent *evt) 
    const char *subsys = evt->getSubsystem();
    if (!subsys) 
        ALOGW("No subsystem found in netlink event");
        return;
    

    if (!strcmp(subsys, "net")) 
        NetlinkEvent::Action action = evt->getAction();
        const char *iface = evt->findParam("INTERFACE");
        if ((action == NetlinkEvent::Action::kAdd) ||
            (action == NetlinkEvent::Action::kLinkUp) ||
            (action == NetlinkEvent::Action::kLinkDown)) 
            const char *ifIndex = evt->findParam("IFINDEX");
            long ifaceIndex = parseIfIndex(ifIndex);
            if (ifaceIndex) 
                gCtls->trafficCtrl.addInterface(iface, ifaceIndex);
             else 
                ALOGE("invalid interface index: %s(%s)", iface, ifIndex);
            
        

        if (action == NetlinkEvent::Action::kAdd) 
            notifyInterfaceAdded(iface);
         else if (action == NetlinkEvent::Action::kRemove) 
            notifyInterfaceRemoved(iface);
         else if (action == NetlinkEvent::Action::kChange) 
            evt->dump();
            notifyInterfaceChanged("nana", true);
         else if (action == NetlinkEvent::Action::kLinkUp) 
            notifyInterfaceLinkChanged(iface, true);
         else if (action == NetlinkEvent::Action::kLinkDown) 
            notifyInterfaceLinkChanged(iface, false);
         else if (action == NetlinkEvent::Action::kAddressUpdated ||
                   action == NetlinkEvent::Action::kAddressRemoved) 
            const char *address = evt->findParam("ADDRESS");
            const char *flags = evt->findParam("FLAGS");
            const char *scope = evt->findParam("SCOPE");
            const char *ifIndex = evt->findParam("IFINDEX");
            char addrstr[INET6_ADDRSTRLEN + strlen("/128")];
            strlcpy(addrstr, address, sizeof(addrstr));
            char *slash = strchr(addrstr, '/');
            if (slash) 
                *slash = '\\0';
            

            long ifaceIndex = parseIfIndex(ifIndex);
            if (!ifaceIndex) 
                ALOGE("invalid interface index: %s(%s)", iface, ifIndex);
            
            const bool addrUpdated = (action == NetlinkEvent::Action::kAddressUpdated);
            if (addrUpdated) 
                gCtls->netCtrl.addInterfaceAddress(ifaceIndex, address);
             else   // action == NetlinkEvent::Action::kAddressRemoved
                bool shouldDestroy = gCtls->netCtrl.removeInterfaceAddress(ifaceIndex, address);
                if (shouldDestroy) 
                    SockDiag sd;
                    if (sd.open()) 
                        int ret = sd.destroySockets(addrstr);
                        if (ret < 0) 
                            ALOGE("Error destroying sockets: %s", strerror(-ret));
                        
                     else 
                        ALOGE("Error opening NETLINK_SOCK_DIAG socket: %s", strerror(errno));
                    
                
            
            // Note: if this interface was deleted, iface is "" and we don't notify.
            if (iface && iface[0] && address && flags && scope) 
                if (addrUpdated) 
                    notifyAddressUpdated(address, iface, std::stoi(flags), std::stoi(scope));
                 else 
                    notifyAddressRemoved(address, iface, std::stoi(flags), std::stoi(scope));
                
            
         else if (action == NetlinkEvent::Action::kRdnss) 
            const char *lifetime = evt->findParam("LIFETIME");
            const char *servers = evt->findParam("SERVERS");
            if (lifetime && servers) 
                notifyInterfaceDnsServers(iface, strtol(lifetime, nullptr, 10),
                                          android::base::Split(servers, ","));
            
         else if (action == NetlinkEvent::Action::kRouteUpdated ||
                   action == NetlinkEvent::Action::kRouteRemoved) 
            const char *route = evt->findParam("ROUTE");
            const char *gateway = evt->findParam("GATEWAY");
            const char *iface = evt->findParam("INTERFACE");
            if (route && (gateway || iface)) 
                notifyRouteChange((action == NetlinkEvent::Action::kRouteUpdated) ? true : false,
                                  route, (gateway == nullptr) ? "" : gateway,
                                  (iface == nullptr) ? "" : iface);
            
        

     else if (!strcmp(subsys, "qlog") || !strcmp(subsys, "xt_quota2")) 
        const char *alertName = evt->findParam("ALERT_NAME");
        const char *iface = evt->findParam("INTERFACE");
        if (alertName && iface) 
            notifyQuotaLimitReached(alertName, iface);
        

     else if (!strcmp(subsys, "strict")) 
        const char *uid = evt->findParam("UID");
        const char *hex = evt->findParam("HEX");
        if (uid && hex) 
            notifyStrictCleartext(strtol(uid, nullptr, 10), hex);
        

     else if (!strcmp(subsys, "xt_idletimer")) 
        const char *label = evt->findParam("INTERFACE");
        const char *state = evt->findParam("STATE");
        const char *timestamp = evt->findParam("TIME_NS");
        const char *uid = evt->findParam("UID");
        if (state) 
            bool isActive = !strcmp("active", state);
            int64_t processTimestamp = (timestamp == nullptr) ? 0 : strtoll(timestamp, nullptr, 10);
            int intLabel;
            // NMS only accepts interface class activity changes with integer labels, and only ever
            // creates idletimers with integer labels.
            if (android::base::ParseInt(label, &intLabel)) 
                const long reportedUid =
                        (uid != nullptr && isActive) ? strtol(uid, nullptr, 10) : -1;
                notifyInterfaceClassActivityChanged(intLabel, isActive, processTimestamp,
                                                    reportedUid);
            
        

#if !LOG_NDEBUG
     else if (strcmp(subsys, "platform") && strcmp(subsys, "backlight")) 
        /* It is not a VSYNC or a backlight event */
        ALOGV("unexpected event from subsystem %s", subsys);
#endif
    

onEvent()函数中,对net类的uenvent的处理只是发消息通知Java层(函数中的各种notify函数只是调用CommandListener的接口向Java层发送消息),底层没有进行任何的处理。这里收到的消息有:

NetlinkEvent::kAdd:系统中增加了一种网络interface。
NetlinkEvent::kRemove:系统中移除了一种网络interface。
NetlinkEvent::kChange:系统中某种网络的 interface发生了变化。
NetlinkEvent:kLinkUp:系统中某个网络interface 建立了连接。
NetlinkEvent:kLinkDown:系统中某个网络 interface 断开了连接。
NetlinkEvent::kAddressUpdated:系统中某个网络interface的地址发生了变化。
NetlinkEvent::kAddressRemoved:系统中某个网络interface 的地址被移除了。
NetlinkEvent::kRouteUpdated:系统路由更新。

另外,还有来自流量控制的通知消息和某个网络Interface进入 activity或idle状态的消息。

1.3 处理NMS的命令 

        NdcDispatcher对象用来处理从 NetworkManagementService中发送的命令。NdcDispatcher类中注册的命令如下:

/system/netd/server/NdcDispatcher.cpp
   
sp<INetd> NdcDispatcher::mNetd;
sp<IDnsResolver> NdcDispatcher::mDnsResolver;

NdcDispatcher::NdcDispatcher() 
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binderNetd = sm->getService(String16("netd"));
    sp<IBinder> binderDnsResolver = sm->getService(String16("dnsresolver"));
    if ((binderNetd != nullptr) && (binderDnsResolver != nullptr)) 
        NdcDispatcher::mNetd = interface_cast<INetd>(binderNetd);
        NdcDispatcher::mDnsResolver = interface_cast<IDnsResolver>(binderDnsResolver);
     else 
        LOG(LOGLEVEL) << "Unable to get binder service";
        exit(1);
    
    registerCmd(new InterfaceCmd());
    registerCmd(new IpFwdCmd());
    registerCmd(new TetherCmd());
    registerCmd(new NatCmd());
    registerCmd(new BandwidthControlCmd());
    registerCmd(new IdletimerControlCmd());
    registerCmd(new FirewallCmd());
    registerCmd(new ClatdCmd());
    registerCmd(new NetworkCommand());
    registerCmd(new StrictCmd());



void NdcDispatcher::registerCmd(NdcNetdCommand* cmd) 
    mCommands.push_back(cmd);


int NdcDispatcher::dispatchCommand(int argc, char** argv) 
    if (argc >= CMD_ARGS_MAX) 
        mNdc.sendMsg(500, "Command too long", false);
    

    for (const auto* c : mCommands) 
        if (c->getCommand() == argv[0]) 
            if (c->runCommand(&mNdc, argc, argv)) 
                mNdc.sendMsg(500, "Handler error", true);
            
            return 0;
        
    
    mNdc.sendMsg(500, "Command not recognized", false);
    return 0;

其中:

InterfaceCmd对象用来处理各种网络Interface相关的命令,例如,添加、删除
IpFwdCmd对象用来处理IP转发的命令,包括status、enable和disable命令;
TetherCmd对象用来处理网络共享的命令;
NatCmd对象用来处理带宽控制的命令;
BandwidthControlCmd 用来处理带宽控制的命令;
IdletimerControlCmd用来处理设置监听网络接口空闲的命令;
FirewallCmd 用来处理设置防火墙的命令;
ClatdCmd用来处理启动或停止 clatd的命令。
NetworkCommand 用来处理解析网络地址的命令,包括设置dns服务器的地址;

 1.4 DNS服务代理

    DnsProxyListener对象实现了DNS服务的代理功能,它注册了以下的命令:

DnsProxyListener::DnsProxyListener() : FrameworkListener(SOCKET_NAME) 
    registerCmd(new GetAddrInfoCmd());
    registerCmd(new GetHostByAddrCmd());
    registerCmd(new GetHostByNameCmd());
    registerCmd(new ResNSendCommand());
    registerCmd(new GetDnsNetIdCommand());

说明:

GetAddrInfoCmd 命令用来完成主机名到IP地址解析。
GetHostByAddrCmd 命令用来完成从IP地址到主机名的解析。
GetHostByNameCmd 命令通过主机名获得主机信息。

1.5 MDnsSdListener的作用-与守护进程进行交互 

/system/netd/server/MDnsSdListener.cpp
  
MDnsSdListener::MDnsSdListener() : FrameworkListener(SOCKET_NAME, true) 
    Monitor *m = new Monitor();
    registerCmd(new Handler(m, this));

       MDnsSdListener 中的命令主要作用是和mdsnd守护进程进行交互。包括启动和停止 mdsnd守护进程,通过mdsnd来解析一些服务的地址等。

以上是关于Android源码笔记--网络的主要内容,如果未能解决你的问题,请参考以下文章

笔记 android网络框架源码解析及对比(待续)

Android源码笔记--网络

Android源码笔记--网络

基于SSM框架智慧物业项目开发全程实录(全程实战附源码)

Android源码笔记--恢复出厂设置

Android源码笔记--恢复出厂设置