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的队列是依赖于消息队列的, ...
随机推荐
- servlet第1讲初识
- how computer boot up?
The power button activates the power supply in the PC, sending power to the motherboard and other co ...
- DefaultHttpClient is deprecated 【Api 弃用]】
最近在使用Apache的httpclient的时候,maven引用了最新版本4.3,发现Idea提示DefaultHttpClient等常用的类已经不推荐使用了,之前在使用4.2.3版本的时候,还没有 ...
- string 转 int,int 转 string
string str="12345"; int b=atoi(str.c_str()); 可以配合atof,转为double char buf[10]; sprintf(buf, ...
- PHP字符串函数试题
Ctrl+A查看答案 1.把ASCII字符的字符串转换为十六进制值的函数是什么?答:bin2hex($string),例如bin2hex('ab') = 6162 2.ASCII码转字符,字符转ASC ...
- launchMode传递参数注意startActivityForResult
Activity1 到Activity2 用startActivityForResult 如果Activity2的launchMode为 singleInstance 和 singleTask 都会启 ...
- select用法
每一次操作select的时候,总是要出来翻一下资料,不如自己总结一下,以后就翻这里了. 比如<select class="selector"></select&g ...
- 【转】Git代码行统计命令集
http://blog.csdn.NET/dwarven/article/details/46550117 http://blog.csdn.net/hshl1214/article/details/ ...
- 四种xml的解析方式
这篇文章是我上网找资料,加上自己总结了一些而得 资料来源: http://www.cnblogs.com/allenzheng/archive/2012/12/01/2797196.html http ...
- Beam me out!
Beam me out! 题目描述 King Remark, first of his name, is a benign ruler and every wrongdoer gets a second ...