前面的三篇《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卡挂载流程浅析(五)》中继续分析。
因为这些都是我个人的一些见解,因此不见得都正确,希望读者抱着怀疑的态度阅读。不过不是有句名言叫“大胆假设,小心求证”吗!如文中有错误,还恳请各位看官指正。