一、Android热插拔事件处理流程图

Android热插拔事件处理流程如下图所示:

二、组成

1. NetlinkManager:
全称是NetlinkManager.cpp位于Android 4.x 源码位置/system/vold/NetlinkManager.cpp。该类的主要通过引用NetlinkHandler类中的onEvent()方法来接收来自内核的事件消息,NetlinkHandler位于/system/vold/NetlinkHandler.cpp。

2. VolumeManager:
全称是VolumeManager.cpp位于Android 4.x源码位置/system/vold/VolumeManager.cpp。该类的主要作用是接收经过NetlinkManager处理过后的事件消息。因为我们这里是SD的挂载,因此经过NetlinkManager处理过后的消息会分为五种,分别是:block,switch,usb_composite,battery,power_supply。这里SD卡挂载的事件是block。

3. DirectVolume:
位于/system/vold/DirectVolume.cpp。该类的是一个工具类,主要负责对传入的事件进行进一步的处理,block事件又可以分为:Add,Removed,Change,Noaction这四种。后文通过介绍Add事件展开。

4. Volume:
位于/system/vold/Volume.cpp,该类是负责SD卡挂载的主要类。Volume.cpp主要负责检查SD卡格式,以及对复合要求的SD卡进行挂载,并通过Socket将消息SD卡挂载的消息传递给NativeDaemonConnector。

5. CommandListener:
该类位于位于/system/vold/CommandListener.cpp。通过vold socket与NativeDaemonConnector通信。

6. NativeDaemonConnector:
该类位于frameworks/base/services/java/com.android.server/NativeDaemonConnector.java。该类用于接收来自Volume.cpp 发来的SD卡挂载消息并向上传递。

7. MountService:
位于frameworks/base/services/java/com.android.server/MountService.java。MountService是一个服务类,该服务是系统服务,提供对外部存储设备的管理、查询等。在外部存储设备状态发生变化的时候,该类会发出相应的通知给上层应用。在Android系统中这是一个非常重要的类。

8.StorageManaer:
位于frameworks/base/core/java/andriod/os/storage/StorageManager.java。在该类的说明中有提到,该类是系统存储服务的接口。在系统设置中,有Storage相关项,同时Setting也注册了该类的监听器。而StorageManager又将自己的监听器注册到了MountService中,因此该类主要用于上层应用获取SD卡状态。

三、典型流程描述 (SD卡挂载流程)

整个过程从Kernel检测到SD卡插入事件开始,之前的一些硬件中断的触发以及driver的加载这里并不叙述,一直到SD卡挂载消息更新到“Android——系统设置——存储”一项中。
1. Kernel发出SD卡插入uevent。
2. NetlinkHandler::onEvent()接收内核发出的uevent并进行解析
3. VolumeManager::handlBlockEvent()处理经过第二步处理后的事件。
4. 接下来调用DirectVolume:: handleBlockEvent()。
在该方法中主要有两点需要注意:
第一,程序首先会遍历mPath容器,寻找与event对应的sysfs_path是否存在与mPath容器中。
第二,针对event中的action有4种处理方式:Add,Removed,Change,Noaction 。
例如:在Add action中会有如下操作(因为我们这里所讲的是SD卡的挂载流程,因此以Add来说明),首先创建设备节点,其次对disk和partition两种格式的设备分别进行处理。SD卡属于disk类型。
5. 经过上一步之后会调用DirectVolume::handleDiskAdded()方法,在该方法中会广播disk insert消息。
6. SocketListener::runListener会接收DirectVolume::handleDiskAdded()广播的消息。该方法主要完成对event中数据的获取,通过Socket。(PS:这里的SocketListener.cpp位于Android源码/system/core/libsysutils/src/中,后文的FramworkListener.cpp也是,之前自己找了很久 T_T)
7. 调用FrameworkListener::onDataAvailable()方法处理接收到的消息内容。
8. FrameworkListener::dispatchCommand()该方法用于分发指令。
9. 在FrameworkListener::dispatchCommand()方法中,通过runCommand()方法去调用相应的指令。
10. 在/system/vold/CommandListener.cpp中有runCommand()的具体实现。在该类中可以找到这个方法:CommandListener::VolumeCmd::runCommand(),从字面意思上来看这个方法就是对Volume分发指令的解析。该方法中会执行“mount”函数:vm->mountVolume(arg[2])。
11. mountVolume(arg[2])在VolumeManager::mountVolume()中实现,在该方法中调用v->mountVol()。
12. mountVol()方法在Volume::mountVol()中实现,该函数是真正的挂载函数。(在该方法中,后续的处理都在该方法中,在Mount过程中会广播相应的消息给上层,通过setState()函数。)
13. setState(Volume::Checking);广播给上层,正在检查SD卡,为挂载做准备。
14. Fat::check();SD卡检查方法,检查SD卡是否是FAT格式。
15. Fat::doMount()挂载SD卡。
至此,SD的挂载已算初步完成,接下来应该将SD卡挂载后的消息发送给上层,在13中也提到过,在挂载以及检查的过程中其实也有发送消息给上层的。
16. MountService的构造函数中会开启监听线程,用于监听来自vold的socket信息。
Thread thread = new Thread(mConnector,VOLD_TAG); thread.start();
17. mConnector是NativeDaemonConnector的对象,NativeDaemonConnector继承了Runnable并Override了run方法。在run方法中通过一个while(true)调用ListenToSocket()方法来实现实时监听。
18. 在ListenToSocket()中,首先建立与Vold通信的Socket Server端,然后调用MountService中的onDaemonConnected()方法。(PS:Java与Native通信可以通过JNI,那么Native与Java通信就需要通过Socket来实现了。Android中Native与Frameworks通信 这篇文章中有简介,感兴趣的朋友可以参考一下)
19. onDaemonConnected()方法是在接口INativeDaemonConnectorCallbacks中定义的,MountService实现了该接口并Override了onDaemonConnected()方法。该方法开启一个线程用于更新外置存储设备的状态,主要更新状态的方法也在其中实现。
20. 然后回到ListenToSocket中,通过inputStream来获取Vold传递来的event,并存放在队列中。
21. 然后这些event会在onDaemonConnected()通过队列的”队列.take()”方法取出。并根据不同的event调用updatePublicVolumeState()方法,在该方法中调用packageManagerService中的updateExteralState()方法来更新存储设备的状态。(注:这里不太理解packageManagerService中的unloadAllContainers(args)方法)
22. 更新是通过packageHelper.getMountService().finishMediaUpdate()方法来实现的。
23. 在updatePublicVolumeState()方法中,更新后会执行如下代码:
bl.mListener.onStorageStateChanged();
在Android源码/packages/apps/Settings/src/com.android.settings.deviceinfo/Memory.java代码中,实现了StorageEventListener 的匿名内部类,并Override了onStorageStateChanged();方法。因此在updatePublicVolumeState()中调用onStorageStateChanged();方法后,Memory.java中也会收到。在Memory.java中收到以后会在Setting界面进行更新,系统设置——存储中会更新SD卡的状态。从而SD卡的挂载从底层到达了上层。

四、Vold

1. Vold简介

Vold的全称是volume daemon。主要负责系统对大容量存储设备(USB/SD)的挂载/卸载任务,它是一个守护进程,该进程支持这些存储外设的热插拔。自Android 2.2开始,Vold升级为vold 2.0,配置文件路径在Android 4.0之后变为/etc/vold.fstab。

2.Vold工作流程

Vold的工作流程大致可以分为三个部分:创建监听、引导、事件处理。

(1)创建监听

创建监听指的是创建监听链接,一方面用于监听来自内核的uevent,另一方面用于监听来自上层的控制命令,这些命令包括控制SD卡的挂载与卸载,这里所说的链接也就是socket。在Android 系统启动的时候,init进程会去解析init.rc文件,在该文件中,有如下代码:

Service vold /system/bin/vold
Socket vold stream 0660 root mount
Iprio be 2

这样系统会在启动的时候创建与上层通信的socket,此socket name为"vold"。

在Android 4.0源码/system/vold路径下的main.cpp<NetlinkManager::start():socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT) >中创建了与内核通信的socket。在main.cpp中通过实例化VolumeManager和NetlinkManager时创建。

(2)引导

Vold进程启动时候会对现有的外部存储设备进行检查。首先加载并解析vold.fstab,并检查挂载点是否已被挂载。然后执行SD卡的挂载,最后处理USB大容量存储。因为系统是按行解析的,通过查看vold.fstab可以很清楚的知道这一点。
vold.fatab中最重要的语句:

dev_mount sdcard /mnt/sdcard auto /devices/platform/rk29_sdmmc.0/mmc_host/mmc0
dev_mount <lable> <mount_point> <part> <sysfs_path…>
挂载命令 标签 挂载点第几个分区 设备的sysfs paths
注:
第几个分区:如果为auto则表示第1个分区。
参数之间不能有空格,只能以tab为间隔(注意:这里为了对齐因此采用空格隔开,如果自行修改vold.fstab之后加以空格的话系统会识别不到的)。
如果vold.fstab解析无误,VolueManager将创建DirectVolume,若vold.fstab解析不存在或者打开失败,Vold将会读取Linux内核中的参数,此时如果参数中存在SDCARD(也就是SD的默认路径),VolumeManager则会创建AutoVolume,如果不存在这个默认路径那么就不会创建。

(3)事件处理

通过对两个socket的监听,完成对事件的处理以及对上层应用的响应。

a) Kernel发出uevent
NetlinkManager检测到kernel发出的uevent,解析后调用NetlinkHandler::onEvent()方法。该方法会分别处理不同的事件,这里重要的事件有:
“block”事件主要指Volume的mount、unmount、createAsec等。由VolumeManager的handleBlockEvent(evt)来处理,根据多态性最终将会调用AutoVolume或者DirectVolume的handleBlockEvent方法来处理。
“switch”事件主要指Volume的connet、disconnet等。根据相关操作,改变设备参数(设备类型、挂载点等)通过CommandListener告知FrameWork层。

b)FrameWork发出控制命令
与a)相反,CommandListener检测到FrameWork层的命令(MountService发出的命令)调用VolumeManager的函数,VolumeManager找出对应的Volume,调用Volume函数去挂载/卸载操作。而Volume类中的相关操作最终通过调用Linux函数完成。

五、Vold用户态

1. NetlinkManager

NetlinkManager负责与Kernel交互,通过PF_NETLINK来现。

Vlod启动代码如下(/system/vold/main.cpp):

[cpp] view plain copy
  1. intmain(){
  2. VolumeManager*vm;
  3. CommandListener*cl;
  4. NetlinkManager*nm;
  5. SLOGI("Vold2.1(therevenge)firingup");
  6. mkdir("/dev/block/vold",0755);
  7. /*Createoursingletonmanagers*/
  8. if(!(vm=VolumeManager::Instance())){
  9. SLOGE("UnabletocreateVolumeManager");
  10. exit(1);
  11. };
  12. if(!(nm=NetlinkManager::Instance())){
  13. SLOGE("UnabletocreateNetlinkManager");
  14. exit(1);
  15. };
  16. cl=newCommandListener();
  17. vm->setBroadcaster((SocketListener*)cl);
  18. nm->setBroadcaster((SocketListener*)cl);
  19. if(vm->start()){
  20. SLOGE("UnabletostartVolumeManager(%s)",strerror(errno));
  21. exit(1);
  22. }
  23. /*解析/etc/vold.fstab文件,
  24. 读取type,label,mount_point,part
  25. 1)构建DirectVolume对象:如果part为auto,则调用dv=newDirectVolume(vm,label,mount_point,-1);
  26. 2)添加vold.fstab中定义的某一挂载项对应的sysfs_path到DirectVolume对象的mPaths容器dv->addPath(sysfs_path);
  27. 3)将这个DirectVolume对象添加到VolumeManager对象的容器mVolumes中vm->addVolume(dv);
  28. */
  29. if(process_config(vm)){
  30. SLOGE("Errorreadingconfiguration(%s)...continuinganyways",strerror(errno));
  31. }
  32. /*会调用NetlinkManager类的start()方法,它创建PF_NETLINKsocket,
  33. 并开启线程从此socket中读取数据*/
  34. if(nm->start()){
  35. SLOGE("UnabletostartNetlinkManager(%s)",strerror(errno));
  36. exit(1);
  37. }
  38. #ifdefUSE_USB_MODE_SWITCH
  39. SLOGE("StartMiscdevicesManager...");
  40. MiscManager*mm;
  41. if(!(mm=MiscManager::Instance())){
  42. SLOGE("UnabletocreateMiscManager");
  43. exit(1);
  44. };
  45. mm->setBroadcaster((SocketListener*)cl);
  46. if(mm->start()){
  47. SLOGE("UnabletostartMiscManager(%s)",strerror(errno));
  48. exit(1);
  49. }
  50. G3Dev*g3=newG3Dev(mm);
  51. g3->handleUsb();
  52. mm->addMisc(g3);
  53. #endif
  54. coldboot("/sys/block");//冷启动,vold错过了一些uevent,重新触发。向sysfs的uevent文件写入”add\n”字符也可以触发sysfs事件,相当执行了一次热插拔。
  55. //coldboot("/sys/class/switch");
  56. /*
  57. *Nowthatwe'reup,wecanrespondtocommands
  58. */
  59. if(cl->startListener()){
  60. SLOGE("UnabletostartCommandListener(%s)",strerror(errno));
  61. exit(1);
  62. }
  63. //Eventuallywe'llbecomethemonitoringthread
  64. while(1){
  65. sleep(1000);
  66. }
  67. SLOGI("Voldexiting");
  68. exit(0);
  69. }

NetlinkManager的家族关系如下所示:

上图中的虚线为启动是的调用流程。
(1) class NetlinkManager(在其start函数中创建了NetlinkHandler对象,并把创建的socket作为参数)

(2)class NetlinkHandler: public NetlinkListener(实现了onEvent)
(3) class NetlinkListener : public SocketListener (实现了onDataAvailable)
(4) class SocketListener(实现了runListener,在一个线程中通过select查看哪些socket有数据,通过调用onDataAvailable来读取数据)

2. NetlinkManager::start()

[cpp] view plain copy
  1. intNetlinkManager::start(){
  2. structsockaddr_nlnladdr;
  3. intsz=64*1024;
  4. inton=1;
  5. memset(&nladdr,0,sizeof(nladdr));
  6. nladdr.nl_family=AF_NETLINK;
  7. nladdr.nl_pid=getpid();
  8. nladdr.nl_groups=0xffffffff;
  9. //创建一个socket用于内核空间和用户空间的异步通信,监控系统的hotplug事件
  10. if((mSock=socket(PF_NETLINK,
  11. SOCK_DGRAM,NETLINK_KOBJECT_UEVENT))<0){
  12. SLOGE("Unabletocreateueventsocket:%s",strerror(errno));
  13. return-1;
  14. }
  15. if(setsockopt(mSock,SOL_SOCKET,SO_RCVBUFFORCE,&sz,sizeof(sz))<0){
  16. SLOGE("UnabletosetueventsocketSO_RECBUFFORCEoption:%s",strerror(errno));
  17. return-1;
  18. }
  19. if(setsockopt(mSock,SOL_SOCKET,SO_PASSCRED,&on,sizeof(on))<0){
  20. SLOGE("UnabletosetueventsocketSO_PASSCREDoption:%s",strerror(errno));
  21. return-1;
  22. }
  23. if(bind(mSock,(structsockaddr*)&nladdr,sizeof(nladdr))<0){
  24. SLOGE("Unabletobindueventsocket:%s",strerror(errno));
  25. return-1;
  26. }
  27. //利用新创建的socket实例化一个NetlinkHandler类对象,NetlinkHandler继承了类NetlinkListener,
  28. //NetlinkListener又继承了类SocketListener
  29. mHandler=newNetlinkHandler(mSock);
  30. if(mHandler->start()){//启动NetlinkHandler
  31. SLOGE("UnabletostartNetlinkHandler:%s",strerror(errno));
  32. return-1;
  33. }
  34. return0;
  35. }



socket作为参数创建了NetlinkHandler对象,然后启动NetlinkHandler。

[cpp] view plain copy
  1. intNetlinkHandler::start(){
  2. returnthis->startListener();
  3. }
  4. intSocketListener::startListener(){
  5. if(!mSocketName&&mSock==-1){
  6. SLOGE("Failedtostartunboundlistener");
  7. errno=EINVAL;
  8. return-1;
  9. }elseif(mSocketName){
  10. if((mSock=android_get_control_socket(mSocketName))<0){
  11. SLOGE("Obtainingfiledescriptorsocket'%s'failed:%s",
  12. mSocketName,strerror(errno));
  13. return-1;
  14. }
  15. }
  16. if(mListen&&listen(mSock,4)<0){
  17. SLOGE("Unabletolistenonsocket(%s)",strerror(errno));
  18. return-1;
  19. }elseif(!mListen)
  20. mClients->push_back(newSocketClient(mSock,false));
  21. if(pipe(mCtrlPipe)){
  22. SLOGE("pipefailed(%s)",strerror(errno));
  23. return-1;
  24. }
  25. if(pthread_create(&mThread,NULL,SocketListener::threadStart,this)){
  26. SLOGE("pthread_create(%s)",strerror(errno));
  27. return-1;
  28. }
  29. return0;
  30. }
  31. void*SocketListener::threadStart(void*obj){
  32. SocketListener*me=reinterpret_cast<SocketListener*>(obj);
  33. me->runListener();
  34. pthread_exit(NULL);
  35. returnNULL;
  36. }
  37. voidSocketListener::runListener(){
  38. SocketClientCollection*pendingList=newSocketClientCollection();
  39. while(1){//死循环,一直监听
  40. SocketClientCollection::iteratorit;
  41. fd_setread_fds;
  42. intrc=0;
  43. intmax=-1;
  44. FD_ZERO(&read_fds);//清空文件描述符集read_fds
  45. if(mListen){
  46. max=mSock;
  47. FD_SET(mSock,&read_fds);//添加文件描述符到文件描述符集read_fds
  48. }
  49. FD_SET(mCtrlPipe[0],&read_fds);//添加管道的读取端文件描述符到read_fds
  50. if(mCtrlPipe[0]>max)
  51. max=mCtrlPipe[0];
  52. pthread_mutex_lock(&mClientsLock);//对容器mClients的操作需要加锁
  53. for(it=mClients->begin();it!=mClients->end();++it){
  54. intfd=(*it)->getSocket();
  55. FD_SET(fd,&read_fds);////遍历容器mClients的所有成员,调用内联函数getSocket()获取文件描述符,并添加到文件描述符集read_fds
  56. if(fd>max)
  57. max=fd;
  58. }
  59. pthread_mutex_unlock(&mClientsLock);
  60. //等待文件描述符中某一文件描述符或者说socket有数据到来
  61. if((rc=select(max+1,&read_fds,NULL,NULL,NULL))<0){
  62. if(errno==EINTR)
  63. continue;
  64. SLOGE("selectfailed(%s)",strerror(errno));
  65. sleep(1);
  66. continue;
  67. }elseif(!rc)
  68. continue;
  69. if(FD_ISSET(mCtrlPipe[0],&read_fds))
  70. break;
  71. if(mListen&&FD_ISSET(mSock,&read_fds)){//监听套接字处理
  72. structsockaddraddr;
  73. socklen_talen;
  74. intc;
  75. do{
  76. alen=sizeof(addr);
  77. c=accept(mSock,&addr,&alen);//接收链接请求,建立连接,如果成功c即为建立链接后的数据交换套接字,将其添加到mClient容器
  78. }while(c<0&&errno==EINTR);
  79. if(c<0){
  80. SLOGE("acceptfailed(%s)",strerror(errno));
  81. sleep(1);
  82. continue;
  83. }
  84. pthread_mutex_lock(&mClientsLock);
  85. mClients->push_back(newSocketClient(c,true));
  86. pthread_mutex_unlock(&mClientsLock);
  87. }
  88. /*Addallactiveclientstothependinglistfirst*/
  89. pendingList->clear();
  90. pthread_mutex_lock(&mClientsLock);
  91. for(it=mClients->begin();it!=mClients->end();++it){
  92. intfd=(*it)->getSocket();
  93. if(FD_ISSET(fd,&read_fds)){
  94. pendingList->push_back(*it);
  95. }
  96. }
  97. pthread_mutex_unlock(&mClientsLock);
  98. /*Processthependinglist,sinceitisownedbythethread,
  99. *thereisnoneedtolockit*/
  100. while(!pendingList->empty()){//非监听套接字处理
  101. /*Popthefirstitemfromthelist*/
  102. it=pendingList->begin();
  103. SocketClient*c=*it;
  104. pendingList->erase(it);
  105. /*Processit,iffalseisreturnedandoursocketsare
  106. *connection-based,removeanddestroyit*/
  107. //******onDataAvailable在NetlinkListener中实现*********
  108. if(!onDataAvailable(c)&&mListen){
  109. /*Removetheclientfromourarray*/
  110. pthread_mutex_lock(&mClientsLock);
  111. for(it=mClients->begin();it!=mClients->end();++it){
  112. if(*it==c){
  113. mClients->erase(it);
  114. break;
  115. }
  116. }
  117. pthread_mutex_unlock(&mClientsLock);
  118. /*Removeourreferencetotheclient*/
  119. c->decRef();
  120. }
  121. }
  122. }
  123. deletependingList;
  124. }

SocketListener::runListener是线程真正执行的函数:mListen成员用来判定是否监听套接字,Netlink套接字属于udp套接字,非监听套接字,该函数的主要功能体现在,如果该套接字有数据到来,就调用函数onDataAvailable读取数据。

3. NetlinkListener::onDataAvailable

[cpp] view plain copy
  1. boolNetlinkListener::onDataAvailable(SocketClient*cli)
  2. {
  3. intsocket=cli->getSocket();
  4. ssize_tcount;
  5. //从socket中读取kernel发送来的uevent消息
  6. count=TEMP_FAILURE_RETRY(uevent_kernel_multicast_recv(socket,mBuffer,sizeof(mBuffer)));
  7. if(count<0){
  8. SLOGE("recvmsgfailed(%s)",strerror(errno));
  9. returnfalse;
  10. }
  11. NetlinkEvent*evt=newNetlinkEvent();
  12. if(!evt->decode(mBuffer,count,mFormat)){
  13. SLOGE("ErrordecodingNetlinkEvent");
  14. }else{
  15. onEvent(evt);//在NetlinkHandler中实现
  16. }
  17. deleteevt;
  18. returntrue;
  19. }

4. NetlinkHandler::onEvent

[cpp] view plain copy
  1. voidNetlinkHandler::onEvent(NetlinkEvent*evt){
  2. VolumeManager*vm=VolumeManager::Instance();
  3. constchar*subsys=evt->getSubsystem();
  4. if(!subsys){
  5. SLOGW("Nosubsystemfoundinnetlinkevent");
  6. return;
  7. }
  8. if(!strcmp(subsys,"block")){
  9. if(uEventOnOffFlag)
  10. {
  11. SLOGW("####netlinkeventblock####");
  12. evt->dump();
  13. }
  14. vm->handleBlockEvent(evt);
  15. #ifdefUSE_USB_MODE_SWITCH
  16. }elseif(!strcmp(subsys,"usb")
  17. ||!strcmp(subsys,"scsi_device")){
  18. SLOGW("subsystemfoundinnetlinkevent");
  19. MiscManager*mm=MiscManager::Instance();
  20. mm->handleEvent(evt);
  21. #endif
  22. }
  23. }

5. uevent_kernel_multicast_recv

[cpp] view plain copy
  1. /**
  2. *Likerecv(),butchecksthatmessagesactuallyoriginatefromthekernel.
  3. */
  4. ssize_tuevent_kernel_multicast_recv(intsocket,void*buffer,size_tlength){
  5. structioveciov={buffer,length};
  6. structsockaddr_nladdr;
  7. charcontrol[CMSG_SPACE(sizeof(structucred))];
  8. structmsghdrhdr={
  9. &addr,
  10. sizeof(addr),
  11. &iov,
  12. 1,
  13. control,
  14. sizeof(control),
  15. 0,
  16. };
  17. ssize_tn=recvmsg(socket,&hdr,0);
  18. if(n<=0){
  19. returnn;
  20. }
  21. if(addr.nl_groups==0||addr.nl_pid!=0){
  22. /*ignoringnon-kernelorunicastnetlinkmessage*/
  23. gotoout;
  24. }
  25. structcmsghdr*cmsg=CMSG_FIRSTHDR(&hdr);
  26. if(cmsg==NULL||cmsg->cmsg_type!=SCM_CREDENTIALS){
  27. /*ignoringnetlinkmessagewithnosendercredentials*/
  28. gotoout;
  29. }
  30. structucred*cred=(structucred*)CMSG_DATA(cmsg);
  31. if(cred->uid!=0){
  32. /*ignoringnetlinkmessagefromnon-rootuser*/
  33. gotoout;
  34. }
  35. returnn;
  36. out:
  37. /*clearresidualpotentiallymaliciousdata*/
  38. bzero(buffer,length);
  39. errno=EIO;
  40. return-1;
  41. }


六、与Vold相关的Kernel态

  • 用户态创建的netlink sock被kernel保存在:nl_table[sk->sk_protocol].mc_list
  • Kernel态创建的netlink sock被kernel保存在:uevent_sock_list,上面的sk->sk_protocol为uevent_sock_list的协议, 二者只有协议一致才可以发送。

1. 创建kernel态sock

  • 在用户态的socket创建方式(/system/vold/NetlinkManager.cpp):
[cpp] view plain copy
  1. if((mSock=socket(PF_NETLINK,
  2. SOCK_DGRAM,NETLINK_KOBJECT_UEVENT))<0){
  3. SLOGE("Unabletocreateueventsocket:%s",strerror(errno));
  4. return-1;
  5. }
  • 在Kernel的socket创建方式(/kernel/lib/kobject_uevent.c):
[cpp] view plain copy
  1. staticintuevent_net_init(structnet*net)
  2. {
  3. structuevent_sock*ue_sk;
  4. ue_sk=kzalloc(sizeof(*ue_sk),GFP_KERNEL);
  5. if(!ue_sk)
  6. return-ENOMEM;
  7. ue_sk->sk=netlink_kernel_create(net,NETLINK_KOBJECT_UEVENT,
  8. 1,NULL,NULL,THIS_MODULE);
  9. if(!ue_sk->sk){
  10. printk(KERN_ERR
  11. "kobject_uevent:unabletocreatenetlinksocket!\n");
  12. kfree(ue_sk);
  13. return-ENODEV;
  14. }
  15. mutex_lock(&uevent_sock_mutex);
  16. list_add_tail(&ue_sk->list,&uevent_sock_list);
  17. mutex_unlock(&uevent_sock_mutex);
  18. return0;
  19. }

从上面的代码可知,此sock被创建之后,被增加到全局变量uevent_sock_list列表中,下面的分析围绕此列表进行。

  • netlink_kernel_create函数原型:
[cpp] view plain copy
  1. structsock*netlink_kernel_create(structnet*net,intunit,unsignedintgroups,
  2. void(*input)(structsk_buff*skb),
  3. structmutex*cb_mutex,structmodule*module)

1) struct net *net:是一个网络名字空间namespace,在不同的名字空间里面可以有自己的转发信息库,有自己的一套net_device等等。默认情况下都是使用init_net这个全局变量

2) int unit: 表示netlink协议类型,如 NETLINK_KOBJECT_UEVENT

3)unsigned int groups: 组类型

4) void (*input)(struct sk_buff *skb):参数input则为内核模块定义的netlink消息处理函数,当有消息到达这个netlink socket时,该input函数指针就会被调用。函数指针input的参数skb实际上就是函数netlink_kernel_create返回的 struct sock指针,sock实际是socket的一个内核表示数据结构,用户态应用创建的socket在内核中也会有一个struct sock结构来表示。

5) struct mutex *cb_mutex: 互斥销

6) struct module *module: 一般为THIS_MODULE

  • struct sock

用户态socket在kernel中的表示。

2.相关数据结构

相关数据结构如下图所示:

3.发送消息给用户空间

3.1 发送消息流程图

3.2 kobject_uevent_env

[cpp] view plain copy
  1. /**
  2. *kobject_uevent_env-sendanueventwithenvironmentaldata
  3. *
  4. *@action:actionthatishappening
  5. *@kobj:structkobjectthattheactionishappeningto
  6. *@envp_ext:pointertoenvironmentaldata
  7. *
  8. *Returns0ifkobject_uevent_env()iscompletedwithsuccessorthe
  9. *correspondingerrorwhenitfails.
  10. */
  11. intkobject_uevent_env(structkobject*kobj,enumkobject_actionaction,
  12. char*envp_ext[])
  13. {
  14. structkobj_uevent_env*env;
  15. constchar*action_string=kobject_actions[action];
  16. constchar*devpath=NULL;
  17. constchar*subsystem;
  18. structkobject*top_kobj;
  19. structkset*kset;
  20. conststructkset_uevent_ops*uevent_ops;
  21. u64seq;
  22. inti=0;
  23. intretval=0;
  24. #ifdefCONFIG_NET
  25. structuevent_sock*ue_sk;
  26. #endif
  27. pr_debug("kobject:'%s'(%p):%s\n",
  28. kobject_name(kobj),kobj,__func__);
  29. /*searchtheksetwebelongto*/
  30. top_kobj=kobj;
  31. while(!top_kobj->kset&&top_kobj->parent)
  32. top_kobj=top_kobj->parent;
  33. if(!top_kobj->kset){
  34. pr_debug("kobject:'%s'(%p):%s:attemptedtosenduevent"
  35. "withoutkset!\n",kobject_name(kobj),kobj,
  36. __func__);
  37. return-EINVAL;
  38. }
  39. kset=top_kobj->kset;
  40. uevent_ops=kset->uevent_ops;
  41. /*skiptheevent,ifuevent_suppressisset*/
  42. if(kobj->uevent_suppress){
  43. pr_debug("kobject:'%s'(%p):%s:uevent_suppress"
  44. "causedtheeventtodrop!\n",
  45. kobject_name(kobj),kobj,__func__);
  46. return0;
  47. }
  48. /*skiptheevent,ifthefilterreturnszero.*/
  49. if(uevent_ops&&uevent_ops->filter)
  50. if(!uevent_ops->filter(kset,kobj)){
  51. pr_debug("kobject:'%s'(%p):%s:filterfunction"
  52. "causedtheeventtodrop!\n",
  53. kobject_name(kobj),kobj,__func__);
  54. return0;
  55. }
  56. /*originatingsubsystem*/
  57. if(uevent_ops&&uevent_ops->name)
  58. subsystem=uevent_ops->name(kset,kobj);
  59. else
  60. subsystem=kobject_name(&kset->kobj);
  61. if(!subsystem){
  62. pr_debug("kobject:'%s'(%p):%s:unsetsubsystemcausedthe"
  63. "eventtodrop!\n",kobject_name(kobj),kobj,
  64. __func__);
  65. return0;
  66. }
  67. /*environmentbuffer*/
  68. env=kzalloc(sizeof(structkobj_uevent_env),GFP_KERNEL);
  69. if(!env)
  70. return-ENOMEM;
  71. /*completeobjectpath*/
  72. devpath=kobject_get_path(kobj,GFP_KERNEL);
  73. if(!devpath){
  74. retval=-ENOENT;
  75. gotoexit;
  76. }
  77. /*defaultkeys*/
  78. retval=add_uevent_var(env,"ACTION=%s",action_string);
  79. if(retval)
  80. gotoexit;
  81. retval=add_uevent_var(env,"DEVPATH=%s",devpath);
  82. if(retval)
  83. gotoexit;
  84. retval=add_uevent_var(env,"SUBSYSTEM=%s",subsystem);
  85. if(retval)
  86. gotoexit;
  87. /*keyspassedinfromthecaller*/
  88. if(envp_ext){
  89. for(i=0;envp_ext[i];i++){
  90. retval=add_uevent_var(env,"%s",envp_ext[i]);
  91. if(retval)
  92. gotoexit;
  93. }
  94. }
  95. /*lettheksetspecificfunctionadditsstuff*/
  96. if(uevent_ops&&uevent_ops->uevent){
  97. retval=uevent_ops->uevent(kset,kobj,env);
  98. if(retval){
  99. pr_debug("kobject:'%s'(%p):%s:uevent()returned"
  100. "%d\n",kobject_name(kobj),kobj,
  101. __func__,retval);
  102. gotoexit;
  103. }
  104. }
  105. /*
  106. *Mark"add"and"remove"eventsintheobjecttoensureproper
  107. *eventstouserspaceduringautomaticcleanup.Iftheobjectdid
  108. *sendan"add"event,"remove"willautomaticallygeneratedby
  109. *thecore,ifnotalreadydonebythecaller.
  110. */
  111. if(action==KOBJ_ADD)
  112. kobj->state_add_uevent_sent=1;
  113. elseif(action==KOBJ_REMOVE)
  114. kobj->state_remove_uevent_sent=1;
  115. /*wewillsendanevent,sorequestanewsequencenumber*/
  116. spin_lock(&sequence_lock);
  117. seq=++uevent_seqnum;
  118. spin_unlock(&sequence_lock);
  119. retval=add_uevent_var(env,"SEQNUM=%llu",(unsignedlonglong)seq);
  120. if(retval)
  121. gotoexit;
  122. #ifdefined(CONFIG_NET)
  123. /*sendnetlinkmessage*/
  124. mutex_lock(&uevent_sock_mutex);
  125. list_for_each_entry(ue_sk,&uevent_sock_list,list){
  126. structsock*uevent_sock=ue_sk->sk;
  127. structsk_buff*skb;
  128. size_tlen;
  129. /*allocatemessagewiththemaximumpossiblesize*/
  130. len=strlen(action_string)+strlen(devpath)+2;
  131. skb=alloc_skb(len+env->buflen,GFP_KERNEL);
  132. if(skb){
  133. char*scratch;
  134. /*addheader*/
  135. scratch=skb_put(skb,len);
  136. sprintf(scratch,"%s@%s",action_string,devpath);//action_string+devpath
  137. /*copykeystoourcontinuouseventpayloadbuffer*/
  138. for(i=0;i<env->envp_idx;i++){
  139. len=strlen(env->envp[i])+1;
  140. scratch=skb_put(skb,len);
  141. strcpy(scratch,env->envp[i]);
  142. }
  143. NETLINK_CB(skb).dst_group=1;
  144. retval=netlink_broadcast_filtered(uevent_sock,skb,
  145. 0,1,GFP_KERNEL,
  146. kobj_bcast_filter,
  147. kobj);
  148. /*ENOBUFSshouldbehandledinuserspace*/
  149. if(retval==-ENOBUFS)
  150. retval=0;
  151. }else
  152. retval=-ENOMEM;
  153. }
  154. mutex_unlock(&uevent_sock_mutex);
  155. #endif
  156. /*calluevent_helper,usuallyonlyenabledduringearlyboot*/
  157. if(uevent_helper[0]&&!kobj_usermode_filter(kobj)){
  158. char*argv[3];
  159. argv[0]=uevent_helper;
  160. argv[1]=(char*)subsystem;
  161. argv[2]=NULL;
  162. retval=add_uevent_var(env,"HOME=/");
  163. if(retval)
  164. gotoexit;
  165. retval=add_uevent_var(env,
  166. "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
  167. if(retval)
  168. gotoexit;
  169. retval=call_usermodehelper(argv[0],argv,
  170. env->envp,UMH_WAIT_EXEC);
  171. }
  172. exit:
  173. kfree(devpath);
  174. kfree(env);
  175. returnretval;
  176. }


[cpp] view plain copy
  1. /**
  2. *kobject_uevent-notifyuserspacebysendinganuevent
  3. *
  4. *@action:actionthatishappening
  5. *@kobj:structkobjectthattheactionishappeningto
  6. *
  7. *Returns0ifkobject_uevent()iscompletedwithsuccessorthe
  8. *correspondingerrorwhenitfails.
  9. */
  10. intkobject_uevent(structkobject*kobj,enumkobject_actionaction)
  11. {
  12. returnkobject_uevent_env(kobj,action,NULL);
  13. }


3.3 netlink_broadcast_filtered

[cpp] view plain copy
  1. intnetlink_broadcast_filtered(structsock*ssk,structsk_buff*skb,u32pid,
  2. u32group,gfp_tallocation,
  3. int(*filter)(structsock*dsk,structsk_buff*skb,void*data),
  4. void*filter_data)
  5. {
  6. structnet*net=sock_net(ssk);
  7. structnetlink_broadcast_datainfo;
  8. structhlist_node*node;
  9. structsock*sk;
  10. skb=netlink_trim(skb,allocation);
  11. info.exclude_sk=ssk;
  12. info.net=net;
  13. info.pid=pid;
  14. info.group=group;
  15. info.failure=0;
  16. info.delivery_failure=0;
  17. info.congested=0;
  18. info.delivered=0;
  19. info.allocation=allocation;
  20. info.skb=skb;
  21. info.skb2=NULL;
  22. info.tx_filter=filter;
  23. info.tx_data=filter_data;
  24. /*Whilewesleepinclone,donotallowtochangesocketlist*/
  25. netlink_lock_table();
  26. //向nl_table[ssk->sk_protocol].mc_list中的每个sock发送此netlink消息
  27. sk_for_each_bound(sk,node,&nl_table[ssk->sk_protocol].mc_list)
  28. do_one_broadcast(sk,&info);
  29. consume_skb(skb);
  30. netlink_unlock_table();
  31. if(info.delivery_failure){
  32. kfree_skb(info.skb2);
  33. return-ENOBUFS;
  34. }else
  35. consume_skb(info.skb2);
  36. if(info.delivered){
  37. if(info.congested&&(allocation&__GFP_WAIT))
  38. yield();
  39. return0;
  40. }
  41. return-ESRCH;
  42. }

static struct netlink_table *nl_table;是全局变量,它维护了用户态创建的所有netlink sock,按协议分类,每种协议一个链表mc_list。它在函数netlink_proto_init中被初始化,向nl_table[sk->sk_protocol].mc_list中增加sock的调用流程如下(kernel/net/netlink/af_netlink.c):


3.4 do_one_broadcast

[cpp] view plain copy
  1. staticinlineintdo_one_broadcast(structsock*sk,
  2. structnetlink_broadcast_data*p)
  3. {
  4. structnetlink_sock*nlk=nlk_sk(sk);
  5. intval;
  6. if(p->exclude_sk==sk)
  7. gotoout;
  8. if(nlk->pid==p->pid||p->group-1>=nlk->ngroups||
  9. !test_bit(p->group-1,nlk->groups))
  10. gotoout;
  11. if(!net_eq(sock_net(sk),p->net))
  12. gotoout;
  13. if(p->failure){
  14. netlink_overrun(sk);
  15. gotoout;
  16. }
  17. sock_hold(sk);
  18. if(p->skb2==NULL){
  19. if(skb_shared(p->skb)){
  20. p->skb2=skb_clone(p->skb,p->allocation);
  21. }else{
  22. p->skb2=skb_get(p->skb);
  23. /*
  24. *skbownershipmayhavebeensetwhen
  25. *deliveredtoaprevioussocket.
  26. */
  27. skb_orphan(p->skb2);
  28. }
  29. }
  30. if(p->skb2==NULL){
  31. netlink_overrun(sk);
  32. /*Clonefailed.NotifyALLlisteners.*/
  33. p->failure=1;
  34. if(nlk->flags&NETLINK_BROADCAST_SEND_ERROR)
  35. p->delivery_failure=1;
  36. }elseif(p->tx_filter&&p->tx_filter(sk,p->skb2,p->tx_data)){
  37. kfree_skb(p->skb2);
  38. p->skb2=NULL;
  39. }elseif(sk_filter(sk,p->skb2)){
  40. kfree_skb(p->skb2);
  41. p->skb2=NULL;
  42. }elseif((val=netlink_broadcast_deliver(sk,p->skb2))<0){
  43. netlink_overrun(sk);
  44. if(nlk->flags&NETLINK_BROADCAST_SEND_ERROR)
  45. p->delivery_failure=1;
  46. }else{
  47. p->congested|=val;
  48. p->delivered=1;
  49. p->skb2=NULL;
  50. }
  51. sock_put(sk);
  52. out:
  53. return0;
  54. }


3.5 netlink_broadcast_deliver

[cpp] view plain copy
  1. staticinlineintnetlink_broadcast_deliver(structsock*sk,
  2. structsk_buff*skb)
  3. {
  4. structnetlink_sock*nlk=nlk_sk(sk);
  5. if(atomic_read(&sk->sk_rmem_alloc)<=sk->sk_rcvbuf&&
  6. !test_bit(0,&nlk->state)){
  7. skb_set_owner_r(skb,sk);
  8. skb_queue_tail(&sk->sk_receive_queue,skb);
  9. sk->sk_data_ready(sk,skb->len);
  10. returnatomic_read(&sk->sk_rmem_alloc)>sk->sk_rcvbuf;
  11. }
  12. return-1;
  13. }


参考文献:

1. http://blog.csdn.net/magicyu2/article/details/6974074

2. http://blog.csdn.net/wangll9/article/details/7346363


更多相关文章

  1. Android(安卓)Camera调用流程
  2. Android(安卓)无线启动过程分析 无线启动过程分析
  3. Android(安卓)getText(int resId)和getString(int resId)
  4. Android(安卓)中文API (37) —— AbsoluteLayout
  5. android studio打包apk
  6. android中webView JS调用Android的方法、webView的下拉刷新(Swipe
  7. 转:Android中几种图像特效处理方法小结
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. 〖Android〗我的ADT Eclipse定制
  2. Android绘图机制与处理技巧-更新中
  3. Android原生分享到微博、微信等平台的实
  4. 对Android及移动互联网的大局观看法!
  5. 学习Android的几大主攻方向
  6. Android开发常见异常和解决方案(二)
  7. android makefile(android.mk)分析(序)
  8. Android进程管理简单介绍
  9. 最新的免费android教程,助你深入浅出的轻
  10. Android自定义属性与自定义属性的获取