一、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. Android(安卓)Canvas drawArc方法介绍
  2. android源码解析--switch
  3. Android(安卓)监听EditText文本输入 EditText监听事和输入事件
  4. Android(安卓)ConstraintLayout 约束布局
  5. Android(安卓)AM命令行启动程序的方法
  6. Android(安卓)JNI入门第六篇——C调用Java
  7. 2011.09.15 ——— android 桌面添加快捷方式之判断是否存在无效
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. Android调用系统自带的下载程序进行下载
  2. Android 为【apk】文件签名,增加修改系统
  3. Android 控件大全
  4. Android应用架构之MVP模式
  5. Android Service总结02 service介绍
  6. EditText android:editable is deprecate
  7. Android学习笔记进阶1之MediaPlayer
  8. Android关于drawable和drawable-v24,mipma
  9. Android平台OpenMax多媒体引擎介绍
  10. Android模块化和组件化开发简单理解(一)