码迷,mamicode.com
首页 > 移动开发 > 详细

Android—— 4.2 Vold挂载管理_NetlinkManager (四)

时间:2014-08-16 09:44:20      阅读:368      评论:0      收藏:0      [点我收藏+]

标签:netlink   socket   虚函数   uevent   handleblockevent   

  在前文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\n", 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部分大体的功能结构图:

                   bubuko.com,布布扣


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






Android—— 4.2 Vold挂载管理_NetlinkManager (四),布布扣,bubuko.com

Android—— 4.2 Vold挂载管理_NetlinkManager (四)

标签:netlink   socket   虚函数   uevent   handleblockevent   

原文地址:http://blog.csdn.net/jscese/article/details/38586021

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!