android vold 检测block设备和USB设备

Android VoldVolume Daemon 

负责大容量存储设备挂载和删除的守护进程。

服务在init.rc中被开启:

 

[c-sharp] view plain copy print ?
  1. service vold /system/bin/vold  
  2.     socket vold stream 0660 root mount  

 

 

本文主要分为两个部分:

 

·Vold 的架构分析

·Vold的功能总结

 

1.Vold的架构分析

 

Android Vold ,一方面负责接受内核发送的关于外部存储设备加载和删除的信息,然后将信息发送给framework层的MountService;另一方面负责执行MountService发送的命令。

这些cmdmes的传递主要是通过Socket通信来实现(Socket的通信的具体细节这里不再赘述)。

下面从代码的角度简要分析这一过程的实现:

1.1在vold.c中,首先建立和framework层的通信:

[c-sharp] view plain copy print ?
  1. if ((door_sock = android_get_control_socket(VOLD_SOCKET)) < 0) {  
  2.     LOGE("Obtaining file descriptor socket '%s' failed: %s",  
  3.          VOLD_SOCKET, strerror(errno));  
  4.     exit(1);  
  5. }  
  6. if (listen(door_sock, 4) < 0) {  
  7.     LOGE("Unable to listen on fd '%d' for socket '%s': %s",   
  8.          door_sock, VOLD_SOCKET, strerror(errno));  
  9.     exit(1);  
  10. }  
 

其中,VOLD_SOCKETinit进程中创建,android_get_control_socket()主要是获取VOLD_SOCKET的文件描述符。

Listern()主要用于监听来自其他framework层的Socket连接请求。

 

framewok层,MountService开启之后,会创建一个新的线程。在class MountService 的构造方法中:

 

[c-sharp] view plain copy print ?
  1. if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {  
  2.                 Thread thread = new Thread(mListener, MountListener.class.getName());  
  3.                 thread.start();  
  4.             }  

 

 

class MountListener 实现了Runnable接口,在它继承的run()方法中创建了一个无限循环:

[c-sharp] view plain copy print ?
  1. while (true) {  
  2.                 listenToSocket();  
  3.             }  
 

 

listenToSocket()方法中:

 

[c-sharp] view plain copy print ?
  1.   socket = new LocalSocket();  
  2.   LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET,   
  3.           LocalSocketAddress.Namespace.RESERVED);  
  4.   socket.connect(address);  
  5.   InputStream inputStream = socket.getInputStream();  
  6.   mOutputStream = socket.getOutputStream();  
  7. ····································  
  8.   while (true) {  
  9.       int count = inputStream.read(buffer);  
  10.       if (count < 0) break;  
  11.       int start = 0;  
  12.       for (int i = 0; i < count; i++) {  
  13.           if (buffer[i] == 0) {  
  14.               String event = new String(buffer, start, i - start);  
  15.               handleEvent(event);  
  16.               start = i + 1;  
  17.           }                     
  18.       }  
  19.   }    
  

首先,实例化一个本地的LocalSocket 用于与Vold的通信,其次建立与VOLD_SOCKET的连接。然后再建立一个文件输入流,用于保存Vold传来的mesbuff中。最后,在一个无线循环中读取buff的内容,并执行handleEvent()

handleEvent()中通过if else语句对传来的事件做相应处理

 

[c-sharp] view plain copy print ?
  1. if (event.equals(VOLD_EVT_UMS_ENABLED)) {  
  2.             ................  
  3.         } else if (event.equals(VOLD_EVT_UMS_DISABLED)) {  
  4.             ................  
  5.         } else if (event.equals(VOLD_EVT_EXTERNAL_UMS_CONNECTED)) {  
  6.             ...............            
  7.             mService.notifyUmsConnected(path);                   
  8.             .....................  
  9.         } else if (event.equals(VOLD_EVT_UMS_CONNECTED)) {  
  10.             ...........................  
  11.             mService.notifyUmsConnected(path);               
  12.         } else if (event.equals(VOLD_EVT_EXTERNAL_UMS_DISCONNECTED)) {  
  13.              .........................  

 

对于其中一个事件的处理,例如.notifyUmsConnected():

 

最后,将处理之后需要执行的命令发送给vold

 

到现在为止,我们就建立了vold MountService之间的通信。

 

1.2建立与内核的socket通信

[c-sharp] view plain copy print ?
  1. ....................  
  2. Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);  
  3.         mContext.sendBroadcast(intent);     
  4. ....................     
  

[c-sharp] view plain copy print ?
  1. if ((uevent_sock = socket(PF_NETLINK,  
  2.                              SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {  
  3. ........  
  4.     }  
  5.     if (setsockopt(uevent_sock, SOL_SOCKET, SO_RCVBUFFORCE, &uevent_sz,  
  6.                    sizeof(uevent_sz)) < 0) {  
  7. .......  
  8.     }  
  9.     if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {  
  10.      ......  
  11.     }  
 

创建一个uevent_sock,建立与内核的通信。setsockopt()函数主要用于设置uevent_sock的选项,bind()用于将内核的socketuevent_sock进行地址的绑定。

 

1.3挂载现有存储设备

 

volmgr_bootstrap()函数首先解析配置文件vold.conf

最后会将需要挂载的设备信息放在一个全局变量的链表中val_root

static volume_t *vol_root = NULL;

1.4挂载mmc/sdcard

[c-sharp] view plain copy print ?
  1. volmgr_bootstrap();  
  2. simulate_uevent()确定uevent的action是'add','remove'还是'change';  
  3. if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) {  
  4.         LOGE("Unable to process config");  
  5.         return rc;  
  6.     }  
 

mmc_bootstrap()

 

dipatch_uevent():根据uevent->subsystem确定uevent处理的句柄。

 

 

[c-sharp] view plain copy print ?
  1. struct uevent {  
  2.     const char *action;  
  3.     const char *path;  
  4.     const char *subsystem;  
  5.     const char *firmware;  
  6.     int major;  
  7.     int minor;  
  8. };  

 

 

最终的挂载操作在MountService开启之后实现

1.5 usb大容量存储的处理ums_bootstrap()

 

1.6 switch_bootstrap()

 

1.7主服务(死循环)

 

[c-sharp] view plain copy print ?
  1. struct uevent_dispatch {  
  2.     char *subsystem;  
  3.     int (* dispatch) (struct uevent *);  
  4. };  

 

[c-sharp] view plain copy print ?
  1. while(1) {  
  2.        ········  
  3.         FD_ZERO(&read_fds);//初始化文件描述集合   
  4.         FD_SET(door_sock, &read_fds);//将door_sock加入文件描述集   
  5.         if (door_sock > max)  
  6.             max = door_sock;  
  7.         FD_SET(uevent_sock, &read_fds);//将event_sock加入文件描述集   
  8.         if (uevent_sock > max)  
  9.             max = uevent_sock;  
  10.         if (fw_sock != -1) {  
  11.             FD_SET(fw_sock, &read_fds);//将fw_sock加入文件描述集   
  12.             if (fw_sock > max)  
  13.                 max = fw_sock;  
  14.         }  
  15.        //当所有的文件描述符都没改变时,阻塞线程   
  16.         if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) {  
  17.             LOGE("select() failed (%s)", strerror(errno));  
  18.             sleep(1);  
  19.             continue;  
  20.         }  
  21.         if (!rc) {  
  22.             continue;  
  23.         }  
  24.         //检测如果是door_sock,检测与framework的连接,并发送msg   
  25.         if (FD_ISSET(door_sock, &read_fds)) {  
  26.             struct sockaddr addr;  
  27.             socklen_t alen;  
  28.             alen = sizeof(addr);  
  29.             if (fw_sock != -1) {  
  30.                 LOGE("Dropping duplicate framework connection");  
  31.                 int tmp = accept(door_sock, &addr, &alen);  
  32.                 close(tmp);  
  33.                 continue;  
  34.             }  
  35.             if ((fw_sock = accept(door_sock, &addr, &alen)) < 0) {  
  36.                 LOGE("Unable to accept framework connection (%s)",  
  37.                      strerror(errno));  
  38.             }  
  39.             LOG_VOL("Accepted connection from framework");  
  40. /* for iNand */  
  41. volmgr_usb_bootstrap();  
  42.             if ((rc = volmgr_send_states()) < 0) {  
  43.                 LOGE("Unable to send volmgr status to framework (%d)", rc);  
  44.             }  
  45.         }  
  46.         //如果是fw_sock,执行framework传来的命令   
  47.         if (FD_ISSET(fw_sock, &read_fds)) {  
  48.             if ((rc = process_framework_command(fw_sock)) < 0) {  
  49.                 if (rc == -ECONNRESET) {  
  50.                     LOGE("Framework disconnected");  
  51.                     close(fw_sock);  
  52.                     fw_sock = -1;  
  53.                 } else {  
  54.                     LOGE("Error processing framework command (%s)",  
  55.                          strerror(errno));  
  56.                 }  
  57.             }  
  58.         }  
  59.       //如果是uevent_sock,产生一个uevent事件   
  60.         if (FD_ISSET(uevent_sock, &read_fds)) {  
  61.             if ((rc = process_uevent_message(uevent_sock)) < 0) {  
  62.                 LOGE("Error processing uevent msg (%s)", strerror(errno));  
  63.             }  
  64.         }  
  65.     } // while  
 

 

2.Vold的功能总结

1)创建连接:
     在vold作为一个守护进程,一方面接受驱动的信息,并把信息传给应用层;另一方面接受上层的命令并完成相应操作。
     所以这里的连接一共有两条:
       ·vold socket: 负责vold与应用层的信息传递;
       ·访问udevsocket: 负责vold与底层的信息传递;
     这两个连接都是在进程的一开始完成创建的。

 

     2)引导
     这里主要是在vold启动时,对现有外设存储设备的处理。

·首先,要加载并解析vold.conf,并检查挂载点是否已经被挂载;

·其次,执行MMC卡挂载; 

·最后,处理USB大容量存储。

 

     3)事件处理:
     这里通过对两个连接的监听,完成对动态事件的处理,以及对上层应用操作的响应。

补充:

google原生Android 针对Vold的移植还需要改进:

1.U盘多分区挂载,原生的只同时支持4个分区挂载,这个就需要修改源码。

2.另外vold不支持 ntfs的挂载,linux 对ntfs的支持本来就不好,可以利用ntfs-3g来挂载,也需要修改代码。

3.vold还可以检测其他热插拔设备,主要获取其句柄。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值