Android 4.1 Netd詳細分析(四)程式碼分析2

來源:互聯網
上載者:User

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

 

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.