Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3003875
  • 博文数量: 674
  • 博客积分: 17881
  • 博客等级: 上将
  • 技术积分: 4849
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-17 10:15
文章分类

全部博文(674)

文章存档

2013年(34)

2012年(146)

2011年(197)

2010年(297)

分类: LINUX

2012-03-14 18:29:27

Android VoldVolume Daemon 

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

服务在init.rc中被开启:

 

  1. service vold /system/bin/vold  
  2.     socket vold stream 0660 root mount  
service vold /system/bin/vold socket vold stream 0660 root mount

 

 

本文主要分为两个部分:

 

·Vold 的架构分析

·Vold的功能总结

 

1.Vold的架构分析

 

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

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

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

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

  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. }  
if ((door_sock = android_get_control_socket(VOLD_SOCKET)) < 0) { LOGE("Obtaining file descriptor socket '%s' failed: %s", VOLD_SOCKET, strerror(errno)); exit(1); } if (listen(door_sock, 4) < 0) { LOGE("Unable to listen on fd '%d' for socket '%s': %s", door_sock, VOLD_SOCKET, strerror(errno)); exit(1); } 

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

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

 

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

 

  1. if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {  
  2.                 Thread thread = new Thread(mListener, MountListener.class.getName());  
  3.                 thread.start();  
  4.             }  
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { Thread thread = new Thread(mListener, MountListener.class.getName()); thread.start(); }

 

 

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

  1. while (true) {  
  2.                 listenToSocket();  
  3.             }  
while (true) { listenToSocket(); } 

 

listenToSocket()方法中:

 

  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.   }    
socket = new LocalSocket(); LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET, LocalSocketAddress.Namespace.RESERVED); socket.connect(address); InputStream inputStream = socket.getInputStream(); mOutputStream = socket.getOutputStream(); ···································· while (true) { int count = inputStream.read(buffer); if (count < 0) break; int start = 0; for (int i = 0; i < count; i++) { if (buffer[i] == 0) { String event = new String(buffer, start, i - start); handleEvent(event); start = i + 1; } } }   

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

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

 

  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.              .........................  
if (event.equals(VOLD_EVT_UMS_ENABLED)) { ................ } else if (event.equals(VOLD_EVT_UMS_DISABLED)) { ................ } else if (event.equals(VOLD_EVT_EXTERNAL_UMS_CONNECTED)) { ............... mService.notifyUmsConnected(path); ..................... } else if (event.equals(VOLD_EVT_UMS_CONNECTED)) { ........................... mService.notifyUmsConnected(path); } else if (event.equals(VOLD_EVT_EXTERNAL_UMS_DISCONNECTED)) { .........................

 

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

 

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

 

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

 

1.2建立与内核的socket通信

  1. ....................  
  2. Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);  
  3.         mContext.sendBroadcast(intent);     
  4. ....................     
....................Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED); mContext.sendBroadcast(intent); ....................   

  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.     }  
if ((uevent_sock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {........ } if (setsockopt(uevent_sock, SOL_SOCKET, SO_RCVBUFFORCE, &uevent_sz, sizeof(uevent_sz)) < 0) {....... } if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { ...... } 

创建一个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

  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.     }  
volmgr_bootstrap();simulate_uevent()确定uevent的action是'add','remove'还是'change';if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) { LOGE("Unable to process config"); return rc; } 

mmc_bootstrap()

 

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

 

 

  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. };  
struct uevent { const char *action; const char *path; const char *subsystem; const char *firmware; int major; int minor;};

 

 

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

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

 

1.6 switch_bootstrap()

 

1.7主服务(死循环)

 

  1. struct uevent_dispatch {  
  2.     char *subsystem;  
  3.     int (* dispatch) (struct uevent *);  
  4. };  
struct uevent_dispatch { char *subsystem; int (* dispatch) (struct uevent *);};

 

  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  
while(1) { ········ FD_ZERO(&read_fds);//初始化文件描述集合 FD_SET(door_sock, &read_fds);//将door_sock加入文件描述集 if (door_sock > max) max = door_sock; FD_SET(uevent_sock, &read_fds);//将event_sock加入文件描述集 if (uevent_sock > max) max = uevent_sock; if (fw_sock != -1) { FD_SET(fw_sock, &read_fds);//将fw_sock加入文件描述集 if (fw_sock > max) max = fw_sock; } //当所有的文件描述符都没改变时,阻塞线程 if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) { LOGE("select() failed (%s)", strerror(errno)); sleep(1); continue; } if (!rc) { continue; } //检测如果是door_sock,检测与framework的连接,并发送msg if (FD_ISSET(door_sock, &read_fds)) { struct sockaddr addr; socklen_t alen; alen = sizeof(addr); if (fw_sock != -1) { LOGE("Dropping duplicate framework connection"); int tmp = accept(door_sock, &addr, &alen); close(tmp); continue; } if ((fw_sock = accept(door_sock, &addr, &alen)) < 0) { LOGE("Unable to accept framework connection (%s)", strerror(errno)); } LOG_VOL("Accepted connection from framework");/* for iNand */volmgr_usb_bootstrap(); if ((rc = volmgr_send_states()) < 0) { LOGE("Unable to send volmgr status to framework (%d)", rc); } } //如果是fw_sock,执行framework传来的命令 if (FD_ISSET(fw_sock, &read_fds)) { if ((rc = process_framework_command(fw_sock)) < 0) { if (rc == -ECONNRESET) { LOGE("Framework disconnected"); close(fw_sock); fw_sock = -1; } else { LOGE("Error processing framework command (%s)", strerror(errno)); } } } //如果是uevent_sock,产生一个uevent事件 if (FD_ISSET(uevent_sock, &read_fds)) { if ((rc = process_uevent_message(uevent_sock)) < 0) { LOGE("Error processing uevent msg (%s)", strerror(errno)); } } } // while 

 

2.Vold的功能总结

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

 

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

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

·其次,执行MMC卡挂载; 

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

 

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

补充:

Telechips比较google原生Android 针对Vold的移植主要在以下两方面:

1.Telchips支持多种存储设备,例如nand,sata,scsi,mmc/sd;从代码角度而言,主要增加了对这些设备事件的处理句柄;

2.Telchips加入了对ntfs的支持,主要增加了三个处理函数:ntfs_check(),ntfs_identify()和ntfs_mount();

http://blog.csdn.net/fengkehuan/article/details/6195049

阅读(1724) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~