Android 4.1 Netd详细分析(四)代码分析2
2012-11-09 18:01
615 查看
个人邮箱:xiaokeweng@gmail.com
我们按照main函数代码的执行顺序,首先实例化NetlinkManager。接下来代码如下。
首先进行 NetlinkManager 的实例化。从 NetlinkManager.cpp 中可以查看到实例化的内容如下 ,其中 mBroadcaster 的类型是 SocketListener*。
接下来实例化 CommandListener 并将 nm 的 setBroadcaster 进行赋值,通过这个步骤操作,可以使 nm 调用到 cl 的 socket 进行广播,意义是将 nm 的处理结果通过内部广播提交给Framework,在后面将详细介绍。
而后 nm 调用了它的 start()方法,如下。 函数创建了三个监听线程,根据 setupSocket 参数的不同可以限定监听socket 的监听的内核模块事件,并分别start。
如下式setupSocket()函数,创建socket,设置属性,并start线程开始监听,函数的返回值为 Netlinkhandler 类型。
期间还经过 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
如上调用 startListener(),这里在监听 Kernel 层中,使用的是无链接状态(udp)的 socket 因为该部分 socket 只涉及到单向的通信,而后调用 pthread_create 函数创建新的线程,并将 this 指针传递给它,正式的启动线程监听。
runListener()才是真正的处理函数,使用了 fd_set 结构,使用了 select 函数,用于判断监听的 kernel 相关部分是否有 event 发出,如果有,则调用 onDataAvailable 函数进行处理(如下)。该函数主要功能是对于 event 进行解码、判断、调用处理函数。该函数在 SocketListener 中为纯虚函数,只是提供了接口,根据具体继承关系、使用
socket 类型(有链接、无链接、socketpair),再做不同的处理,由于现分析是通过 NetlinkListener 进行的调用。
至此从 netd/Netlinkmanager 到公共库中的具体监听socket 的实现,自上而下的监听就算成了,该部分实现了 Kernel 部分与 Netd 的联系的建立。上面调用的 NetlinkListener 中的 onDataAvaliable(如下)。而后在 onDataAvaiable()中,通过调用 NetlinkEvent 中的 decode
方法将受到的 event 按照要求的格式进行解码,解码成功后将调用 onEvent 方法进行处理,这里的 onEvent 函数也是纯虚函数,只做借口具体的实现在,netd/NetlinkHandler.cpp 中。
至此,处理流程又回到了 netd 部分(),并且得到了解码成字符串形式的来自 Kernel 的 event,接下来开始在 netd 部分进行处理,并将处理结果提交给 Framework 层。onEvent 函数根据不同的 event 进行选择,调用相应的处理函数如下。
一般从内核发出的 event 都做状态报告,查拔事件等,一般主要目的是向上层发报反馈。如下调用了 mNm 的 getBroadcaster 的 sendBroadcast 方法,该方法即为前文中主函数提到的,nm 将mBroadcaster 用 cl 进行赋值的目的。直接将相应的操作码(ResponseCode 类中全部为操作码)连带消息字符串发送给 Framework 层。此时 cl 应该已经通过
startlistener 方法与 Framework 层建立联系。
至此,捕捉内核event,并向上层反馈的基本流程就算分析完了,那么kernel-netd-framework的‘一半’我们就算了解了。
我们按照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的‘一半’我们就算了解了。
相关文章推荐
- Android 4.1 Netd详细分析(五)代码分析3
- Android 4.1 Netd详细分析(三)代码分析1
- Android 4.1 Netd详细分析(三)代码分析1
- Android 4.1 Netd详细分析(四)代码分析2
- Android 4.1 Netd详细分析(五)代码分析3
- Android 4.1 Netd详细分析(六)DnsProxyListener
- Android 4.1 Netd 详细分析系列
- Android 4.1 Netd详细分析(六)DnsProxyListener
- Android 4.1 Netd详细分析(一)概述与应用实例
- Android 4.1 Netd详细分析(二)源文件/模块/基础类统领
- Android 4.1 Netd详细分析(一)概述与应用实例
- Android 4.1 Netd详细分析(二)源文件/模块/基础类统领
- Android 4.1 Netd详细分析(一)概述与应用实例
- android待机详细结合代码分析(二)
- android通话过程RIL层详细分析(代码)
- 关于Android大数据收集,埋点统计的详细讲解以及案例代码分析附github代码
- android待机详细结合代码分析(一)
- android待机详细结合代码分析(二)
- Android Netd详细分析(一)概述
- android通话过程RIL层详细分析(代码)