zoukankan      html  css  js  c++  java
  • Android—— 4.2 Vold挂载管理_NetlinkManager (四)

      在前文Android—— 4.2 Vold挂载管理_主体构建main (一)中有结构图表示,Vold是kernel与用户层的一个交互管理模块。

    Android—— 4.2 Vold挂载管理_VolumeManager (三)简介了核心VolumeManager的构建。这篇分析从kernel进程沟通到VolumeManager进程的关键:NetlinkManager


                                                                                       撰写不易。转载请注明出处:http://blog.csdn.net/jscese/article/details/38586021

    一:NetlinkManager构建

    依然从/system/vold/main.cpp中的main中:

        if (!(nm = NetlinkManager::Instance())) {
            SLOGE("Unable to create NetlinkManager");
            exit(1);
        };
    
        ...
    
        if (nm->start()) {
            SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
            exit(1);
        }

    构造函数没干啥。基本的构建由这个 start 函数開始

    /system/vold/NetlinkManager.cpp中:

    int NetlinkManager::start() {
        struct sockaddr_nl nladdr;//使用的 socket 结构 用于与kernel进程通信 
        int sz = 64 * 1024;
        int on = 1;
    
        memset(&nladdr, 0, sizeof(nladdr));// 初始化
        nladdr.nl_family = AF_NETLINK;
        nladdr.nl_pid = getpid();
        nladdr.nl_groups = 0xffffffff;
    
        if ((mSock = socket(PF_NETLINK,//创建 类型为 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 SO_RECBUFFORCE option: %s", strerror(errno));
            return -1;
        }
    
        if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
            SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
            return -1;
        }
    
        if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {//绑定socket地址
            SLOGE("Unable to bind uevent socket: %s", strerror(errno));
            return -1;
        }
    
        mHandler = new NetlinkHandler(mSock);//传入创建的socket的标识构造一个NetlinkHandler实例
        if (mHandler->start()) {//开启socket监控
            SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
            return -1;
        }
        return 0;
    }

    这里使用的是Netlink套接字。Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最经常使用的接口。结构定义:

    struct sockaddr_nl {
    	__kernel_sa_family_t	nl_family;	/* AF_NETLINK	*/
    	unsigned short	nl_pad;		/* zero		*/
    	__u32		nl_pid;		/* port ID	*/
           	__u32		nl_groups;	/* multicast groups mask */
    };

    看NetlinkHandler的构造:

    NetlinkHandler::NetlinkHandler(int listenerSocket) :
                    NetlinkListener(listenerSocket) {
    }

    跟着父类:

    NetlinkListener::NetlinkListener(int socket) :
                                SocketListener(socket, false) {
        mFormat = NETLINK_FORMAT_ASCII;
    }

    这里又是构造了一个SockListener的实例,传入了上面创建的socket标识。

    接着调用的start()函数,也是终于实如今SockListener的startListener()。

    继承关系:NetlinkHandler——>NetlinkListener——>SocketListener

    关于构造SockListener以及startListener()函数开启socket监听的实现流程在前文Android—— 4.2 Vold挂载管理_CommandListener (二)中已分析,

    差别在于socket不同。并且不是正常监听的socket,这里的mListen为false,CommandListener的为true。不再做分析!


    二:NetlinkManager实现:

    当监听到了socket事件的时候,同CommandListener一样,调用当时SocketListener实例的虚函数onDataAvailable的子类中的实现

    这里是system/core/libsysutils/src/NetlinkListener.cpp中:

    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));//从socket中抽取出event的buffer
        if (count < 0) {
            if (uid > 0)
                LOG_EVENT_INT(65537, uid);
            SLOGE("recvmsg failed (%s)", strerror(errno));
            return false;
        }
    
        NetlinkEvent *evt = new NetlinkEvent();
        if (!evt->decode(mBuffer, count, mFormat)) {//交给NetlinkEent 实例解析buffer,保存參数
            SLOGE("Error decoding NetlinkEvent");
        } else {
            onEvent(evt);//虚函数~传递evt给子类NetlinkHandler实现
        }
    
        delete evt;
        return true;
    }

    到NetlinkHandler.cpp中:

    void NetlinkHandler::onEvent(NetlinkEvent *evt) {
        VolumeManager *vm = VolumeManager::Instance();
        const char *subsys = evt->getSubsystem();
    
        if (!subsys) {
            SLOGW("No subsystem found in netlink event");
            return;
        }
    
        if (!strcmp(subsys, "block")) {
            vm->handleBlockEvent(evt);//把event事件交给VolumeManager
        }
    }

    这里真正传递到了VolumeManager中,实现了从kernel到vold,看下VolumeManager的handle处理:

    void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
        const char *devpath = evt->findParam("DEVPATH");
    
        /* Lookup a volume to handle this device */
        VolumeCollection::iterator it;
        bool hit = false;
        for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {//遍历容器中的Volume 实例依次传入event
            if (!(*it)->handleBlockEvent(evt)) {//Volume类的虚函数。子类DirectVolume实现
    #ifdef NETLINK_DEBUG
                SLOGD("Device '%s' event handled by volume %s
    ", devpath, (*it)->getLabel());
    #endif
                hit = true;
                break;
            }
        }
    
        if (!hit) {
    #ifdef NETLINK_DEBUG
            SLOGW("No volumes handled block event for '%s'", devpath);
    #endif
        }
    }

    能够看到这里用到了Android—— 4.2 Vold挂载管理_VolumeManager (三)中解析出来增加进Volume容器中的Volume。

    画了一张NetlinkManager部分大体的功能结构图:

                      


    整个NetlinkManager部分的实现大体就是这样,至于kernel层假设检測到存储设备的热插拔发出uevent的以及Volume的处理兴许分析!






  • 相关阅读:
    【LeetCode-位运算】汉明距离总和
    python类的继承和重写
    单元测试unittest使用说明
    Java学习90
    Java学习89
    Java学习88
    Java学习87
    Java学习86
    Java学习85
    Java学习84
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/6834480.html
Copyright © 2011-2022 走看看