在前文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. 測試 電池溫度的 batch file

    無限迴圈, 執行讀取 電池溫度, @echo off adb root :loop echo %date% %time% adb shell "cat /sys/class/power_su ...

  2. java 仓库maven

    工具: apache-maven-3.2.3.zip maven_data.zip 在java Window->Preferences->Maven中 Installations中添加ap ...

  3. 使用springboot 2.0后,静态资源默认路径无法访问

    原因在于:META-INF/resources / resources / static / public 都是spring boot 认为静态资源应该放置的位置,会自动去寻找静态资源 然而,在2.0 ...

  4. php设置报错级别

    ini_set("display_errors", "On");//若页面不报错的话,请设置php.ini 的display_errors 为 On error ...

  5. ArcObject开发,“异常在 ESRI.ArcGIS.Version.dll”错误

    “System.DllNotFoundException”类型的未经处理的异常在 ESRI.ArcGIS.Version.dll 中发生 其他信息: 无法加载 DLL“ArcGISVersion.dl ...

  6. doviceone- http组件进行webservice的POST请求

    var http = mm("do_Http"); http.method = "POST"; // GET | POST http.timeout = 100 ...

  7. DEDECMS图片集上传图片出错302的解决办法

    无忧主机(www.51php.com)小编今天在调试dede网站的时候发现了一个问题,因为小编想在网站上增加一个图片集的栏目,于是就到后台图片集栏目去添加内容,谁知在上传图片的时候给我弹出个错误信息框 ...

  8. struts2.16中文乱码问题解决

    方法1.在struts.xml文件中添加<constant name="struts.i18n.encoding" value="GBK" /> 方 ...

  9. CF - 420B - Online Meeting(思维)

    题意:n 个人參加线上会议.某经理记录了中间一段时间的 m 条上下线记录(1 ≤ n, m ≤ 105).+ 表示上线,- 表示下线. leader是指仅仅要有人在线,他都在线的人.求全部可能的lea ...

  10. mysql数据库管理工具(navicat for mysql)

    Navicat Premium 是一个可多重连接的数据库管理工具,它可让你以单一程序同时连接到 MySQL.Oracle.PostgreSQL.SQLite 及 SQL Server 数据库,让管理不 ...