android usb挂载分析---vold处理内核消息
MountService启动之后 ,一切准备工作都 做好了,就等待碰上u盘插上了,
这里要讲的是内核发信息给vold,我们在 vold启动这篇曾讲到过注册了一个到内核的UEVENT事件,当有u盘插入的时候,我们就能从这个套接字上收到内核所发出的消息了,这样就开始了vold的消息处理。
先看下消息处理的流程:

在SocketListener::runListener()函数 中,我们一直在select,等待某个连接的到来或者已经的套接字上数据的到来,看下代码:
- if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
 - SLOGE("select failed (%s)", strerror(errno));
 - sleep(1);
 - continue;
 - } else if (!rc)
 - continue;
 - if (FD_ISSET(mCtrlPipe[0], &read_fds))
 - break;
 - if (mListen && FD_ISSET(mSock, &read_fds)) {
 - struct sockaddr addr;
 - socklen_t alen = sizeof(addr);
 - int c;
 - if ((c = accept(mSock, &addr, &alen)) < 0) {
 - SLOGE("accept failed (%s)", strerror(errno));
 - sleep(1);
 - continue;
 - }
 - pthread_mutex_lock(&mClientsLock);
 - mClients->push_back(new SocketClient(c));
 - pthread_mutex_unlock(&mClientsLock);
 - }
 - do {
 - pthread_mutex_lock(&mClientsLock);
 - for (it = mClients->begin(); it != mClients->end(); ++it) {
 - int fd = (*it)->getSocket();
 - if (FD_ISSET(fd, &read_fds)) {
 - pthread_mutex_unlock(&mClientsLock);
 - if (!onDataAvailable(*it)) {
 - close(fd);
 - pthread_mutex_lock(&mClientsLock);
 - delete *it;
 - it = mClients->erase(it);
 - pthread_mutex_unlock(&mClientsLock);
 - }
 - FD_CLR(fd, &read_fds);
 - pthread_mutex_lock(&mClientsLock);
 - continue;
 - }
 - }
 - pthread_mutex_unlock(&mClientsLock);
 - } while (0);
 - }
 
当某个套接字上有数据到来时,首先看这个套接字是不是listen的那个套接字,如果是则接收 连接并加到mClients链表中,否则说明某个套接字上有数据到来,这时里是我们注册到内核的那个套接字,调用onDataAvailable函数,这里由于多态调用的是NetlinkListener::onDataAvailable中的这个函数:
- bool NetlinkListener::onDataAvailable(SocketClient *cli)
 - {
 - int socket = cli->getSocket();
 - int count;
 - if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) {
 - SLOGE("recv failed (%s)", strerror(errno));
 - return false;
 - }
 - NetlinkEvent *evt = new NetlinkEvent();
 - if (!evt->decode(mBuffer, count)) {
 - SLOGE("Error decoding NetlinkEvent");
 - goto out;
 - }
 - onEvent(evt);
 - out:
 - delete evt;
 - return true;
 - }
 
调用recv接收数据,接着new一个NetlinkEvent并调用它的 decode函数对收到的数据进行解析:
- bool NetlinkEvent::decode(char *buffer, int size) {
 - char *s = buffer;
 - char *end;
 - int param_idx = 0;
 - int i;
 - int first = 1;
 - end = s + size;
 - while (s < end) {
 - if (first) {
 - char *p;
 - for (p = s; *p != '@'; p++);
 - p++;
 - mPath = strdup(p);
 - first = 0;
 - } else {
 - if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
 - char *a = s + strlen("ACTION=");
 - if (!strcmp(a, "add"))
 - mAction = NlActionAdd;
 - else if (!strcmp(a, "remove"))
 - mAction = NlActionRemove;
 - else if (!strcmp(a, "change"))
 - mAction = NlActionChange;
 - } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
 - mSeq = atoi(s + strlen("SEQNUM="));
 - else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
 - mSubsystem = strdup(s + strlen("SUBSYSTEM="));
 - else
 - mParams[param_idx++] = strdup(s);
 - }
 - s+= strlen(s) + 1;
 - }
 - return true;
 - }
 
这里会对消息进行解析,解析出ACTION、DEVPATH、SUBSYSTEM等等,下面看一下我抓的 一个u盘插入抓的log:
- D/NetlinkEvent( 946): s = add@/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host1/target1:0:0/1:0:0:0/block/sda
 - D/NetlinkEvent( 946): s = ACTION=add
 - D/NetlinkEvent( 946): s = DEVPATH=/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host1/target1:0:0/1:0:0:0/block/sda
 - D/NetlinkEvent( 946): s = SUBSYSTEM=block
 - D/NetlinkEvent( 946): s = MAJOR=8
 - D/NetlinkEvent( 946): s = MINOR=0
 - D/NetlinkEvent( 946): s = DEVNAME=sda
 - D/NetlinkEvent( 946): s = DEVTYPE=disk
 - D/NetlinkEvent( 946): s = NPARTS=1
 - D/NetlinkEvent( 946): s = SEQNUM=1058
 - D/NetlinkEvent( 1206): s = DEVPATH=/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host1/target1:0:0/1:0:0:0/block/sda/sda1
 - D/NetlinkEvent( 1206): s = SUBSYSTEM=block
 - D/NetlinkEvent( 1206): s = MAJOR=8
 - D/NetlinkEvent( 1206): s = MINOR=1
 - D/NetlinkEvent( 1206): s = DEVNAME=sda1
 - D/NetlinkEvent( 1206): s = DEVTYPE=partition
 - D/NetlinkEvent( 1206): s = PARTN=1
 - D/NetlinkEvent( 1206): s = SEQNUM=1059
 
这个u盘只有一个分区,下面是有两个分区的log(一部分):
- D/NetlinkEvent( 1207): s = ACTION=add
 - D/NetlinkEvent( 1207): s = DEVPATH=/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host2/target2:0:0/2:0:0:0/block/sdb
 - D/NetlinkEvent( 1207): s = SUBSYSTEM=block
 - D/NetlinkEvent( 1207): s = MAJOR=8
 - D/NetlinkEvent( 1207): s = MINOR=16
 - D/NetlinkEvent( 1207): s = DEVNAME=sdb
 - D/NetlinkEvent( 1207): s = DEVTYPE=disk
 - D/NetlinkEvent( 1207): s = NPARTS=2
 - D/NetlinkEvent( 1207): s = SEQNUM=1086
 
可以看到,从内核收到的消息中我们能获得很多的信息。
解析完后,就调用onEvent函数对消息进行处理,这里调用的是NetlinkHandler的onEvent函数:
- 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);
 - } else if (!strcmp(subsys, "switch")) {
 - vm->handleSwitchEvent(evt);
 - } else if (!strcmp(subsys, "usb_composite")) {
 - vm->handleUsbCompositeEvent(evt);
 - } else if (!strcmp(subsys, "battery")) {
 - } else if (!strcmp(subsys, "power_supply")) {
 - }
 - }
 
从上面 的log可以看出这里获取的subsys是block,所以调用handleBlockEvent函数
- 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) {
 - if (!(*it)->handleBlockEvent(evt)) {
 - #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
 - }
 - }
 
mVolumes中我们在初始化的时候往里面add了 个DirectVolume,所以这里调用DirectVolume::handleBlockEvent
- int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
 - const char *dp = evt->findParam("DEVPATH");
 - PathCollection::iterator it;
 - for (it = mPaths->begin(); it != mPaths->end(); ++it) {
 - if (!strncmp(dp, *it, strlen(*it))) {
 - /* We can handle this disk */
 - int action = evt->getAction();
 - const char *devtype = evt->findParam("DEVTYPE");
 - if (action == NetlinkEvent::NlActionAdd) {
 - int major = atoi(evt->findParam("MAJOR"));
 - int minor = atoi(evt->findParam("MINOR"));
 - char nodepath[255];
 - snprintf(nodepath,
 - sizeof(nodepath), "/dev/block/vold/%d:%d",
 - major, minor);
 - if (createDeviceNode(nodepath, major, minor)) {
 - SLOGE("Error making device node '%s' (%s)", nodepath,
 - strerror(errno));
 - }
 - if (!strcmp(devtype, "disk")) {
 - handleDiskAdded(dp, evt);
 - } else {
 - handlePartitionAdded(dp, evt);
 - }
 - } else if (action == NetlinkEvent::NlActionRemove) {
 - if (!strcmp(devtype, "disk")) {
 - handleDiskRemoved(dp, evt);
 - } else {
 - handlePartitionRemoved(dp, evt);
 - }
 - } else if (action == NetlinkEvent::NlActionChange) {
 - if (!strcmp(devtype, "disk")) {
 - handleDiskChanged(dp, evt);
 - } else {
 - handlePartitionChanged(dp, evt);
 - }
 - } else {
 - SLOGW("Ignoring non add/remove/change event");
 - }
 - return 0;
 - }
 - }
 - errno = ENODEV;
 - return -1;
 - }
 
mPaths我们在parse vold.fstab把相应的解析到的路径添加进去了,我们看下这个脚本:
- ev_mount sdcard /mnt/sdcard auto /devices/platform/hiusb-ehci.0 /devices/platform/hi_godbox-ehci.0
 
这里add的路径正好和上面 log打出来的路径相匹配,首先执行的handleDiskAdded,也就是在收到这样的消息的时候,提示有磁盘插入:
- void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {
 - mDiskMajor = atoi(evt->findParam("MAJOR"));
 - mDiskMinor = atoi(evt->findParam("MINOR"));
 - const char *tmp = evt->findParam("NPARTS");
 - if (tmp) {
 - mDiskNumParts = atoi(tmp);
 - } else {
 - SLOGW("Kernel block uevent missing 'NPARTS'");
 - mDiskNumParts = 1;
 - }
 - char msg[255];
 - int partmask = 0;
 - int i;
 - for (i = 1; i <= mDiskNumParts; i++) {
 - partmask |= (1 << i);
 - }
 - mPendingPartMap = partmask;
 - if (mDiskNumParts == 0) {
 - #ifdef PARTITION_DEBUG
 - SLOGD("Dv::diskIns - No partitions - good to go son!");
 - #endif
 - setState(Volume::State_Idle);
 - } else {
 - #ifdef PARTITION_DEBUG
 - SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)",
 - mDiskNumParts, mPendingPartMap);
 - #endif
 - setState(Volume::State_Pending);
 - }
 - snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
 - getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
 - mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
 - msg, false);
 - }
 
mDiskNumParts 不为0,将Volume的状态设置为State_Pending并向FrameWork层广播VolumeDiskInserted的消息,在setState函数中也会广播VolumeStateChange的消息给上层,接着就是handlePartitionAdded 这里是处理add /block/sda/sda*这样的消息的
- void DirectVolume::handlePartitionAdded(const char *devpath, NetlinkEvent *evt) {
 - int major = atoi(evt->findParam("MAJOR"));
 - int minor = atoi(evt->findParam("MINOR"));
 - int part_num;
 - const char *tmp = evt->findParam("PARTN");
 - if (tmp) {
 - part_num = atoi(tmp);
 - } else {
 - SLOGW("Kernel block uevent missing 'PARTN'");
 - part_num = 1;
 - }
 - if (part_num > mDiskNumParts) {
 - mDiskNumParts = part_num;
 - }
 - if (major != mDiskMajor) {
 - SLOGE("Partition '%s' has a different major than its disk!", devpath);
 - return;
 - }
 - #ifdef PARTITION_DEBUG
 - SLOGD("Dv:partAdd: part_num = %d, minor = %d\n", part_num, minor);
 - #endif
 - mPartMinors[part_num -1] = minor;
 - mPendingPartMap &= ~(1 << part_num);
 - if (!mPendingPartMap) {
 - #ifdef PARTITION_DEBUG
 - SLOGD("Dv:partAdd: Got all partitions - ready to rock!");
 - #endif
 - if (getState() != Volume::State_Formatting) {
 - setState(Volume::State_Idle);
 - }
 - } else {
 - #ifdef PARTITION_DEBUG
 - SLOGD("Dv:partAdd: pending mask now = 0x%x", mPendingPartMap);
 - #endif
 - }
 - }
 
当mPendingPartMap减为0时,这时Volume的状态不为State_Formatting,将广播一条VolumeStateChange的消息。
到这里,内核的消息基本就处理完了,当然这里讲的只是add的消息,还有remove,change消息等。。。这里就不做介绍了。
android usb挂载分析---vold处理内核消息的更多相关文章
- android usb挂载分析----vold启动
		
http://blog.csdn.net/new_abc/article/details/7396733 前段时间做了下usb挂载的,现在出了几个bug,又要把流程给梳理下,顺便也把相关的知识总结下, ...
 - android usb挂载分析---MountService启动
		
android usb挂载分析---MountService启动 分类: android框架 u盘挂载2012-03-27 23:00 11799人阅读 评论(4) 收藏 举报 androidsock ...
 - android usb挂载分析
		
http://blog.csdn.net/new_abc/article/details/7409018
 - android文件系统挂载分析(1)---正常开机挂载
		
未完,更新中 ... "android"系列分为三部分: 1.正常开机挂载 2.encryption 3.dm-verity 我们知道android有很多分区,如"sys ...
 - Android USB驱动源码分析(-)
		
Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...
 - Android源码分析-消息队列和Looper
		
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17361775 前言 上周对Android中的事件派发机制进行了分析,这次博主 ...
 - Chromium on Android: Android在系统Chromium为了实现主消息循环分析
		
总结:刚开始接触一个Chromium on Android时间.很好奇Chromium主消息循环是如何整合Android应用. 为Android计划,一旦启动,主线程将具有Java消息层循环处理系统事 ...
 - Android USB Host框架
		
Android 下的usb框架及功能点:https://blog.csdn.net/tianruxishui/article/details/379029591.Android framework中* ...
 - 【TencentOS  tiny】深度源码分析(4)——消息队列
		
消息队列 在前一篇文章中[TencentOS tiny学习]源码分析(3)--队列 我们描述了TencentOS tiny的队列实现,同时也点出了TencentOS tiny的队列是依赖于消息队列的, ...
 
随机推荐
- Vowel Counting
			
Vowel Counting Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Tota ...
 - 安卓OpenGL入门
			
1.先用一个GLSurfaceView作为画布,然后自定义一个Renderer继承自Renderer,把这个自定义的Renderer通过setRenderer()设置给GLSurfaceView就可以 ...
 - 安卓之PreferenceActivity分享
			
PerferenceActivity是什么,看下面的截图: Android的系统截图 乐手设置截图 好了,我们看到Android系统本身就大量用到了PreferenceActivity来对系统进行信息 ...
 - OSPF 原理
			
关于OSPF的数据结构Link-State Protocol Data Structures链路状态路由器与距离矢量路由器,可以知道关于整个网络的更多信息Neighbor table:also kno ...
 - avd
			
http://stackoverflow.com/questions/2662650/making-the-android-emulator-run-faster http://www.cnblogs ...
 - css 相关
			
background-size: auto就会变成就是不会让图像变形的,会自动调整,一般是会设置多少箱像素的, background-size: XXpx XXpx;百分百那就铺满整个区域了 back ...
 - linux 守护进程创建流程
			
#include <sys/stat.h> #include <fcntl.h> /* Bit-mask values for 'flags' argument of beco ...
 - uIP学习笔记
			
uIP学习笔记 从零开始使用uIP freemodbus modbus TCP 学习笔记
 - 运用Merge Into实现增加或更新数据
			
declare @SqlStr as nvarchar(max) set @SqlStr=N'Merge Into [Categories] t USING(VALUES (9,''rice'','' ...
 - 【dp】 poj 1157
			
不错的dp入门题 画出dp矩阵 每个dp[i][j]是由“其上”的状态或是“其左上”的状态转化而来,那我们选对角线和上边进行三角dp推导 #include<stdio.h> #incl ...