Android以太网网口注册流程

本文详细剖析了Android以太网框架中,底层网口注册事件如何通过Netd服务上报到上层。首先,Netd通过SocketListener监听底层Uevent事件,然后经过NetlinkListener和NetlinkHandler层层封装,最终调用NetlinkManager的onDataAvailable处理底层上报的事件。在这个过程中,NetlinkEvent被创建并解析,提取ACTION参数,根据ACTION的不同调用不同的处理函数。当ACTION为网口注册时,事件会被通知到上层的NetworkManagementService,进而影响到如EthernetTracker等组件,最终通过Listener回调更新网络状态。整个流程涉及到了网络管理、事件监听和处理、状态更新等多个关键环节。

一 引言

  在上一篇文章,我们从上层APP出发,通过以太网的使能来分析了以太网框架中,上层指令如何传递到底层。这篇文章,我们将通过网口注册的流程来分析,以太网框架中,底层事件状态是如何上报给上层。图1-1所示为网口注册的整体流程图。

在这里插入图片描述

图1-1 网口注册整体流程图

二 Netd事件上报流程

  从上一节图1-1可以看出,Netd是通过SocketListener来监听底层的Uevent的事件上报。在分析Netd事件上报之前,有必要先将Netd中相关的类的关系梳理一下,具体类图如下2-1所示:
在这里插入图片描述

图2-1 Netd相关类图关系

从Netd的类图关系看,主要有4个类,其主要作用如下:

  • SocketListener : 这是Native层获取底层Uevent的公用接口类,Android其他一些模块,例如vold模块,也通过该Listener来监听底层Uevent事件。监听到事件后,通过onDataAvailable来处理底层上报的数据;
  • NetlinkListener:该类继承自SocketListener。在onDataAvailable函数中调用onEvent继续封装底层的事件;
  • NetlinkHandler:该类继承自NetlinkListener。在onEvent中继续封装处理底层事件,并通过上层注册的监听对象,将该状态上报给上层。
  • NetlinkManager:其内部维护了几个NetinkHandler引用对象,以及一个SocketListener引用对象,来管理socket的通信,包括socket的创建,以及释放等等。

  Netd在启动时候,会创建NetlinkManager引用对象,并且创建NetlinkHandler的引用对象,并且调用其start来启动监听,最后会调用到SocketListener的runListener函数中,来实时监听底层Uevent事件上报。

//SocketListener.cpp
void SocketListener::runListener() {
    while (true) {
        std::vector<pollfd> fds;

        pthread_mutex_lock(&mClientsLock);
        fds.reserve(2 + mClients.size());
        fds.push_back({.fd = mCtrlPipe[0], .events = POLLIN});
        if (mListen) fds.push_back({.fd = mSock, .events = POLLIN});
        for (auto pair : mClients) {
            // NB: calling out to an other object with mClientsLock held (safe)        
            const int fd = pair.second->getSocket();
            if (fd != pair.first) SLOGE("fd mismatch: %d != %d", fd, pair.first);      
            fds.push_back({.fd = fd, .events = POLLIN});
        }
        pthread_mutex_unlock(&mClientsLock);

        SLOGV("mListen=%d, mSocketName=%s", mListen, mSocketName);                     
        int rc = TEMP_FAILURE_RETRY(poll(fds.data(), fds.size(), -1));                 
        if (rc < 0) {
            SLOGE("poll failed (%s) mListen=%d", strerror(errno), mListen);            
            sleep(1);
            continue;
        }

        if (fds[0].revents & (POLLIN | POLLERR)) {
            char c = CtrlPipe_Shutdown;
            TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
            if (c == CtrlPipe_Shutdown) {
                break;
            }
            continue;                                                                  
        }
        if (mListen && (fds[1].revents & (POLLIN | POLLERR))) {
            int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
            if (c < 0) {
                SLOGE("accept failed (%s)", strerror(errno));
                sleep(1);
                continue;
            }
            pthread_mutex_lock(&mClientsLock);
            mClients[c] = new SocketClient(c, true, mUseCmdNum);
            pthread_mutex_unlock(&mClientsLock);
        }

        // Add all active clients to the pending list first, so we can release         
        // the lock before invoking the callbacks.                                     
        std::vector<SocketClient*> pending;
        pthread_mutex_lock(&mClientsLock);
        const int size = fds.size();
        for (int i = mListen ? 2 : 1; i < size; ++i) {
            const struct pollfd& p = fds[i];
            if (p.revents & (POLLIN | POLLERR)) {
                auto it = mClients.find(p.fd);
                if (it == mClients.end()) {
                    SLOGE("fd vanished: %d", p.fd);
                    continue;
                }
                SocketClient* c = it->second;
                pending.push_back(c);
                c->incRef();
            }
        }
        pthread_mutex_unlock(&mClientsLock);

        for (SocketClient* c : pending) {
            // Process it, if false is returned, remove from the map                   
            SLOGV("processing fd %d", c->getSocket());
            //通过onDataAvailable函数处理底层事件的上报
            if (!onDataAvailable(c)) {
                release(c, false);
            }
            c->decRef();
        }   
    }
}

  在runListener中是一个死循环,实时监听底层的Uevent事件。在接收到底层事件上报后,最终调用onDataAvailable处理,真正实现是在子类NetLinkListener中,具体代码如下:

//NetlinkListener.cpp
bool NetlinkListener::onDataAvailable(SocketClient *cli)                        
{                                                                               
    int socket = cli->getSocket();                                              
    ssize_t count;                                                              
    uid_t uid = -1;                                                             
                                                                                
    bool require_group = true;                                                  
    if (mFormat == NETLINK_FORMAT_BINARY_UNICAST) {                             
        require_group = false;                                                  
    }                                                                           
    //通过uevent_kernel_recv获取底层Uevent事件,并将其存储到mBuffer中
    count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket,                       
            mBuffer, sizeof(mBuffer), require_group, &uid));                    
    if (count < 0) {                                                            
        SLOGE("recvmsg failed (%s)", strerror(errno));                          
        return false;                                                           
    }                                                                           
    //创建NetlinkEvent对象,并且解析后,最终调用onEvent做进一步处理
    NetlinkEvent *evt = new NetlinkEvent();                                     
    if (evt->decode(mBuffer, count, mFormat)) {                                 
        onEvent(evt);                                                           
    } else if (mFormat != NETLINK_FORMAT_BINARY) {                              
        // Don't complain if parseBinaryNetlinkMessage returns false. That can  
        // just mean that the buffer contained no messages we're interested in. 
        SLOGE("Error decoding NetlinkEvent");                                   
    }                                                                           
                                                                                
    delete evt;                                                                 
    return true;                                                                
}                                                                               

在NetLinkListener中的onDataAvailable方法中,主要做了以下三件事:

  • 通过uevent_kernel_recv获取底层的Uevent事件的上报,并将其存储到mBuffer中;
  • 创建NetlinkEvent对象,并调用decode函数,将mBuffer中的数据风封装到NetlinkEvent中;
  • 最终调用子类的onEvent继续处理;
 bool NetlinkEvent::decode(char *buffer, int size, int format) {           
     if (format == NetlinkListener::NETLINK_FORMAT_BINARY                  
             || format == NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST) {
         return parseBinaryNetlinkMessage(buffer, size);                   
     } else {                                                              
         return parseAsciiNetlinkMessage(buffer, size);                    
     }                                                                     
 }                                                                         

在decode函数中,根据底层上报的是二进制数据做不通的处理,如果是二进制数据,则调用parseBinaryNetlinkMessage函数处理;否则调用parseAsciiNetlinkMessage函数处理。二进制主要是路由等信息的上报,此处我们重点关注非二进制的数据上报。

bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) {             
    const char *s = buffer;                                                       
    const char *end;                                                              
    int param_idx = 0;                                                            
    int first = 1;                                                                
                                                                                  
    if (size == 0)                                                                
        return false;                                                             
                                                                                  
    /* Ensure the buffer is zero-terminated, the code below depends on this */    
    buffer[size-1] = '\0';                                                        
                                                                                  
    end = s + size;                                                               
    while (s < end) {                                                             
        if (first) {                                                              
            const char *p;                                                        
            /* buffer is 0-terminated, no need to check p < end */                
            for (p = s; *p != '@'; p++) {                                         
                if (!*p) { /* no '@', should not happen */                        
                    return false;                                                 
                }                                                 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GitFranc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值