在前文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的处理兴许分析!

最新文章

  1. UIScrollView控件实现图片缩放功能
  2. Windows,caffe 仅cpu
  3. HTTP 方法
  4. LA 3708 Graveyard 墓地雕塑 NEERC 2006
  5. ios专题 - objc runtime 动态增加属性
  6. POJ 2553 The Bottom of a Graph (强连通分量)
  7. 改变 font Awesome、Ionic 图标属性
  8. [置顶] spring集成mina 实现消息推送以及转发
  9. @synchronized(self)
  10. [Codeforces 863C]1-2-3
  11. BZOJ_1662_[Usaco2006 Nov]Round Numbers 圆环数_数位DP
  12. HTTP协议11-cookie和seesion
  13. Java 学习使用常见的开源连接池
  14. 通过PHP来 获取文件内容 并且分割字符串 呈现在表格中
  15. 图的遍历(bfs+dfs)模板
  16. .NET 11 个 Visual Studio 代码性能分析工具
  17. django2.0 官方中文文档地址
  18. TOEIC真题学习
  19. nginx 各参数说明
  20. bootstrap datetimepicker 在 angular 项目中的运用

热门文章

  1. vscode Go 1.11.4 编译错误 need Delve built by Go 1.11 or later
  2. 2014年国内最热门的.NET开源平台
  3. 洛谷——P1785 漂亮的绝杀
  4. readis 内部数据结构
  5. Oracle 检查表空间使用情况
  6. 第一次用THINKPHP 报路径错
  7. SQLite创建表并加入数据
  8. css样式大全(整理版)
  9. python函数式编程学习之map,reduce,filter,sorted
  10. Linux学习之十二-Linux文件属性