個人郵箱: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的‘一半’我們就算瞭解了。