Android 4.1 Netd详细分析(四)代码分析2
来源:互联网 发布:kali 访问windows共享 编辑:程序博客网 时间:2024/05/18 02:22
- 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详细分析(四)代码分析2
- Android 4.1 Netd详细分析(四)代码分析2
- Android 4.1 Netd详细分析(三)代码分析1
- Android 4.1 Netd详细分析(五)代码分析3
- Android 4.1 Netd详细分析(三)代码分析1
- Android 4.1 Netd详细分析(五)代码分析3
- Android 4.1 Netd 详细分析系列
- Android Netd详细分析(一)概述
- Android 4.1 Netd详细分析(六)DnsProxyListener
- 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 netd守护进程机制 --- netd分析
- Android中的网络管理源码分析--netd
- Android中的网络管理源码分析--netd
- 在iTerm2中使用Zmodem的方法
- 基于BP神经网络的简单字符识别算法自小结(C语言版)
- Yann LeCun,牛人也!
- ubuntu 安装PHPREDIS
- secureCRT的backspace不可用
- Android 4.1 Netd详细分析(四)代码分析2
- nginx php
- 一个JSP页面导致的tomcat内存溢出
- 黑马程序员-day13-基本数据类型对象包装类
- java与shell脚本互调
- 黑马程序员 java学习笔记(day02)
- 【UITableView】UITableView 编辑
- Memcached常用命令及使用说明
- 深入理解 AngularJS 的 Scope