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\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部分大体的功能结构图:

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

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

时间: 2024-10-14 09:04:44

Android—— 4.2 Vold挂载管理_NetlinkManager (四)的相关文章

Android—— 4.2 Vold挂载管理_Kernel_USB_Uevent (七)

在前文Android-- 4.2 Vold挂载管理_NetlinkManager (四)中有解析到Vold 是从kernel中获取uevent事件,来获取device信息,其中是通过一个Netlink的套接字,目前整个Vold机制也分析完了, 上篇 Android-- 4.2 Vold挂载管理_MountService (六) 分析了机制中最上层的,这里分析一下最下层的kernel uevent事件的发送,以USB设备为例! 撰写不易,转载请注明出处:http://blog.csdn.net/j

Android—— 4.2 Vold挂载管理_mmcblk内置-双sdcard (八)

Vold的学习过了一段时间了,才想着把mmcblock内置成sdcard的方法记录一下. 当初就是因为要做这个功能才去学习Vold机制,贴出之前的博客: Android-- 4.2 Vold挂载管理_主体构建main (一) Android-- 4.2 Vold挂载管理_CommandListener (二) Android-- 4.2 Vold挂载管理_VolumeManager (三) Android-- 4.2 Vold挂载管理_NetlinkManager (四) Android-- 4

Android—— 4.2 Vold挂载管理_DirectVolume/Volume (五)

在前文Android-- 4.2 Vold挂载管理_VolumeManager (三) 中解析了VolumeManager是怎么样抽取Volume实例以及DirectVolume与Volume之间的关系,在上篇Android-- 4.2 Vold挂载管理_NetlinkManager (四)中从kernel开始调用到handleBlockEvent,这里解析一下Vold挂载的真正操作,也就是Volume的操作! 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/a

Android—— 4.2 Vold挂载管理_MountService (六)

整个Vold机制应该算system层,与framwork层的交互在Android-- 4.2 Vold挂载管理_CommandListener (二)中有提到过,是通过一个"vold"的socket进行通信的,这里分析一下framework中负责与Vold通信的:MountService 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/38978387 一.MountService启动: 在/frameworks/bas

Android—— 4.2 Vold挂载管理_CommandListener (二)

在前一篇博客中介绍了个大体结构 Android-- 4.2 Vold挂载管理_主体构建 (一),按照代码的顺序结构来依次分析,这里来看看CommandListener这个类做了什么. 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/38434263 一:CommandListener构造 在/system/vold/main.cpp的main函数中构建实例: cl = new CommandListener(); vm->setB

Android—— 4.2 Vold挂载管理_VolumeManager (三)

在Android-- 4.2 Vold挂载管理_主体构建main (一)中分析了大体的框架,这里分析一下核心VolumeManager,再次补上结构框架图如下: 可以看到VolumeManager就是整个Android 磁盘挂载Vold机制的核心调度,上下连接的中转站! 我从Vold main代码的顺序结构来一次分析,上一篇Android-- 4.2 Vold挂载管理_CommandListener (二)  中分析了与framework层交互的CommandListener的功能作用. 这里分

linux之磁盘管理(四)

文件系统管理 重新创建文件系统会损坏原有文件. 创建某个分区上的文件系统 使用 mkfs :make file system -t  FSTYPE   指定文件系统类型 mkfs命令比较特殊 [[email protected] ~]# which mkfs.ext2 /sbin/mkfs.ext2 [[email protected] ~]# ls -l /sbin/mkfs.ext2 -rwxr-xr-x 3 root root 47312 Sep  4  2009 /sbin/mkfs.e

从零开始学android&lt;android事件的处理方式.二十四.&gt;

在android中一共有 多种事件,每种事件都有自己相对应的处理机制 如以下几种 1 单击事件 View.OnClickListener public abstract void onClick (View v) 单击组件时触发 2 单击事件 View.OnLongClickListener public abstract boolean onLongClick (View v) 长按组件时触发 3 键盘事件 View.OnKeyListener public abstract boolean

Android 6.0 - 动态权限管理的解决方案(转)

转自:http://www.cnblogs.com/dubo-/p/6018262.html Android 6.0 - 动态权限管理的解决方案 转载请标注 Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用户体验, 同时也为程序员带来新的负担. 动态权限管理就是这样, 一方面让用户更加容易的控制自己的隐私, 一方面需要重新适配应用权限. 时代总是不断发展, 程序总是以人为本, 让我们为应用添加动态权限管理吧! 这里提供了一个非常不错的解决方案, 提供源码, 项目可以直