前面的三篇博文《Android 2.3 SD卡挂载流程浅析(一)》、《Android 2.3 SD卡挂载流程浅析(二)》、《Android 2.3 SD卡挂载流程浅析(三)》的分析,知道了SD卡挂载的消息是如何从底层传递到上层的,在《Android 2.3 SD卡挂载流程浅析(三)》中,我们已经知道了最后是在updatePublicVolumeState()中调用onStorageStateChanged(),从而达到更新SD卡挂载信息的。在本文《Android
2.3 SD卡挂载流程浅析(四)》中,我会将前文提到的程序调用流程图画出来,并对代码进行简单的分析。
首先,还是挂出这张老图(因为每次都用这张图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("Nosubsystemfoundinnetlinkevent");
- 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");
- VolumeCollection::iteratorit;
- boolhit=false;
- for(it=mVolumes->begin();it!=mVolumes->end();++it){
- if(!(*it)->handleBlockEvent(evt)){
- #ifdefNETLINK_DEBUG
- SLOGD("Device'%s'eventhandledbyvolume%s\n",devpath,(*it)->getLabel());
- #endif
- hit=true;
- break;
- }
- }
- if(!hit){
- #ifdefNETLINK_DEBUG
- SLOGW("Novolumeshandledblockeventfor'%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::iteratorit;
- for(it=mPaths->begin();it!=mPaths->end();++it){
- if(!strncmp(dp,*it,strlen(*it))){
- 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("Errormakingdevicenode'%s'(%s)",nodepath,
- strerror(errno));
- }
- if(!strcmp(devtype,"disk")){
- <spanstyle="color:#ff0000;">handleDiskAdded(dp,evt);<spanstyle="color:#33cc00;">
- }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("Ignoringnonadd/remove/changeevent");
- }
- 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("Kernelblockueventmissing'NPARTS'");
- mDiskNumParts=1;
- }
- charmsg[255];
- intpartmask=0;
- inti;
- for(i=1;i<=mDiskNumParts;i++){
- partmask|=(1<<i);
- }
- mPendingPartMap=partmask;
- if(mDiskNumParts==0){
- #ifdefPARTITION_DEBUG
- SLOGD("Dv::diskIns-Nopartitions-goodtogoson!");
- #endif
- setState(Volume::State_Idle);
- }else{
- #ifdefPARTITION_DEBUG
- SLOGD("Dv::diskIns-waitingfor%dpartitions(mask0x%x)",
- mDiskNumParts,mPendingPartMap);
- #endif
- setState(Volume::State_Pending);
- }
- snprintf(msg,sizeof(msg),"Volume%s%sdiskinserted(%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::iteratorit;
- fd_setread_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))<0){
- SLOGE("selectfailed(%s)",strerror(errno));
- sleep(1);
- continue;
- }elseif(!rc)
- continue;
- if(FD_ISSET(mCtrlPipe[0],&read_fds))
- break;
- if(mListen&&FD_ISSET(mSock,&read_fds)){
- structsockaddraddr;
- socklen_talen=sizeof(addr);
- intc;
- if((c=accept(mSock,&addr,&alen))<0){
- SLOGE("acceptfailed(%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(!<spanstyle="color:#ff0000;">onDataAvailable(*it)</span>){
- 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))<0){
- SLOGE("read()failed(%s)",strerror(errno));
- returnfalse;
- }elseif(!len)
- returnfalse;
- intoffset=0;
- inti;
- for(i=0;i<len;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::iteratori;
- 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,"Unsupportedescapesequence",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);
- #if0
- for(k=0;k<argc;k++){
- SLOGD("arg[%d]='%s'",k,argv[k]);
- }
- #endif
- if(quote){
- cli->sendMsg(500,"Unclosedquoteserror",false);
- gotoout;
- }
- for(i=mCommands->begin();i!=mCommands->end();++i){
- FrameworkCommand*c=*i;
- if(!strcmp(argv[0],c->getCommand())){
- if(c-><spanstyle="color:#ff0000;">runCommand</span>(cli,argc,argv)){
- SLOGW("Handler'%s'error(%s)",c->getCommand(),strerror(errno));
- }
- gotoout;
- }
- }
- cli->sendMsg(500,"Commandnotrecognized",false);
- out:
- intj;
- for(j=0;j<argc;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<2){
- cli->sendMsg(ResponseCode::CommandSyntaxError,"MissingArgument",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:volumedebug<off/on>",false);
- return0;
- }
- vm->setDebug(!strcmp(argv[2],"on")?true:false);
- }elseif(!strcmp(argv[1],"mount")){
- if(argc!=3){
- cli->sendMsg(ResponseCode::CommandSyntaxError,"Usage:volumemount<path>",false);
- return0;
- }
- <spanstyle="color:#ff0000;">rc=vm->mountVolume(argv[2]);</span>
- }elseif(!strcmp(argv[1],"unmount")){
- if(argc<3||argc>4||(argc==4&&strcmp(argv[3],"force"))){
- cli->sendMsg(ResponseCode::CommandSyntaxError,"Usage:volumeunmount<path>[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:volumeformat<path>",false);
- return0;
- }
- rc=vm->formatVolume(argv[2]);
- }elseif(!strcmp(argv[1],"share")){
- if(argc!=4){
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage:volumeshare<path><method>",false);
- return0;
- }
- rc=vm->shareVolume(argv[2],argv[3]);
- }elseif(!strcmp(argv[1],"unshare")){
- if(argc!=4){
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage:volumeunshare<path><method>",false);
- return0;
- }
- rc=vm->unshareVolume(argv[2],argv[3]);
- }elseif(!strcmp(argv[1],"shared")){
- boolenabled=false;
- if(argc!=4){
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage:volumeshared<path><method>",false);
- return0;
- }
- if(vm->shareEnabled(argv[2],argv[3],&enabled)){
- cli->sendMsg(
- ResponseCode::OperationFailed,"Failedtodetermineshareenablestate",true);
- }else{
- cli->sendMsg(ResponseCode::ShareEnabledResult,
- (enabled?"Shareenabled":"Sharedisabled"),false);
- }
- return0;
- }else{
- cli->sendMsg(ResponseCode::CommandSyntaxError,"Unknownvolumecmd",false);
- }
- if(!rc){
- cli->sendMsg(ResponseCode::CommandOkay,"volumeoperationsucceeded",false);
- }else{
- interno=errno;
- rc=ResponseCode::convertFromErrno();
- cli->sendMsg(rc,"volumeoperationfailed",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;
- }
- return<spanstyle="color:#ff0000;">v->mountVol();
- </span>}
- intVolumeManager::mountVolume(constchar*label){
- Volume*v=lookupVolume(label);
- if(!v){
- errno=ENOENT;
- return-1;
- }
- return<spanstyle="color:#ff0000;">v->mountVol();
- </span>}
10.真正的挂载者
Volume::mountVol()
//代码路径:AndroidSourcecode2.3/system/vold/Volume.cpp
//SD卡的挂载最终是在该方法中实现的,如果挂载有异常,也会在该方法的执行过程通过setState方法发出广播。
- intVolume::mountVol(){
- dev_tdeviceNodes[4];
- intn,i,rc=0;
- charerrmsg[255];
- if(getState()==Volume::State_NoMedia){
- snprintf(errmsg,sizeof(errmsg),
- "Volume%s%smountfailed-nomedia",
- 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("Volumeisidlebutappearstobemounted-fixing");
- setState(Volume::State_Mounted);
- return0;
- }
- n=getDeviceNodes((dev_t*)&deviceNodes,4);
- if(!n){
- SLOGE("Failedtogetdevicenodes(%s)\n",strerror(errno));
- return-1;
- }
- for(i=0;i<n;i++){
- chardevicePath[255];
- sprintf(devicePath,"/dev/block/vold/%d:%d",MAJOR(deviceNodes[i]),
- MINOR(deviceNodes[i]));
- SLOGI("%sbeingconsideredforvolume%s\n",devicePath,getLabel());
- errno=0;
- setState(Volume::State_Checking);
- if(Fat::check(devicePath)){
- if(errno==ENODATA){
- SLOGW("%sdoesnotcontainaFATfilesystem\n",devicePath);
- continue;
- }
- errno=EIO;
- SLOGE("%sfailedFSchecks(%s)",devicePath,strerror(errno));
- setState(Volume::State_Idle);
- return-1;
- }
- errno=0;
- if(Fat::doMount(devicePath,"/mnt/secure/staging",false,false,false,
- 1000,1015,0702,true)){
- SLOGE("%sfailedtomountviaVFAT(%s)\n",devicePath,strerror(errno));
- continue;
- }
- SLOGI("Device%s,target%smounted@/mnt/secure/staging",devicePath,getMountpoint());
- protectFromAutorunStupidity();
- if(createBindMounts()){
- SLOGE("Failedtocreatebindmounts(%s)",strerror(errno));
- umount("/mnt/secure/staging");
- setState(Volume::State_Idle);
- return-1;
- }
- if(doMoveMount("/mnt/secure/staging",getMountpoint(),false)){
- SLOGE("Failedtomovemount(%s)",strerror(errno));
- umount("/mnt/secure/staging");
- setState(Volume::State_Idle);
- return-1;
- }
- setState(Volume::State_Mounted);
- mCurrentlyMountedKdev=deviceNodes[i];
- return0;
- }
- SLOGE("Volume%sfoundnosuitabledevicesformounting:(\n",getLabel());
- setState(Volume::State_Idle);
- return-1;
- }
到这里SD卡的挂载基本上已经完成,但是我们的目的是理清一条从底向上的路线,因此我会继续向上分析。我会将这一点在下一篇博文《Android 2.3 SD卡挂载流程浅析(五)》中继续分析。
因为这些都是我个人的一些见解,因此不见得都正确,希望读者抱着怀疑的态度阅读。不过不是有句名言叫“大胆假设,小心求证”吗!如文中有错误,还恳请各位看官指正。
分享到:
相关推荐
Android23SD卡挂载流程浅析.docx
Android23SD卡挂载流程浅析.doc
本文档基于android4.2平台,sd卡热插拔在android层是如何传递消息
主要介绍了Android2.3实现SD卡与U盘自动挂载的方法,较为详细的分析了Android2.3实现SD卡与U盘自动挂载的具体步骤与相关技巧,需要的朋友可以参考下
但是每款定制过的android 系统的外置SD卡的路径都不一样,那我们怎么才能去获取这个路径呢,我们可以想其它的办法,我这里提供了一个类可以获取外置SD卡或内置SD卡的 label(名称),path(路径),mount_point(挂载点)...
本文实例讲述了Android判断SD卡是否已经挂载的方法。分享给大家供大家参考。具体如下: 提供一个监听方法BroadcastReceiver 设置IntentFilter为: Intent.ACTION_MEDIA_MOUNTED Intent.ACTION_MEDIA_EJECT Intent....
AndroidStudio编写
SD卡任意挂载工具
SD卡挂载高歌好用
android 内部存储 sd卡app私有文件 等
android读取sd卡中MP3文件
在ubuntu系统中1、 查看sd卡名字,2、挂在sd卡,3、 查看sd卡内容,
这是一个修改自内核的SD driver 模块 :linux3.4.2 SD/MMC/TF卡挂载问题的解决
android 读取和存储sd卡一个例子,欢迎下载!
Android手机SD卡文件浏览器:遍历出手机Sd卡中的文件。
android 读取外置和内置存储卡路径和大小,亲测好使,项目中以运用
在Android N上并没有提供直接的方法获取外置SD卡或挂载U盘路径,可以通过下面方法获取内置sd卡路径 Environment.getExternalStorageDirectory().getAbsolutePath(); 通过查看getExternalStorageDirectory源码发现,...