在前文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 (四)的更多相关文章

  1. android中退出当前应用程序的四种方法

    android中退出当前应用程序的四种方法 [IT168 技术]Android程序有很多Activity,比如说主窗口A,调用了子窗口B,如果在B中直接finish(), 接下里显示的是A.在B中如何 ...

  2. Linux 挂载管理(mount)

    标签:mount,umount 概述 在上一章增加linux操作系统空间中已经使用过了mount命令对分区进行挂载,这一章详细介绍挂载管理,该命令涉及的知识点也挺多的而且也还比较重要,是需要掌握的一个 ...

  3. android的Log日志打印管理工具类(一)

    android的Log日志的打印管理工具类: package com.gzcivil.utils; import android.util.Log; /** * 日志打印管理 * * @author ...

  4. 使用Visual Studio Team Services敏捷规划和项目组合管理(四)——冲刺计划和任务板

    使用Visual Studio Team Services敏捷规划和项目组合管理(四)--冲刺计划和任务板 团队在sprint计划会议期间创建冲刺积压工作项,通常在冲刺的第一天召开该会议.每个冲刺都对 ...

  5. Spring事务管理的四种方式(以银行转账为例)

    Spring事务管理的四种方式(以银行转账为例) 一.事务的作用 将若干的数据库操作作为一个整体控制,一起成功或一起失败.   原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不 ...

  6. Android 仿今日头条频道管理(下)(GridView之间Item的移动和拖拽)

    前言 上篇博客我们说到了今日头条频道管理的操作交互体验,我也介绍了2个GridView之间Item的相互移动.详情请參考:Android 仿今日头条频道管理(上)(GridView之间Item的移动和 ...

  7. Android UI组件:布局管理器

    为了更好的管理Android应用的用户界面中的组件,Android提供了布局管理器.通过使用布局管理器,Android应用的图形用户界面具有良好的平台无关性.通常,推荐使用布局管理器来管理组件的分布. ...

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

    转自:http://www.cnblogs.com/dubo-/p/6018262.html Android 6.0 - 动态权限管理的解决方案   转载请标注 Android 6.0版本(Api 2 ...

  9. android中常用的布局管理器(二)

    接上篇博客 (3)LinearLayout     线性布局管理器 线性布局管理器是将放入其中的组件按照垂直或水平方向来布局,每一行或每一列只能放一个组件,并且不会换行,当组件排列到窗体的边缘后,后面 ...

随机推荐

  1. C 语言 和 python 调用 .so 文件

    什么是静态库和动态库, 看一篇博客 http://www.cnblogs.com/skynet/p/3372855.html 现在,我们首先生成.so文件 首先, 我们写一个a.c文件 1 2 3 4 ...

  2. LeetCode OJ-- Recover Binary Search Tree ***@

    https://oj.leetcode.com/problems/recover-binary-search-tree/ 一棵二叉搜索树,二叉搜索树的特征是,中根遍历的话,得到的序列是递增的 题目中, ...

  3. LeetCode OJ-- 3Sum **

    https://oj.leetcode.com/problems/3sum/ 在一个数列中,求出所有3个数之和是0的3个数. 刚开始给自己挖了坑,由于没闹清,unique()函数的含义,去掉重复不彻底 ...

  4. Jquery 返回json数据在IE浏览器中提示下载的问题

    Jquery 返回json数据,IE浏览器提示下载的问题,当提交完数据后返回的本来是json数据的,在火弧里测试正常,解决方法如下 今天遇到Jquery 返回json数据,IE浏览器提示下载的问题,当 ...

  5. Topcoder SRM 666 DIV 1

    WalkOverATree 题意:给你一棵树,有个人在节点0,现在问你,这个人走L步,最多能访问多少个不同的节点,一个节点可以被走多次,但只算一次. 题解:这个问题的关键在于,每个点最多走两次,这是因 ...

  6. mac python 切换系统默认版本

    1 找到所安装python路径/usr/local/Cellar/python/2.7.13/bin2 vim ~/.bash_profile 3 添加如下代码: PATH="/usr/lo ...

  7. TypeError at /post/ render_to_response() got an unexpected keyword argument 'context_instance'

    Exception Type: TypeError at /post/ Exception Value: render_to_response() got an unexpected keyword ...

  8. 某音乐类App评论相关API的分析及SQL注入尝试

    关键字:APIfen.工具使用.sql注入 涉及工具/包:Fiddler.Burpsuite.Js2Py.Closure Compiler.selenium.phantomjs.sqlmap 摘要: ...

  9. 黑苹果+win10双系统折腾笔记

    寒假趁机在家折腾一下黑苹果 笔记本配置:神船K610D I7 4600 ,其他配置思路一样,驱动要自己找 镜像和工具:OS X Yosemite 10.10.3 镜像 WIN10 TLSB 2016 ...

  10. 鼠标点击input框后里面的内容就消失

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...