作者: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;
}
下一篇文章继续分析vold整个源码的走向。。