作者:gzshun. 原創作品,轉載請標明出處!
NetlinkManager類負責管理捕獲核心的uevent事件,這裡使用了Netlink通訊端。
Netlink的概念:
Netlink通訊端是用以實現使用者進程與核心進程通訊的一種特殊的處理序間通訊(IPC) ,也是網路應用程式與核心通訊的最常用的介面。Netlink通訊端可以使用標準的通訊端APIs來建立。socket(), bind(), sendmsg(), recvmsg() 和 close()很容易地應用到 netlink
socket。netlink包含於標頭檔linux/netlink.h中。
平時的應用程式層一般都不會用到Netlink這個通訊端,瞭解就行。
在Main.cpp檔案中的main函數裡面,有一個準備工作是用來開啟監聽核心uevent事件的線程,源碼如下:
if (nm->start()) { SLOGE("Unable to start NetlinkManager (%s)", strerror(errno)); exit(1); }
nm是NetlinkManager類執行個體化的一個對象,以下是start()函數的源碼:
/********************************************************************************** **file:system/vold/NetlinkManager.cpp **以下一些socket的初始化,跟linux的應用程式層的tcp/udp使用差不多。 **********************************************************************************/ int NetlinkManager::start() { struct sockaddr_nl nladdr; int sz = 64 * 1024; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = getpid(); nladdr.nl_groups = 0xffffffff; if ((mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) { SLOGE("Unable to create uevent socket: %s", strerror(errno)); return -1; } if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) { SLOGE("Unable to set uevent socket options: %s", strerror(errno)); return -1; } if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { SLOGE("Unable to bind uevent socket: %s", strerror(errno)); return -1; } /********************************************************************************** **這裡先說明NetlinkHandler類的繼承關係: **NetlinkHandler --> NetlinkListener --> SocketListener(父類) **NetlinkHandler類的start()函數調用了SocketListener::startListener()函數,源碼如下。 **********************************************************************************/ mHandler = new NetlinkHandler(mSock); if (mHandler->start()) { SLOGE("Unable to start NetlinkHandler: %s", strerror(errno)); return -1; } return 0; } /********************************************************************************** **file:system/vold/NetlinkHandler.cpp **該函數使用this指標調用自身的startListener函數,可以發現,在NetlinkHandler沒有 **startListener()這個函數,這函數是它的父類的函數SocketListener::startListener; **********************************************************************************/ int NetlinkHandler::start() { return this->startListener(); } /********************************************************************************** **file:system/core/libsysutils/src/SocketListener.cpp **以下這個函數就涉及到其他方面的內容了,不在vold部分。 **********************************************************************************/ 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; } } if (mListen && listen(mSock, 4) < 0) { SLOGE("Unable to listen on socket (%s)", strerror(errno)); return -1; } else if (!mListen) mClients->push_back(new SocketClient(mSock)); 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; } /********************************************************************************** **該線程函數在類裡面聲明為靜態函數:static void *threadStart(void *obj); **所以不能調用this指標來指向自身的函數,所以通過pthread_create線程的建立函數來傳遞 **一個參數,將this指標傳遞給它; **這裡使用reinterpret_cast運算子是用來處理無關類型之間的轉換, **它會產生一個新的值,這個值會有與原始參數(expressoin)有完全相同的位元位。 **********************************************************************************/ void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj); me->runListener(); pthread_exit(NULL); return NULL; } /********************************************************************************** **該函數才是真正的處理函數了,使用select集合,結合fd_set結構體,可以判斷通訊端有無 **資訊可讀,如果沒有,立即返回,不阻塞; **還使用了管道,僅僅判斷該通訊端的讀端是否有資料可讀。 **********************************************************************************/ void SocketListener::runListener() { while(1) { SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; int max = 0; FD_ZERO(&read_fds); if (mListen) { max = mSock; FD_SET(mSock, &read_fds); } FD_SET(mCtrlPipe[0], &read_fds); if (mCtrlPipe[0] > max) max = mCtrlPipe[0]; pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { FD_SET((*it)->getSocket(), &read_fds); if ((*it)->getSocket() > max) max = (*it)->getSocket(); } pthread_mutex_unlock(&mClientsLock); if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { SLOGE("select failed (%s)", strerror(errno)); sleep(1); continue; } else if (!rc) continue; if (FD_ISSET(mCtrlPipe[0], &read_fds)) break; if (mListen && FD_ISSET(mSock, &read_fds)) { struct sockaddr addr; socklen_t alen = sizeof(addr); int c; if ((c = accept(mSock, &addr, &alen)) < 0) { SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; } pthread_mutex_lock(&mClientsLock); mClients->push_back(new SocketClient(c)); pthread_mutex_unlock(&mClientsLock); } do { pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { int fd = (*it)->getSocket(); if (FD_ISSET(fd, &read_fds)) { pthread_mutex_unlock(&mClientsLock); /********************************************************************************** **onDataAvailable是SocketListener類聲明的一個純虛函數,在其子類NetlinkListener實現 **onDataAvailable函數,函數裡面調用了NetlinkHandler類的onEvent函數,該函數是 **在NetlinkListener類中定義的純虛函數,在vold中的NetlinkHandler類中實現。 **********************************************************************************/ if (!onDataAvailable(*it)) { close(fd); pthread_mutex_lock(&mClientsLock); delete *it; it = mClients->erase(it); pthread_mutex_unlock(&mClientsLock); } FD_CLR(fd, &read_fds); continue; } } pthread_mutex_unlock(&mClientsLock); } while (0); } } /********************************************************************************** **file:system/core/libsysutils/src/NetlinkListener.cpp **該函數用來處理核心的uevent事件,然後調用onEvent函數,讓onEvent函數去捕獲這些事件 **的資訊。 **********************************************************************************/ bool NetlinkListener::onDataAvailable(SocketClient *cli) { int socket = cli->getSocket(); int count; if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) { SLOGE("recv failed (%s)", strerror(errno)); return false; } NetlinkEvent *evt = new NetlinkEvent(); if (!evt->decode(mBuffer, count)) { SLOGE("Error decoding NetlinkEvent"); goto out; } /*下一篇文章介紹該函數*/ onEvent(evt); out: delete evt; return true; }