Android 4.1 Netd详细分析(四)代码分析2

10 篇文章 1 订阅

个人邮箱:xiaokeweng@gmail.com

 

我们按照main函数代码的执行顺序,首先实例化NetlinkManager。接下来代码如下。

    if (!(nm = NetlinkManager::Instance())) {//实例化对象nm
        ALOGE("Unable to create NetlinkManager");
        exit(1);
    };

    cl = new CommandListener();//实例化对象cl
 
	// 将nm的mBroadcaster设置为cl
	// 这样nm就可以通过cl对象的socket进行广播将消息提交给framework层
    nm->setBroadcaster((SocketListener *) cl);
 
    if (nm->start()) {//nm开始start线程
        ALOGE("Unable to start NetlinkManager (%s)", strerror(errno));
        exit(1);
    }
  

 

首先进行 NetlinkManager 的实例化。从 NetlinkManager.cpp 中可以查看到实例化的内容如下 ,其中 mBroadcaster 的类型是 SocketListener*。

NetlinkManager *NetlinkManager::Instance() {
    if (!sInstance)
        sInstance = new NetlinkManager();
    return sInstance;
}

NetlinkManager::NetlinkManager() {
    mBroadcaster = NULL;
}

接下来实例化 CommandListener 并将 nm 的 setBroadcaster 进行赋值,通过这个步骤操作,可以使 nm 调用到 cl 的 socket 进行广播,意义是将 nm 的处理结果通过内部广播提交给Framework,在后面将详细介绍。

 

而后 nm 调用了它的 start()方法,如下。 函数创建了三个监听线程,根据 setupSocket 参数的不同可以限定监听socket 的监听的内核模块事件,并分别start。

// Netlinkmanager.start() /
int NetlinkManager::start() {
   //监听线程 1: 
    // family : NETLINK_KOBJECT_UEVENT
   // group : 0xffffffff  (all)
    // format :NETLINK_FORMAT_ASCII
    if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
         0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {
        return -1;
    }
    //监听线程2 :  与内核通信模块-> 路由表
    // family : NETLINK_ROUTE
    //  group : RTMGRP_LINK   (RouTeMsg GRouP)
    // format : NETLINK_FORMAT_BINARY 
    if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE, RTMGRP_LINK,
         NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
        return -1;
    }
    //监听线程 3:
    // family : NETLINK_NFLOG
    //  group : NFLOG_QUOTA_GROUP 
    // format : NETLINK_FORMAT_BINARY
    if ((mQuotaHandler = setupSocket(&mQuotaSock, NETLINK_NFLOG,
        NFLOG_QUOTA_GROUP, NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
        ALOGE("Unable to open quota2 logging socket");
        // TODO: return -1 once the emulator gets a new kernel.
    }

    return 0;
}

 

如下式setupSocket()函数,创建socket,设置属性,并start线程开始监听,函数的返回值为 Netlinkhandler 类型。

//参数说明
// sock          : 返回的socket表示符
// netlinkFamily : 指定与那写内核模块通信
// groups        : 多播组掩码
// format        : 创建NetlinkHandler指定的参数,指定对evt的解码方式
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;      //多播组
    //
    //创建socket
    //
    if ((*sock = socket(PF_NETLINK, SOCK_DGRAM, netlinkFamily)) < 0) {
        ALOGE("Unable to create netlink socket: %s", strerror(errno));
        return NULL;
    }

    //recive buffer 
    //空间大小为64K的buff
    if (setsockopt(*sock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
        ALOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
        close(*sock);
        return NULL;
    }

    //pass credentials opt
    //关于credentials(证书)    
    if (setsockopt(*sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
        SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
        close(*sock);
        return NULL;
    }
    //
    //bind函数,将socket绑定唯一的 属性&地址&port……   
    //(因sockaddr_nl不同而不同,即因创建socket时属性)
    if (bind(*sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
        ALOGE("Unable to bind netlink socket: %s", strerror(errno));
        close(*sock);
        return NULL;
    }
    //NetlinkHandler.start()
    //继承关系
    //NetlinkHandler -> NetlinkListener -> SocketListener -> start()
    NetlinkHandler *handler = new NetlinkHandler(this, *sock, format);
    if (handler->start()) {//*****************handler -> start
        ALOGE("Unable to start NetlinkHandler: %s", strerror(errno));
        close(*sock);
        return NULL;
    }

    return handler;
}

 

期间还经过 socket()创建 socket,setsockopt()设置基本属性、buffer、credentials、bind()函数。最后调用 NetlinkHandler 的 start()方法。期间的继承关系,NetlinkHandler
→NetlinkListener → SocketListener。而 NetlinkListener 中并没有 startListener(),实在SocketListener 中才存在该接口。

 
由此进入了 Socket 公共库中,这部分代码为很多种系统调配用,也提供了很多接口功能,比如Vold 也使用了与 Netd 极为相似的结构。

相关路径:

/system/core/include/sysutils
/system/core/libsysutils/src    

 

int SocketListener::startListener() {

    if (!mSocketName && mSock == -1) {
        SLOGE("Failed to start unbound listener");
        errno = EINVAL;
        return -1;
    } else if (mSocketName) {
        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
            SLOGE("Obtaining file descriptor socket '%s' failed: %s",
                 mSocketName, strerror(errno));
            return -1;

        }
        SLOGV("got mSock = %d for %s", mSock, mSocketName);
    }
	
    if (mListen && listen(mSock, 4) < 0) {	//有链接(tcp)
        SLOGE("Unable to listen on socket (%s)", strerror(errno));
        return -1;
    } else if (!mListen)			//无链接(udp)
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));

    if (pipe(mCtrlPipe)) {			
        SLOGE("pipe failed (%s)", strerror(errno));
        return -1;
    }

    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
        SLOGE("pthread_create (%s)", strerror(errno));
        return -1;
    }

    return 0;
}

int SocketListener::stopListener() {
    char c = 0;
    int  rc;

    rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
    if (rc != 1) {
        SLOGE("Error writing to control pipe (%s)", strerror(errno));
        return -1;
    }

    void *ret;
    if (pthread_join(mThread, &ret)) {
        SLOGE("Error joining to listener thread (%s)", strerror(errno));
        return -1;
    }
    close(mCtrlPipe[0]);
    close(mCtrlPipe[1]);
    mCtrlPipe[0] = -1;
    mCtrlPipe[1] = -1;

    if (mSocketName && mSock > -1) {
        close(mSock);
        mSock = -1;
    }

    SocketClientCollection::iterator it;
    for (it = mClients->begin(); it != mClients->end();) {
        delete (*it);
        it = mClients->erase(it);
    }
    return 0;
}



 

如上调用 startListener(),这里在监听 Kernel 层中,使用的是无链接状态(udp)的 socket 因为该部分 socket 只涉及到单向的通信,而后调用 pthread_create 函数创建新的线程,并将 this 指针传递给它,正式的启动线程监听。

void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);
 //获得上层
 //无关类型转换,获得完全相同的比特位  
    me->runListener();
    pthread_exit(NULL);
    return NULL;
}

 

runListener()才是真正的处理函数,使用了 fd_set 结构,使用了 select 函数,用于判断监听的 kernel 相关部分是否有 event 发出,如果有,则调用 onDataAvailable 函数进行处理(如下)。该函数主要功能是对于 event 进行解码、判断、调用处理函数。该函数在 SocketListener 中为纯虚函数,只是提供了接口,根据具体继承关系、使用 socket 类型(有链接、无链接、socketpair),再做不同的处理,由于现分析是通过 NetlinkListener 进行的调用。

void SocketListener::runListener() {

    SocketClientCollection *pendingList = new SocketClientCollection();

    while(1) {
        SocketClientCollection::iterator it;
        fd_set read_fds; //使用了fd_set
        int rc = 0;
        int max = -1;

        FD_ZERO(&read_fds);
 //mListener用于判断有链接(TCP)or无链接(UDP)
        if (mListen) {
            max = mSock;
            FD_SET(mSock, &read_fds);
        }
 
        FD_SET(mCtrlPipe[0], &read_fds);
        if (mCtrlPipe[0] > max)
            max = mCtrlPipe[0];
 
 //将链接socket压入mClients队列
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            int fd = (*it)->getSocket();
            FD_SET(fd, &read_fds);
            if (fd > max)
                max = fd;
        }
        pthread_mutex_unlock(&mClientsLock);
        SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
 //select函数
 //返回值:fd中为1的bit个数即满足条件的socket个数
        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
            if (errno == EINTR)
                continue;
            SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
            sleep(1);
            continue;  //  < 0 出错
        } else if (!rc)  // == 0 没有可都数据
            continue;
 
 //********有数据************

        if (FD_ISSET(mCtrlPipe[0], &read_fds))
            break;
 
 //TCP并且监听端口状态变可读
        if (mListen && FD_ISSET(mSock, &read_fds)) {
            struct sockaddr addr;
            socklen_t alen;
            int c;

            do {
                alen = sizeof(addr);
                c = accept(mSock, &addr, &alen);//accept函数,阻塞
                SLOGV("%s got %d from accept", mSocketName, c);
            } while (c < 0 && errno == EINTR);
            if (c < 0) {
                SLOGE("accept failed (%s)", strerror(errno));
                sleep(1);
                continue;
            }
  //将链接socket套接字加入mClients
            pthread_mutex_lock(&mClientsLock);
            mClients->push_back(new SocketClient(c, true, mUseCmdNum));
            pthread_mutex_unlock(&mClientsLock);
        }

        /* Add all active clients to the pending list first */
 //全部加入到pending中
        pendingList->clear();
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            int fd = (*it)->getSocket();
            if (FD_ISSET(fd, &read_fds)) {
                pendingList->push_back(*it);
            }
        }
        pthread_mutex_unlock(&mClientsLock);

        /* Process the pending list, since it is owned by the thread,
         * there is no need to lock it */

        while (!pendingList->empty()) {
            /* Pop the first item from the list */
            it = pendingList->begin();
            SocketClient* c = *it;
            pendingList->erase(it);
            /* Process it, if false is returned and our sockets are
             * connection-based, remove and destroy it */

            if (!onDataAvailable(c) && mListen) { //onDataAvailable函数解码成功后
       //在netlinkListener(UDP)或者 
       //frameworkListener中
       //返回TRUE
                /* Remove the client from our array */
                SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
                pthread_mutex_lock(&mClientsLock);
                for (it = mClients->begin(); it != mClients->end(); ++it) {
                    if (*it == c) {
                        mClients->erase(it);  //删除掉本SocketClient因为处理已经完成
                        break;
                    }
                }
                pthread_mutex_unlock(&mClientsLock);
                /* Remove our reference to the client */
  //删除掉它的属性
                c->decRef(); 
            }
        }//end of while(!pendingList->empty())
    }
    delete pendingList;
}


至此从 netd/Netlinkmanager 到公共库中的具体监听socket 的实现,自上而下的监听就算成了,该部分实现了 Kernel 部分与 Netd 的联系的建立。上面调用的 NetlinkListener 中的 onDataAvaliable(如下)。而后在 onDataAvaiable()中,通过调用 NetlinkEvent 中的 decode 方法将受到的 event 按照要求的格式进行解码,解码成功后将调用 onEvent 方法进行处理,这里的 onEvent 函数也是纯虚函数,只做借口具体的实现在,netd/NetlinkHandler.cpp 中。

  NetlinnkListener.onDataAvailable()  /
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
    int socket = cli->getSocket();
    ssize_t count;
    uid_t uid = -1;
	
    count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(      //多播接受
                                       socket, mBuffer, sizeof(mBuffer), &uid));
    if (count < 0) {
        if (uid > 0)
            LOG_EVENT_INT(65537, uid);
        SLOGE("recvmsg failed (%s)", strerror(errno));
        return false;
    }
	//decode解码成功返回true
    NetlinkEvent *evt = new NetlinkEvent();
    if (!evt->decode(mBuffer, count, mFormat)) {
        SLOGE("Error decoding NetlinkEvent");
    } else {
	//纯虚函数
        onEvent(evt);
    }

    delete evt;
    return true;
}


至此,处理流程又回到了 netd 部分(),并且得到了解码成字符串形式的来自 Kernel 的 event,接下来开始在 netd 部分进行处理,并将处理结果提交给 Framework 层。onEvent 函数根据不同的 event 进行选择,调用相应的处理函数如下。

// ************ NetlinkEvent中定义 **************
// const int NetlinkEvent::NlActionUnknown = 0;
// const int NetlinkEvent::NlActionAdd = 1;
// const int NetlinkEvent::NlActionRemove = 2;
// const int NetlinkEvent::NlActionChange = 3;
// const int NetlinkEvent::NlActionLinkUp = 4;
// const int NetlinkEvent::NlActionLinkDown = 5;
// *********************************************
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *subsys = evt->getSubsystem();
if (!subsys) {
ALOGW("No subsystem found in netlink event");
return;
}
//主要处理的是net部分
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);
}

}//end of “net”
else if (!strcmp(subsys, "qlog")) {
const char *alertName = evt->findParam("ALERT_NAME");
const char *iface = evt->findParam("INTERFACE");
notifyQuotaLimitReached(alertName, iface);

} else if (!strcmp(subsys, "xt_idletimer")) {
int action = evt->getAction();
const char *iface = evt->findParam("INTERFACE");
const char *state = evt->findParam("STATE");
if (state)
notifyInterfaceActivity(iface, !strcmp("active", state));

#if !LOG_NDEBUG //uevent 忽略掉了?
//网络管理涉及,黒屏 & 断开/链接 wifi保持连接状态~所以也要捕捉uevent
} 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
}
}

一般从内核发出的 event 都做状态报告,查拔事件等,一般主要目的是向上层发报反馈。如下调用了 mNm 的 getBroadcaster 的 sendBroadcast 方法,该方法即为前文中主函数提到的,nm 将mBroadcaster 用 cl 进行赋值的目的。直接将相应的操作码(ResponseCode 类中全部为操作码)连带消息字符串发送给 Framework 层。此时 cl 应该已经通过 startlistener 方法与 Framework 层建立联系。

  至此,捕捉内核event,并向上层反馈的基本流程就算分析完了,那么kernel-netd-framework的‘一半’我们就算了解了。

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值