`
yidongkaifa
  • 浏览: 4060759 次
文章分类
社区版块
存档分类
最新评论

Android-vold源码分析之startListener

 
阅读更多
vold处理完磁盘事件,就要开始接受framework的操作命令,在main函数里面,开启了一个线程来监听framework的信息,当收到操作命令,vold进行解析,分析出命令,然后调用相应的磁盘操作函数,待操作完成后,再将操作结果的状态值反馈给framework,中间均使用了广播机制,使用了UDP协议。

在main函数中,有以下函数的调用:

  1. if(cl->startListener()){
  2. SLOGE("UnabletostartCommandListener(%s)",strerror(errno));
  3. exit(1);
  4. }
cl是CommandListener类实例化的一个对象,该对象专门负责与framework的通信,首先说明与CommandListener类相关的一些继承关系。
CommandListener --> FrameworkListener --> SocketListener(父类)
在CommandListener类中,声明了6个类,这6个类继承了VoldCommand类,VoldCommand类继承了FrameworkCommand,关系如下:
VoldCommand --> FrameworkCommand(父类)
以下是CommandListener类的声明:

  1. classCommandListener:publicFrameworkListener{
  2. public:
  3. CommandListener();
  4. virtual~CommandListener(){}
  5. private:
  6. staticvoiddumpArgs(intargc,char**argv,intargObscure);
  7. classDumpCmd:publicVoldCommand{
  8. public:
  9. DumpCmd();
  10. virtual~DumpCmd(){}
  11. intrunCommand(SocketClient*c,intargc,char**argv);
  12. };
  13. classVolumeCmd:publicVoldCommand{
  14. public:
  15. VolumeCmd();
  16. virtual~VolumeCmd(){}
  17. intrunCommand(SocketClient*c,intargc,char**argv);
  18. };
  19. classShareCmd:publicVoldCommand{
  20. public:
  21. ShareCmd();
  22. virtual~ShareCmd(){}
  23. intrunCommand(SocketClient*c,intargc,char**argv);
  24. };
  25. classAsecCmd:publicVoldCommand{
  26. public:
  27. AsecCmd();
  28. virtual~AsecCmd(){}
  29. intrunCommand(SocketClient*c,intargc,char**argv);
  30. };
  31. classStorageCmd:publicVoldCommand{
  32. public:
  33. StorageCmd();
  34. virtual~StorageCmd(){}
  35. intrunCommand(SocketClient*c,intargc,char**argv);
  36. };
  37. classXwarpCmd:publicVoldCommand{
  38. public:
  39. XwarpCmd();
  40. virtual~XwarpCmd(){}
  41. intrunCommand(SocketClient*c,intargc,char**argv);
  42. };
  43. };
在这个类中,VoldCommand主要写了一个纯虚函数runCommand,声明如下:
virtual int runCommand(SocketClient *c, int argc, char **argv) = 0;
为了就是在CommandListener类中的实现,这里总共实现了6个版本的runCommand函数,下一篇文章只讨论其中一个比较重要的VolumeCmd类的实现,其余的跟这个类的实现差不多。
开始深入startListener线程:
进入startListener函数,创建了以下线程:

  1. if(pthread_create(&mThread,NULL,SocketListener::threadStart,this)){
  2. SLOGE("pthread_create(%s)",strerror(errno));
  3. return-1;
  4. }
这里跟前几章线程的创建几乎一样,

  1. void*SocketListener::threadStart(void*obj){
  2. SocketListener*me=reinterpret_cast<SocketListener*>(obj);
  3. me->runListener();
  4. pthread_exit(NULL);
  5. returnNULL;
  6. }
线程真正实现的函数在这里:

  1. voidSocketListener::runListener(){
  2. while(1){
  3. SocketClientCollection::iteratorit;
  4. fd_setread_fds;
  5. intrc=0;
  6. intmax=0;
  7. FD_ZERO(&read_fds);
  8. if(mListen){
  9. max=mSock;
  10. FD_SET(mSock,&read_fds);
  11. }
  12. FD_SET(mCtrlPipe[0],&read_fds);
  13. if(mCtrlPipe[0]>max)
  14. max=mCtrlPipe[0];
  15. pthread_mutex_lock(&mClientsLock);
  16. for(it=mClients->begin();it!=mClients->end();++it){
  17. FD_SET((*it)->getSocket(),&read_fds);
  18. if((*it)->getSocket()>max)
  19. max=(*it)->getSocket();
  20. }
  21. pthread_mutex_unlock(&mClientsLock);
  22. if((rc=select(max+1,&read_fds,NULL,NULL,NULL))<0){
  23. SLOGE("selectfailed(%s)",strerror(errno));
  24. sleep(1);
  25. continue;
  26. }elseif(!rc)
  27. continue;
  28. if(FD_ISSET(mCtrlPipe[0],&read_fds))
  29. break;
  30. if(mListen&&FD_ISSET(mSock,&read_fds)){
  31. structsockaddraddr;
  32. socklen_talen=sizeof(addr);
  33. intc;
  34. if((c=accept(mSock,&addr,&alen))<0){
  35. SLOGE("acceptfailed(%s)",strerror(errno));
  36. sleep(1);
  37. continue;
  38. }
  39. pthread_mutex_lock(&mClientsLock);
  40. mClients->push_back(newSocketClient(c));
  41. pthread_mutex_unlock(&mClientsLock);
  42. }
  43. do{
  44. pthread_mutex_lock(&mClientsLock);
  45. for(it=mClients->begin();it!=mClients->end();++it){
  46. intfd=(*it)->getSocket();
  47. if(FD_ISSET(fd,&read_fds)){
  48. pthread_mutex_unlock(&mClientsLock);
  49. /*当收到framework的操作命令,执行该函数*/
  50. if(!onDataAvailable(*it)){
  51. close(fd);
  52. pthread_mutex_lock(&mClientsLock);
  53. delete*it;
  54. it=mClients->erase(it);
  55. pthread_mutex_unlock(&mClientsLock);
  56. }
  57. FD_CLR(fd,&read_fds);
  58. continue;
  59. }
  60. }
  61. pthread_mutex_unlock(&mClientsLock);
  62. }while(0);
  63. }
  64. }
将收到的命令交给onDataAvailable函数来处理,onDataAvailable函数是类的纯虚函数,在FrameworkListener类实现了该函数:

  1. boolFrameworkListener::onDataAvailable(SocketClient*c){
  2. charbuffer[255];
  3. intlen;
  4. if((len=read(c->getSocket(),buffer,sizeof(buffer)-1))<0){
  5. SLOGE("read()failed(%s)",strerror(errno));
  6. returnerrno;
  7. }elseif(!len)
  8. returnfalse;
  9. intoffset=0;
  10. inti;
  11. for(i=0;i<len;i++){
  12. if(buffer[i]=='\0'){
  13. /*命令的处理函数*/
  14. dispatchCommand(c,buffer+offset);
  15. offset=i+1;
  16. }
  17. }
  18. returntrue;
  19. }
dispatchCommand函数用来选择不同的分支函数,因为在类有6个分支的实现版本,包括DumpCmd,VolumeCmd,ShareCmd,AsecCmd,StorageCmd和XwarpCmd。以下是dispatchCommand函数的源码:

  1. voidFrameworkListener::dispatchCommand(SocketClient*cli,char*data){
  2. FrameworkCommandCollection::iteratori;
  3. intargc=0;
  4. /*staticconstintCMD_ARGS_MAX=16;
  5. 说明framework发送的命令最多只能容纳16个子串*/
  6. char*argv[FrameworkListener::CMD_ARGS_MAX];
  7. /*中间省略了字符串的处理部分,将每个子串保存到了argv数组中,
  8. 所以在out标记的位置,对argv[i]的数组进行释放,
  9. 因为使用了strdup函数复制字符串*/
  10. /*下面这个循环用来循环选择不同的分支实现函数,
  11. mCommands容器保存着6个新声明的类对象*/
  12. for(i=mCommands->begin();i!=mCommands->end();++i){
  13. FrameworkCommand*c=*i;
  14. /*当第一个参数与FrameworkCommand类中的mCommand参数相等时,
  15. 才去调用该对象新实现的runCommand函数*/
  16. if(!strcmp(argv[0],c->getCommand())){
  17. if(c->runCommand(cli,argc,argv)){
  18. SLOGW("Handler'%s'error(%s)",c->getCommand(),strerror(errno));
  19. }
  20. gotoout;
  21. }
  22. }
  23. cli->sendMsg(500,"Commandnotrecognized",false);
  24. out:
  25. intj;
  26. for(j=0;j<argc;j++)
  27. free(argv[j]);
  28. return;
  29. }
这里从代码可能有点疑问,这个循环为什么可以选择不同的分支新实现的函数呢?
仔细看下代码会发现,在FrameworkListener中有一个注册函数,将新的派生类的名字注册到mCommands容器中,每个类的mCommand参数各代表一个派生类的名字。

  1. voidFrameworkListener::registerCmd(FrameworkCommand*cmd){
  2. mCommands->push_back(cmd);
  3. }
在CommandListener类的构造函数中,分别对6个分支的派生类进行了注册,每次注册都实例化了一个新的对象存放到mCommands容器中。

  1. CommandListener::CommandListener():
  2. FrameworkListener("vold"){
  3. registerCmd(newDumpCmd());
  4. registerCmd(newVolumeCmd());
  5. registerCmd(newAsecCmd());
  6. registerCmd(newShareCmd());
  7. registerCmd(newStorageCmd());
  8. registerCmd(newXwarpCmd());
  9. }
那这6个派生类的名称保存在FrameworkCommand类的一个私有变量mCommand中,该类的构造函数就是给mCommand赋值,源码:

  1. FrameworkCommand::FrameworkCommand(constchar*cmd){
  2. mCommand=cmd;
  3. }
在刚才的FrameworkListener::dispatchCommand函数里,有这么一个比较:

  1. if(!strcmp(argv[0],c->getCommand())){}
getCommand函数的源码:

  1. constchar*getCommand(){returnmCommand;}

这里来看mCommand的赋值,我们知道以下关系:
DumpCmd --> VoldCommand --> FrameworkCommand
VolumeCmd --> VoldCommand --> FrameworkCommand
ShareCmd --> VoldCommand --> FrameworkCommand
AsecCmd --> VoldCommand --> FrameworkCommand
StorageCmd --> VoldCommand --> FrameworkCommand
XwarpCmd --> VoldCommand --> FrameworkCommand
所以在CommandListener类中的6个派生类中的构造函数中,必须初始化const char *cmd这个参数,以下是初始化代码:

  1. CommandListener::DumpCmd::DumpCmd():
  2. VoldCommand("dump"){
  3. }
  4. CommandListener::VolumeCmd::VolumeCmd():
  5. VoldCommand("volume"){
  6. }
  7. CommandListener::ShareCmd::ShareCmd():
  8. VoldCommand("share"){
  9. }
  10. CommandListener::StorageCmd::StorageCmd():
  11. VoldCommand("storage"){
  12. }
  13. CommandListener::AsecCmd::AsecCmd():
  14. VoldCommand("asec"){
  15. }
  16. CommandListener::XwarpCmd::XwarpCmd():
  17. VoldCommand("xwarp"){
  18. }

6个构造函数均初始化不同的cmd参数,分别为dump,volume,share,storage,asec,xwarp。
在VoldCommand类的构造函数中,将cmd的值初始化FrameworkCommand类的构造函数。

  1. VoldCommand::VoldCommand(constchar*cmd):
  2. FrameworkCommand(cmd){
  3. }

所以这个比较,就是将framework发下来的命令的第一个参数与mCommands容器中的6个对象的mCommand参数进行了比较,从而选择正确的处理分支函数。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics