Android 2.1 Vold 分析

來源:互聯網
上載者:User

 

Android Vold(Volume Daemon) 

負責大量儲存裝置掛載和刪除的守護進程。

服務在init.rc中被開啟:

 

service vold /system/bin/vold<br /> socket vold stream 0660 root mount

 

 

本文主要分為兩個部分:

 

·Vold 的架構分析

·Vold的功能總結

 

1.Vold的架構分析

 

Android Vold ,一方面負責接受核心發送的關於外部存放裝置載入和刪除的資訊,然後將資訊發送給framework層的MountService;另一方面負責執行MountService發送的命令。

這些cmd和mes的傳遞主要是通過Socket通訊來實現(Socket的通訊的具體細節這裡不再贅述)。

下面從代碼的角度簡要分析這一過程的實現:

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

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

其中,VOLD_SOCKET在init進程中建立,android_get_control_socket()主要是擷取VOLD_SOCKET的檔案描述符。

Listern()主要用於監聽來自其他framework層的Socket串連請求。

 

當framewok層,MountService開啟之後,會建立一個新的線程。在class MountService 的構造方法中:

 

if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {<br /> Thread thread = new Thread(mListener, MountListener.class.getName());<br /> thread.start();<br /> }

 

 

class MountListener 實現了Runnable介面,在它繼承的run()方法中建立了一個無限迴圈:

while (true) {<br /> listenToSocket();<br /> } 

 

在listenToSocket()方法中:

 

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

首先,執行個體化一個本地的LocalSocket 用於與Vold的通訊,其次建立與VOLD_SOCKET的串連。然後再建立一個檔案輸入資料流,用於儲存Vold傳來的mes到buff中。最後,在一個無線迴圈中讀取buff的內容,並執行handleEvent()。

在handleEvent()中通過if else語句對傳來的事件做相應處理

 

if (event.equals(VOLD_EVT_UMS_ENABLED)) {<br /> ................<br /> } else if (event.equals(VOLD_EVT_UMS_DISABLED)) {<br /> ................<br /> } else if (event.equals(VOLD_EVT_EXTERNAL_UMS_CONNECTED)) {<br /> ...............<br /> mService.notifyUmsConnected(path);<br /> .....................<br /> } else if (event.equals(VOLD_EVT_UMS_CONNECTED)) {<br /> ...........................<br /> mService.notifyUmsConnected(path);<br /> } else if (event.equals(VOLD_EVT_EXTERNAL_UMS_DISCONNECTED)) {<br /> .........................

 

對於其中一個事件的處理,例如.notifyUmsConnected():

 

最後,將處理之後需要執行的命令發送給vold。

 

到現在為止,我們就建立了vold 與MountService之間的通訊。

 

1.2建立與核心的socket通訊

....................<br />Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);<br /> mContext.sendBroadcast(intent);<br />....................   

if ((uevent_sock = socket(PF_NETLINK,<br /> SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {<br />........<br /> }<br /> if (setsockopt(uevent_sock, SOL_SOCKET, SO_RCVBUFFORCE, &uevent_sz,<br /> sizeof(uevent_sz)) < 0) {<br />.......<br /> }<br /> if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {<br /> ......<br /> } 

建立一個uevent_sock,建立與核心的通訊。setsockopt()函數主要用於設定uevent_sock的選項,bind()用於將核心的socket與uevent_sock進行地址的綁定。

 

1.3掛載現有存放裝置

 

volmgr_bootstrap()函數首先解析設定檔vold.conf;

最後會將需要掛載的裝置資訊放在一個全域變數的鏈表中val_root

static volume_t *vol_root = NULL;

1.4掛載mmc/sdcard卡

volmgr_bootstrap();<br />simulate_uevent()確定uevent的action是'add','remove'還是'change';<br />if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) {<br /> LOGE("Unable to process config");<br /> return rc;<br /> } 

mmc_bootstrap()

 

dipatch_uevent():根據uevent->subsystem確定uevent處理的控制代碼。

 

 

struct uevent {<br /> const char *action;<br /> const char *path;<br /> const char *subsystem;<br /> const char *firmware;<br /> int major;<br /> int minor;<br />};

 

 

最終的掛載操作在MountService開啟之後實現。

1.5 usb大型存放區的處理ums_bootstrap()

 

1.6 switch_bootstrap()

 

1.7主服務(死迴圈)

 

struct uevent_dispatch {<br /> char *subsystem;<br /> int (* dispatch) (struct uevent *);<br />};

 

while(1) {<br /> ········<br /> FD_ZERO(&read_fds);//初始設定檔案描述集合<br /> FD_SET(door_sock, &read_fds);//將door_sock加入檔案描述集<br /> if (door_sock > max)<br /> max = door_sock;<br /> FD_SET(uevent_sock, &read_fds);//將event_sock加入檔案描述集<br /> if (uevent_sock > max)<br /> max = uevent_sock;<br /> if (fw_sock != -1) {<br /> FD_SET(fw_sock, &read_fds);//將fw_sock加入檔案描述集<br /> if (fw_sock > max)<br /> max = fw_sock;<br /> }<br /> //當所有的檔案描述符都沒改變時,阻塞線程<br /> if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) {<br /> LOGE("select() failed (%s)", strerror(errno));<br /> sleep(1);<br /> continue;<br /> }<br /> if (!rc) {<br /> continue;<br /> }<br /> //檢測如果是door_sock,檢測與framework的串連,並發送msg<br /> if (FD_ISSET(door_sock, &read_fds)) {<br /> struct sockaddr addr;<br /> socklen_t alen;<br /> alen = sizeof(addr);<br /> if (fw_sock != -1) {<br /> LOGE("Dropping duplicate framework connection");<br /> int tmp = accept(door_sock, &addr, &alen);<br /> close(tmp);<br /> continue;<br /> }<br /> if ((fw_sock = accept(door_sock, &addr, &alen)) < 0) {<br /> LOGE("Unable to accept framework connection (%s)",<br /> strerror(errno));<br /> }<br /> LOG_VOL("Accepted connection from framework");<br />/* for iNand */<br />volmgr_usb_bootstrap();<br /> if ((rc = volmgr_send_states()) < 0) {<br /> LOGE("Unable to send volmgr status to framework (%d)", rc);<br /> }<br /> }<br /> //如果是fw_sock,執行framework傳來的命令<br /> if (FD_ISSET(fw_sock, &read_fds)) {<br /> if ((rc = process_framework_command(fw_sock)) < 0) {<br /> if (rc == -ECONNRESET) {<br /> LOGE("Framework disconnected");<br /> close(fw_sock);<br /> fw_sock = -1;<br /> } else {<br /> LOGE("Error processing framework command (%s)",<br /> strerror(errno));<br /> }<br /> }<br /> }<br /> //如果是uevent_sock,產生一個uevent事件<br /> if (FD_ISSET(uevent_sock, &read_fds)) {<br /> if ((rc = process_uevent_message(uevent_sock)) < 0) {<br /> LOGE("Error processing uevent msg (%s)", strerror(errno));<br /> }<br /> }<br /> } // while<br /> 

 

2.Vold的功能總結

1)建立串連:
     在vold作為一個守護進程,一方面接受驅動的資訊,並把資訊傳給應用程式層;另一方面接受上層的命令並完成相應操作。
     所以這裡的串連一共有兩條:
       ·vold socket: 負責vold與應用程式層的資訊傳遞;
       ·訪問udev的socket: 負責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();

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.