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

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

2015-10-02 11:58 483 查看

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

分类: u盘挂载2012-03-29 22:25 3215人阅读 评论(0) 收藏 举报
androidactioniteratordiskdelete

MountService启动之后 ,一切准备工作都 做好了,就等待碰上u盘插上了,

这里要讲的是内核发信息给vold,我们在 vold启动这篇曾讲到过注册了一个到内核的UEVENT事件,当有u盘插入的时候,我们就能从这个套接字上收到内核所发出的消息了,这样就开始了vold的消息处理。

先看下消息处理的流程:



在SocketListener::runListener()函数 中,我们一直在select,等待某个连接的到来或者已经的套接字上数据的到来,看下代码:

[html] view plaincopyprint?

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中的这个函数:

[cpp] view plaincopyprint?

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函数对收到的数据进行解析:

[cpp] view plaincopyprint?

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:

[plain] view plaincopyprint?

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(一部分):

[plain] view plaincopyprint?

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函数:

[cpp] view plaincopyprint?

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函数

[cpp] view plaincopyprint?

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

[cpp] view plaincopyprint?

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把相应的解析到的路径添加进去了,我们看下这个脚本:

[cpp] view plaincopyprint?

ev_mount sdcard /mnt/sdcard auto /devices/platform/hiusb-ehci.0 /devices/platform/hi_godbox-ehci.0

这里add的路径正好和上面 log打出来的路径相匹配,首先执行的handleDiskAdded,也就是在收到这样的消息的时候,提示有磁盘插入:

[cpp] view plaincopyprint?

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*这样的消息的

[cpp] view plaincopyprint?

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消息等。。。这里就不做介绍了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: