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的队列是依赖于消息队列的, ...
随机推荐
- 贝叶斯分类器(Bayes分类器)
贝叶斯(Bayes)定理 (条件概率) 贝叶斯分类器(Bayes分类器) 1概念: 将每个属性及类别标记视为随机变量 给定一个具有属性集合(A1, A2,…,An)的记录 目标是预测 ...
- iOS使用NSMutableAttributedString
在iOS开发中,常常会有一段文字显示不同的颜色和字体,或者给某几个文字加删除线或下划线的需求.之前在网上找了一些资料,有的是重绘UILabel的textLayer,有的是用html5实现的,都比较麻烦 ...
- 剑指offer青蛙跳台阶问题
(1)一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级.求该青蛙跳上一个n 级的台阶总共有多少种跳法. //递归方式 public static int f(int n) { //参数合法性验证 ...
- strictmode
最新的Android平台中(Android 2.3起),新增加了一个新的类,叫StrictMode(android.os.StrictMode).这个类可以用来帮助开发者改进他们编写的应用,并且提供了 ...
- 百度,google的地理编码
1.百度的地理编码:(不支持中国以外的其它城市) http://api.map.baidu.com/geocoder/v2/?ak=E974997f80db18330f8f5c61d084a677&a ...
- redis采用序列化方案存对象
前几天被问到这样一个问题,redis怎么存对象,平时也没怎么注意,只知道redis存字符之类的,不过就是根据键存取值,不过对象的话还是不同的 首先来了解一下为什么要实现序列化 为什么要实现序列化接口 ...
- NullPointerException
if(userName.equals("zhansan")){} 可能会报空指针异常
- javascript语句语义大全(7)
1. 事件 onmousedown——鼠标按下事件 当鼠标按下的时候触发,根据鼠标不同的按键会有不同的值传入,左键0,滚轮1,右键2,不同浏览器可能有不同. onmousemove——当鼠标移动的时候 ...
- Django - 通用视图
urls.py from . import views ... url(r'^$', views.IndexView.as_view, name="index"), url(r'^ ...
- Node.js学习 - CallBack Function
Node.js异步编程的直接体现就是回调,Node使用了大量的回调函数,其所有的API都支持回调. 阻塞代码实例(同步) var fs = require("fs"); var d ...