android sd 挂载流程_Android 2.3 SD卡挂载流程浅析

前面的三篇《Android 2.3 SD卡挂载流程浅析(一) http://www.linuxidc.com/Linux/2011-11/47136.htm》、《Android 2.3 SD卡挂载流程浅析(二) http://www.linuxidc.com/Linux/2011-11/47136p2.htm》、《Android 2.3 SD卡挂载流程浅析(三) http://www.linuxidc.com/Linux/2011-11/47136p3.htm》的分析,知道了SD卡挂载的消息是如何从底层传递到上层的,在《Android 2.3 SD卡挂载流程浅析(三)》中,我们已经知道了最后是在updatePublicVolumeState()中调用onStorageStateChanged(),从而达到更新SD卡挂载信息的。在本文《Android 2.3 SD卡挂载流程浅析(四) http://www.linuxidc.com/Linux/2011-11/47136p4.htm 》中,我会将前文提到的程序调用流程图画出来,并对代码进行简单的分析。

首先,还是挂出这张老图(因为每次都用这张图0_0...)。

就权当复习吧,这是SD卡的整个挂载流程,而程序的调用也是根据这个流程图来的。

1.接收并处理uevent

首先是接收因为插入SD卡被内核检测到而发出的Event;

NetlinkHandler::onEvent(NetlinkEvent *evt)

//代码路径:AndroidSourcecode2.3/system/vold/NetlinkHandler.cpp

//该方法主要通过evt->getSubsystem();方法来获取系统的event

voidNetlinkHandler::onEvent(NetlinkEvent *evt) {

VolumeManager *vm = VolumeManager::Instance();

constchar*subsys = evt->getSubsystem();

if(!subsys) {

SLOGW("No subsystem found in netlink event");

return;

}

if(!strcmp(subsys,"block")) {

vm->handleBlockEvent(evt);

} elseif(!strcmp(subsys,"switch")) {

vm->handleSwitchEvent(evt);

} elseif(!strcmp(subsys,"usb_composite")) {

vm->handleUsbCompositeEvent(evt);

} elseif(!strcmp(subsys,"battery")) {

} elseif(!strcmp(subsys,"power_supply")) {

}

}

voidNetlinkHandler::onEvent(NetlinkEvent *evt) {

VolumeManager *vm = VolumeManager::Instance();

constchar*subsys = evt->getSubsystem();

if(!subsys) {

SLOGW("No subsystem found in netlink event");

return;

}

if(!strcmp(subsys,"block")) {

vm->handleBlockEvent(evt);

}elseif(!strcmp(subsys,"switch")) {

vm->handleSwitchEvent(evt);

}elseif(!strcmp(subsys,"usb_composite")) {

vm->handleUsbCompositeEvent(evt);

}elseif(!strcmp(subsys,"battery")) {

}elseif(!strcmp(subsys,"power_supply")) {

}

}      2.对SD卡挂载事件开始处理

void VolumeManager::handleBlockEvent(NetlinkEvent *evt)

//代码路径:AndroidSourcecode2.3/system/vold/VolumeManager.cpp

//该方法的主要作用是:

//第一,    遍历mPath容器,寻找与event对应的sysfs_path是否存在与mPath容器中。

//第二,    针对Event中的action有4种处理方式:Add,Removed,Change,Noaction。

voidVolumeManager::handleBlockEvent(NetlinkEvent *evt) {

constchar*devpath = evt->findParam("DEVPATH");

/* Lookup a volume to handle this device */

VolumeCollection::iterator it;

boolhit =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

}

}

voidVolumeManager::handleBlockEvent(NetlinkEvent *evt) {

constchar*devpath = evt->findParam("DEVPATH");

/* Lookup a volume to handle this device */

VolumeCollection::iterator it;

boolhit =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

}

}    3.对Block挂载事件进行处理

DirectVolume::handleBlockEvent(NetlinkEvent *evt)

//代码路径:AndroidSourcecode2.3/system/vold/DirectVolume.cpp

//在Add action中首先会创建设备节点,然后对disk和partion两种格式的设备分别进行处理。这里是disk格式。

intDirectVolume::handleBlockEvent(NetlinkEvent *evt) {

constchar*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 */

intaction = evt->getAction();

constchar*devtype = evt->findParam("DEVTYPE");

if(action == NetlinkEvent::NlActionAdd) {

intmajor = atoi(evt->findParam("MAJOR"));

intminor = atoi(evt->findParam("MINOR"));

charnodepath[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);//SD卡插入是Add事件

} else{

handlePartitionAdded(dp, evt);

}

} elseif(action == NetlinkEvent::NlActionRemove) {

if(!strcmp(devtype,"disk")) {

handleDiskRemoved(dp, evt);

} else{

handlePartitionRemoved(dp, evt);

}

} elseif(action == NetlinkEvent::NlActionChange) {

if(!strcmp(devtype,"disk")) {

handleDiskChanged(dp, evt);

} else{

handlePartitionChanged(dp, evt);

}

} else{

SLOGW("Ignoring non add/remove/change event");

}

return0;

}

}

errno = ENODEV;

return-1;

}

int

DirectVolume::handleBlockEvent(NetlinkEvent *evt) {

constchar*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 */

intaction = evt->getAction();

constchar*devtype = evt->findParam("DEVTYPE");

if(action == NetlinkEvent::NlActionAdd) {

intmajor = atoi(evt->findParam("MAJOR"));

intminor = atoi(evt->findParam("MINOR"));

charnodepath[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")) {

style="color:#ff0000;">handleDiskAdded(dp, evt);

style="color:#33cc00;">//SD卡插入是Add事件

}else{

handlePartitionAdded(dp, evt);

}

}elseif(action == NetlinkEvent::NlActionRemove) {

if(!strcmp(devtype,"disk")) {

handleDiskRemoved(dp, evt);

}else{

handlePartitionRemoved(dp, evt);

}

}elseif(action == NetlinkEvent::NlActionChange) {

if(!strcmp(devtype,"disk")) {

handleDiskChanged(dp, evt);

}else{

handlePartitionChanged(dp, evt);

}

}else{

SLOGW("Ignoring non add/remove/change event");

}

return0;

}

}

errno = ENODEV;

return-1;

}      4.处理DiskAdd事件

DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt)

//代码路径:AndroidSourcecode2.3/system/vold/DirectVolume.cpp

//在该方法中广播disk insert的广播消息(这里的广播不同于Java中的广播,这里实际上是Socket)。

voidDirectVolume::handleDiskAdded(constchar*devpath, NetlinkEvent *evt) {

mDiskMajor = atoi(evt->findParam("MAJOR"));

mDiskMinor = atoi(evt->findParam("MINOR"));

constchar*tmp = evt->findParam("NPARTS");

if(tmp) {

mDiskNumParts = atoi(tmp);

} else{

SLOGW("Kernel block uevent missing 'NPARTS'");

mDiskNumParts = 1;

}

charmsg[255];

intpartmask = 0;

inti;

for(i = 1; i <= mDiskNumParts; i++) {

partmask |= (1 <

}

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);

}

voidDirectVolume::handleDiskAdded(constchar*devpath, NetlinkEvent *evt) {

mDiskMajor = atoi(evt->findParam("MAJOR"));

mDiskMinor = atoi(evt->findParam("MINOR"));

constchar*tmp = evt->findParam("NPARTS");

if(tmp) {

mDiskNumParts = atoi(tmp);

}else{

SLOGW("Kernel block uevent missing 'NPARTS'");

mDiskNumParts = 1;

}

charmsg[255];

intpartmask = 0;

inti;

for(i = 1; i <= mDiskNumParts; i++) {

partmask |= (1 <

}

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);

}      5.处理广播消息

SocketListener::runListener()

//代码路径:AndroidSourcecode2.3/system/core/libsysutils/src/SocketListener.cpp

//完成对Socket的监听以及对数据的处理onDataAvailable(* it );

voidSocketListener::runListener() {

while(1) {

SocketClientCollection::iterator it;

fd_set read_fds;

intrc = 0;

intmax = 0;

FD_ZERO(&read_fds);

if(mListen) {

max = mSock;

FD_SET(mSock, &read_fds);

}

FD_SET(mCtrlPipe[0], &read_fds);

if(mCtrlPipe[0] > max)

max = mCtrlPipe[0];

pthread_mutex_lock(&mClientsLock);

for(it = mClients->begin(); it != mClients->end(); ++it) {

FD_SET((*it)->getSocket(), &read_fds);

if((*it)->getSocket() > max)

max = (*it)->getSocket();

}

pthread_mutex_unlock(&mClientsLock);

if((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) 

SLOGE("select failed (%s)", strerror(errno));

sleep(1);

continue;

} elseif(!rc)

continue;

if(FD_ISSET(mCtrlPipe[0], &read_fds))

break;

if(mListen && FD_ISSET(mSock, &read_fds)) {

structsockaddr addr;

socklen_t alen = sizeof(addr);

intc;

if((c = accept(mSock, &addr, &alen)) 

SLOGE("accept failed (%s)", strerror(errno));

sleep(1);

continue;

}

pthread_mutex_lock(&mClientsLock);

mClients->push_back(newSocketClient(c));

pthread_mutex_unlock(&mClientsLock);

}

do{

pthread_mutex_lock(&mClientsLock);

for(it = mClients->begin(); it != mClients->end(); ++it) {

intfd = (*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);

}

}

voidSocketListener::runListener() {

while(1) {

SocketClientCollection::iterator it;

fd_set read_fds;

intrc = 0;

intmax = 0;

FD_ZERO(&read_fds);

if(mListen) {

max = mSock;

FD_SET(mSock, &read_fds);

}

FD_SET(mCtrlPipe[0], &read_fds);

if(mCtrlPipe[0] > max)

max = mCtrlPipe[0];

pthread_mutex_lock(&mClientsLock);

for(it = mClients->begin(); it != mClients->end(); ++it) {

FD_SET((*it)->getSocket(), &read_fds);

if((*it)->getSocket() > max)

max = (*it)->getSocket();

}

pthread_mutex_unlock(&mClientsLock);

if((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) 

SLOGE("select failed (%s)", strerror(errno));

sleep(1);

continue;

}elseif(!rc)

continue;

if(FD_ISSET(mCtrlPipe[0], &read_fds))

break;

if(mListen && FD_ISSET(mSock, &read_fds)) {

structsockaddr addr;

socklen_t alen =sizeof(addr);

intc;

if((c = accept(mSock, &addr, &alen)) 

SLOGE("accept failed (%s)", strerror(errno));

sleep(1);

continue;

}

pthread_mutex_lock(&mClientsLock);

mClients->push_back(newSocketClient(c));

pthread_mutex_unlock(&mClientsLock);

}

do{

pthread_mutex_lock(&mClientsLock);

for(it = mClients->begin(); it != mClients->end(); ++it) {

intfd = (*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);

}

}      6.处理消息内容

FrameworkListener::onDataAvailable(SocketClient *c)

//代码路径:AndroidSourcecode2.3/system/core/libsysutils/src/FrameworkListener.cpp

//对接收到的广播消息进行处理

boolFrameworkListener::onDataAvailable(SocketClient *c) {

charbuffer[255];

intlen;

if((len = read(c->getSocket(), buffer,sizeof(buffer) -1)) 

SLOGE("read() failed (%s)", strerror(errno));

returnfalse;

} elseif(!len)

returnfalse;

intoffset = 0;

inti;

for(i = 0; i 

if(buffer[i] =='\0') {

dispatchCommand(c, buffer + offset);

offset = i + 1;

}

}

returntrue;

}

boolFrameworkListener::onDataAvailable(SocketClient *c) {

charbuffer[255];

intlen;

if((len = read(c->getSocket(), buffer,sizeof(buffer) -1)) 

SLOGE("read() failed (%s)", strerror(errno));

returnfalse;

}elseif(!len)

returnfalse;

intoffset = 0;

inti;

for(i = 0; i 

if(buffer[i] =='\0') {

dispatchCommand(c, buffer + offset);

offset = i + 1;

}

}

returntrue;

}      7.分发指令

FrameworkListener::dispatchCommand(SocketClient *cli, char *data)

//代码路径:AndroidSourcecode2.3/system/core/libsysutils/src/FrameworkListener.cpp

//分配指令:DumpCmd、VolumeCmd、AsecCmd、ShareCmd、StorageCmd、XwarpCmd

voidFrameworkListener::dispatchCommand(SocketClient *cli,char*data) {

FrameworkCommandCollection::iterator i;

intargc = 0;

char*argv[FrameworkListener::CMD_ARGS_MAX];

chartmp[255];

char*p = data;

char*q = tmp;

boolesc =false;

boolquote =false;

intk;

memset(argv, 0, sizeof(argv));

memset(tmp, 0, sizeof(tmp));

while(*p) {

if(*p =='\\') {

if(esc) {

*q++ = '\\';

esc = false;

} else

esc = true;

p++;

continue;

} elseif(esc) {

if(*p =='"')

*q++ = '"';

elseif(*p =='\\')

*q++ = '\\';

else{

cli->sendMsg(500, "Unsupported escape sequence",false);

gotoout;

}

p++;

esc = false;

continue;

}

if(*p =='"') {

if(quote)

quote = false;

else

quote = true;

p++;

continue;

}

*q = *p++;

if(!quote && *q ==' ') {

*q = '\0';

argv[argc++] = strdup(tmp);

memset(tmp, 0, sizeof(tmp));

q = tmp;

continue;

}

q++;

}

argv[argc++] = strdup(tmp);

#if 0

for(k = 0; k 

SLOGD("arg[%d] = '%s'", k, argv[k]);

}

#endif

if(quote) {

cli->sendMsg(500, "Unclosed quotes error",false);

gotoout;

}

for(i = mCommands->begin(); i != mCommands->end(); ++i) {

FrameworkCommand *c = *i;

if(!strcmp(argv[0], c->getCommand())) {

if(c->runCommand(cli, argc, argv)) {

SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));

}

gotoout;

}

}

cli->sendMsg(500, "Command not recognized",false);

out:

intj;

for(j = 0; j 

free(argv[j]);

return;

}

voidFrameworkListener::dispatchCommand(SocketClient *cli,char*data) {

FrameworkCommandCollection::iterator i;

intargc = 0;

char*argv[FrameworkListener::CMD_ARGS_MAX];

chartmp[255];

char*p = data;

char*q = tmp;

boolesc =false;

boolquote =false;

intk;

memset(argv, 0,sizeof(argv));

memset(tmp, 0,sizeof(tmp));

while(*p) {

if(*p =='\\') {

if(esc) {

*q++ ='\\';

esc =false;

}else

esc =true;

p++;

continue;

}elseif(esc) {

if(*p =='"')

*q++ ='"';

elseif(*p =='\\')

*q++ ='\\';

else{

cli->sendMsg(500,"Unsupported escape sequence",false);

gotoout;

}

p++;

esc =false;

continue;

}

if(*p =='"') {

if(quote)

quote =false;

else

quote =true;

p++;

continue;

}

*q = *p++;

if(!quote && *q ==' ') {

*q ='\0';

argv[argc++] = strdup(tmp);

memset(tmp, 0,sizeof(tmp));

q = tmp;

continue;

}

q++;

}

argv[argc++] = strdup(tmp);

#if 0

for(k = 0; k 

SLOGD("arg[%d] = '%s'", k, argv[k]);

}

#endif

if(quote) {

cli->sendMsg(500,"Unclosed quotes error",false);

gotoout;

}

for(i = mCommands->begin(); i != mCommands->end(); ++i) {

FrameworkCommand *c = *i;

if(!strcmp(argv[0], c->getCommand())) {

if(c->runCommand(cli, argc, argv)) {

SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));

}

gotoout;

}

}

cli->sendMsg(500,"Command not recognized",false);

out:

intj;

for(j = 0; j 

free(argv[j]);

return;

}    8.开始执行挂载

CommandListener::VolumeCmd::runCommand(SocketClient *cli,int argc, char **argv)

//代码路径:AndroidSourcecode2.3/system/vold/CommandListener.cpp

//rc = vm->mountVolume(argv[2]);

intCommandListener::VolumeCmd::runCommand(SocketClient *cli,intargc,char**argv) {

dumpArgs(argc, argv, -1);

if(argc 

cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument",false);

return0;

}

VolumeManager *vm = VolumeManager::Instance();

intrc = 0;

if(!strcmp(argv[1],"list")) {

returnvm->listVolumes(cli);

} elseif(!strcmp(argv[1],"debug")) {

if(argc != 3 || (argc == 3 && (strcmp(argv[2],"off") && strcmp(argv[2],"on")))) {

cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug ",false);

return0;

}

vm->setDebug(!strcmp(argv[2], "on") ?true:false);

} elseif(!strcmp(argv[1],"mount")) {

if(argc != 3) {

cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount ",false);

return0;

}

rc = vm->mountVolume(argv[2]);

} elseif(!strcmp(argv[1],"unmount")) {

if(argc  4 || (argc == 4 && strcmp(argv[3],"force"))) {

cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount  [force]",false);

return0;

}

boolforce =false;

if(argc >= 4 && !strcmp(argv[3],"force")) {

force = true;

}

rc = vm->unmountVolume(argv[2], force);

} elseif(!strcmp(argv[1],"format")) {

if(argc != 3) {

cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format ",false);

return0;

}

rc = vm->formatVolume(argv[2]);

} elseif(!strcmp(argv[1],"share")) {

if(argc != 4) {

cli->sendMsg(ResponseCode::CommandSyntaxError,

"Usage: volume share  ",false);

return0;

}

rc = vm->shareVolume(argv[2], argv[3]);

} elseif(!strcmp(argv[1],"unshare")) {

if(argc != 4) {

cli->sendMsg(ResponseCode::CommandSyntaxError,

"Usage: volume unshare  ",false);

return0;

}

rc = vm->unshareVolume(argv[2], argv[3]);

} elseif(!strcmp(argv[1],"shared")) {

boolenabled =false;

if(argc != 4) {

cli->sendMsg(ResponseCode::CommandSyntaxError,

"Usage: volume shared  ",false);

return0;

}

if(vm->shareEnabled(argv[2], argv[3], &enabled)) {

cli->sendMsg(

ResponseCode::OperationFailed, "Failed to determine share enable state",true);

} else{

cli->sendMsg(ResponseCode::ShareEnabledResult,

(enabled ? "Share enabled":"Share disabled"),false);

}

return0;

} else{

cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd",false);

}

if(!rc) {

cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded",false);

} else{

interno = errno;

rc = ResponseCode::convertFromErrno();

cli->sendMsg(rc, "volume operation failed",true);

}

return0;

}

intCommandListener::VolumeCmd::runCommand(SocketClient *cli,intargc,char**argv) {

dumpArgs(argc, argv, -1);

if(argc 

cli->sendMsg(ResponseCode::CommandSyntaxError,"Missing Argument",false);

return0;

}

VolumeManager *vm = VolumeManager::Instance();

intrc = 0;

if(!strcmp(argv[1],"list")) {

returnvm->listVolumes(cli);

}elseif(!strcmp(argv[1],"debug")) {

if(argc != 3 || (argc == 3 && (strcmp(argv[2],"off") && strcmp(argv[2],"on")))) {

cli->sendMsg(ResponseCode::CommandSyntaxError,"Usage: volume debug ",false);

return0;

}

vm->setDebug(!strcmp(argv[2],"on") ?true:false);

}elseif(!strcmp(argv[1],"mount")) {

if(argc != 3) {

cli->sendMsg(ResponseCode::CommandSyntaxError,"Usage: volume mount ",false);

return0;

}

rc = vm->mountVolume(argv[2]);

}elseif(!strcmp(argv[1],"unmount")) {

if(argc  4 || (argc == 4 && strcmp(argv[3],"force"))) {

cli->sendMsg(ResponseCode::CommandSyntaxError,"Usage: volume unmount  [force]",false);

return0;

}

boolforce =false;

if(argc >= 4 && !strcmp(argv[3],"force")) {

force =true;

}

rc = vm->unmountVolume(argv[2], force);

}elseif(!strcmp(argv[1],"format")) {

if(argc != 3) {

cli->sendMsg(ResponseCode::CommandSyntaxError,"Usage: volume format ",false);

return0;

}

rc = vm->formatVolume(argv[2]);

}elseif(!strcmp(argv[1],"share")) {

if(argc != 4) {

cli->sendMsg(ResponseCode::CommandSyntaxError,

"Usage: volume share  ",false);

return0;

}

rc = vm->shareVolume(argv[2], argv[3]);

}elseif(!strcmp(argv[1],"unshare")) {

if(argc != 4) {

cli->sendMsg(ResponseCode::CommandSyntaxError,

"Usage: volume unshare  ",false);

return0;

}

rc = vm->unshareVolume(argv[2], argv[3]);

}elseif(!strcmp(argv[1],"shared")) {

boolenabled =false;

if(argc != 4) {

cli->sendMsg(ResponseCode::CommandSyntaxError,

"Usage: volume shared  ",false);

return0;

}

if(vm->shareEnabled(argv[2], argv[3], &enabled)) {

cli->sendMsg(

ResponseCode::OperationFailed,"Failed to determine share enable state",true);

}else{

cli->sendMsg(ResponseCode::ShareEnabledResult,

(enabled ?"Share enabled":"Share disabled"),false);

}

return0;

}else{

cli->sendMsg(ResponseCode::CommandSyntaxError,"Unknown volume cmd",false);

}

if(!rc) {

cli->sendMsg(ResponseCode::CommandOkay,"volume operation succeeded",false);

}else{

interno = errno;

rc = ResponseCode::convertFromErrno();

cli->sendMsg(rc,"volume operation failed",true);

}

return0;

}     9.调用方法执行挂载动作

VolumeManager::mountVolume(const char *label)

//代码路径:AndroidSourcecode2.3/system/vold/VolumeManager.cpp//v->mountVol();

intVolumeManager::mountVolume(constchar*label) {

Volume *v = lookupVolume(label);

if(!v) {

errno = ENOENT;

return-1;

}

returnv->mountVol();

}

intVolumeManager::mountVolume(constchar*label) {

Volume *v = lookupVolume(label);

if(!v) {

errno = ENOENT;

return-1;

}

returnv->mountVol();

}    10.真正的挂载者

Volume::mountVol()

//代码路径:AndroidSourcecode2.3/system/vold/Volume.cpp

//SD卡的挂载最终是在该方法中实现的,如果挂载有异常,也会在该方法的执行过程通过setState方法发出广播。

intVolume::mountVol() {

dev_t deviceNodes[4];

intn, i, rc = 0;

charerrmsg[255];

if(getState() == Volume::State_NoMedia) {

snprintf(errmsg, sizeof(errmsg),

"Volume %s %s mount failed - no media",

getLabel(), getMountpoint());

mVm->getBroadcaster()->sendBroadcast(

ResponseCode::VolumeMountFailedNoMedia,

errmsg, false);

errno = ENODEV;

return-1;

} elseif(getState() != Volume::State_Idle) {

errno = EBUSY;

return-1;

}

if(isMountpointMounted(getMountpoint())) {

SLOGW("Volume is idle but appears to be mounted - fixing");

setState(Volume::State_Mounted);

// mCurrentlyMountedKdev = XXX

return0;

}

n = getDeviceNodes((dev_t *) &deviceNodes, 4);

if(!n) {

SLOGE("Failed to get device nodes (%s)\n", strerror(errno));

return-1;

}

for(i = 0; i 

chardevicePath[255];

sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]),

MINOR(deviceNodes[i]));

SLOGI("%s being considered for volume %s\n", devicePath, getLabel());

errno = 0;

setState(Volume::State_Checking);

if(Fat::check(devicePath)) {//如果SD卡的格式不对是通不过这里的检测的

if(errno == ENODATA) {

SLOGW("%s does not contain a FAT filesystem\n", devicePath);

continue;

}

errno = EIO;

/* Badness - abort the mount */

SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno));

setState(Volume::State_Idle);

return-1;

}

/*

* Mount the device on our internal staging mountpoint so we can

* muck with it before exposing it to non priviledged users.

*/

errno = 0;

if(Fat::doMount(devicePath,"/mnt/secure/staging",false,false,false,

1000, 1015, 0702, true)) {//真正的挂载方法doMount

SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));

continue;

}

SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint());

protectFromAutorunStupidity();

if(createBindMounts()) {

SLOGE("Failed to create bindmounts (%s)", strerror(errno));

umount("/mnt/secure/staging");

setState(Volume::State_Idle);

return-1;

}

/*

* Now that the bindmount trickery is done, atomically move the

* whole subtree to expose it to non priviledged users.

*/

if(doMoveMount("/mnt/secure/staging", getMountpoint(),false)) {

SLOGE("Failed to move mount (%s)", strerror(errno));

umount("/mnt/secure/staging");

setState(Volume::State_Idle);

return-1;

}

setState(Volume::State_Mounted);

mCurrentlyMountedKdev = deviceNodes[i];

return0;

}

SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());

setState(Volume::State_Idle);

return-1;

}

intVolume::mountVol() {

dev_t deviceNodes[4];

intn, i, rc = 0;

charerrmsg[255];

if(getState() == Volume::State_NoMedia) {

snprintf(errmsg,sizeof(errmsg),

"Volume %s %s mount failed - no media",

getLabel(), getMountpoint());

mVm->getBroadcaster()->sendBroadcast(

ResponseCode::VolumeMountFailedNoMedia,

errmsg,false);

errno = ENODEV;

return-1;

}elseif(getState() != Volume::State_Idle) {

errno = EBUSY;

return-1;

}

if(isMountpointMounted(getMountpoint())) {

SLOGW("Volume is idle but appears to be mounted - fixing");

setState(Volume::State_Mounted);

// mCurrentlyMountedKdev = XXX

return0;

}

n = getDeviceNodes((dev_t *) &deviceNodes, 4);

if(!n) {

SLOGE("Failed to get device nodes (%s)\n", strerror(errno));

return-1;

}

for(i = 0; i 

chardevicePath[255];

sprintf(devicePath,"/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]),

MINOR(deviceNodes[i]));

SLOGI("%s being considered for volume %s\n", devicePath, getLabel());

errno = 0;

setState(Volume::State_Checking);

if(Fat::check(devicePath)) {//如果SD卡的格式不对是通不过这里的检测的

if(errno == ENODATA) {

SLOGW("%s does not contain a FAT filesystem\n", devicePath);

continue;

}

errno = EIO;

/* Badness - abort the mount */

SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno));

setState(Volume::State_Idle);

return-1;

}

/*

* Mount the device on our internal staging mountpoint so we can

* muck with it before exposing it to non priviledged users.

*/

errno = 0;

if(Fat::doMount(devicePath,"/mnt/secure/staging",false,false,false,

1000, 1015, 0702,true)) {//真正的挂载方法doMount

SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));

continue;

}

SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint());

protectFromAutorunStupidity();

if(createBindMounts()) {

SLOGE("Failed to create bindmounts (%s)", strerror(errno));

umount("/mnt/secure/staging");

setState(Volume::State_Idle);

return-1;

}

/*

* Now that the bindmount trickery is done, atomically move the

* whole subtree to expose it to non priviledged users.

*/

if(doMoveMount("/mnt/secure/staging", getMountpoint(),false)) {

SLOGE("Failed to move mount (%s)", strerror(errno));

umount("/mnt/secure/staging");

setState(Volume::State_Idle);

return-1;

}

setState(Volume::State_Mounted);

mCurrentlyMountedKdev = deviceNodes[i];

return0;

}

SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());

setState(Volume::State_Idle);

return-1;

}

到这里SD卡的挂载基本上已经完成,但是我们的目的是理清一条从底向上的路线,因此我会继续向上分析。我会将这一点在下一篇《Android 2.3 SD卡挂载流程浅析(五)》中继续分析。

因为这些都是我个人的一些见解,因此不见得都正确,希望读者抱着怀疑的态度阅读。不过不是有句名言叫“大胆假设,小心求证”吗!如文中有错误,还恳请各位看官指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值