您的位置:首页 > 移动开发 > Android开发

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

2014-06-23 18:29 369 查看
我们按照main函数代码的执行顺序,首先实例化NetlinkManager。接下来代码如下。

[cpp]
view plaincopy

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*。

[cpp]
view plaincopy

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。

[cpp]
view plaincopy

////////////////// 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 类型。

[cpp]
view plaincopy

//参数说明
// 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






[cpp]
view plaincopy

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 指针传递给它,正式的启动线程监听。

[cpp]
view plaincopy

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 进行的调用。

[cpp]
view plaincopy

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 中。

[cpp]
view plaincopy

//////////////// 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 进行选择,调用相应的处理函数如下。

[cpp]
view plaincopy

// ************ 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的‘一半’我们就算了解了。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: