您的位置:首页 > 移动开发 > Android开发

android usb挂载分析---vold处理内核消息

2012-07-25 09:37 621 查看
MountService启动之后
,一切准备工作都 做好了,就等待碰上u盘插上了,我们先看下内核、vold、FrameWork的通信流程



这里要讲的是内核发信息给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:
<pre name="code" class="cpp">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;
}
</pre>mPaths我们在parse vold.fstab把相应的解析到的路径添加进去了,我们看下这个脚本:
<pre></pre>
<pre name="code" class="cpp" style="background-color: rgb(255, 255, 255); font-size: 16px; "></pre><pre name="code" class="cpp" style="background-color: rgb(255, 255, 255); font-size: 16px; "></pre><pre name="code" class="plain">dev_mount sdcard /mnt/sdcard auto /devices/platform/hiusb-ehci.0 /devices/platform/hi_godbox-ehci.0</pre>
<p>这里add的路径正好和上面 log打出来的路径相匹配,首先执行的<span style="font-size:16px">handleDiskAdded,也就是在收到</span><span style="font-size:16px">/block/sda这样的消息的时候,提示有磁盘插入:</span></p>
<p><span style="font-size:16px"></span></p>
<pre name="code" class="cpp">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);
}
</pre><pre name="code" class="cpp" style="background-color: rgb(255, 255, 255); font-size: 16px; ">mDiskNumParts 不为0,将Volume的状态设置为State_Pending并向FrameWork层广播VolumeDiskInserted的消息,在setState函数中也会广播VolumeStateChange的消息给上层</pre><pre name="code" class="cpp" style="background-color: rgb(255, 255, 255); font-size: 16px; ">接着就是handlePartitionAdded 这里是处理add /block/sda/sda*这样的消息的:</pre><pre name="code" class="cpp" style="background-color: rgb(255, 255, 255); font-size: 16px; "><pre name="code" class="cpp">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
}
}
</pre>当mPendingPartMap减为0时,这时Volume的状态不为State_Formatting,将广播一条VolumeStateChange的消息。
<pre></pre>
<p></p>
<pre></pre>
<pre name="code" class="cpp" style="background-color: rgb(255, 255, 255); font-size: 16px; "></pre><pre name="code" class="cpp" style="background-color: rgb(255, 255, 255); font-size: 16px; ">到这里,内核的消息基本就处理完了,当然这里讲的只是add的消息,还有remove,change消息等。。。这里就不做介绍了。</pre>
<p></p>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<p></p>
<p></p>
<p><span style="font-size:16px"><br>
<br>
<br>
<br>
</span></p>
<pre></pre>
<pre></pre>
<pre></pre>

</pre>



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: