上次,初步接觸Android usb client 的掛載問題,所以寫了第一篇研究的感受,許多地方還有點問題,有些現象還不夠清晰,所以想繼續寫下去。
首先,通過上次的驗證,看到的現象,是可以掛載了,但是每一次只能掛載一個存放裝置。
其次,我上次所說的關於驅動的裝置節點,也有問題,其實本身就有一個tegra-udc.c建立的/sys/devices/platform/tegra-udc.0/lun0這麼個節點在,所以不需要在建立什麼mass-storage節點。
===========================================================================
(一)首先,我們看看第一個問題,怎麼每次只掛了一個裝置在上面呢?
1.VOLD首先會去讀取vold.conf的檔案中配置內容(尾插入的鏈表方式)儲存存放裝置的必要資訊(上次講過,就是EMMC的partition 4)
接著,會去通過uevent讀取動態插入的存放裝置資訊,以頭插入鏈表的方式,並將第一個鏈表和這次的鏈表結合起來(auto_add_volume函數),使得動態儲存裝置裝置在鏈表頭幾個,而靜態存放裝置在鏈表後面。這種順序,在我的環境中是正確的,因為我的雖有的動態儲存裝置裝置是掛載在partition 4上面的。用過手機或者有一點掛載卸載經驗的人都知道,如果想要順利卸載partition 4 需要卸載它的裡面目錄,否則partition 4一直顯示busy而不能卸載。為什麼要卸載了存放裝置再掛呢,這是因為防止兩邊同時操作。
這裡要說明下,就是如果想要動態儲存裝置裝置通過ums_path路徑的檢測,需要在auto_add_volume函數裡的ums_path下,明確指定目錄,使得動態儲存裝置裝置,能夠被正確掛載。
2.當在client卸載成功時,就需要掛載到host端了,我一路跟蹤,發現這段vold的volmgr.c代碼起了作用
static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg)<br />{<br /> int rc;<br /> char *devdir_path;<br />#if DEBUG_VOLMGR<br /> LOG_VOL("_cb_volstopped_for_ums_enable(%s):", v->mount_point);<br />#endif<br /> //check dev->disk whether is NULL<br /> if (v->dev->disk)<br /> devdir_path = blkdev_get_devpath(v->dev->disk);<br /> else<br /> devdir_path = blkdev_get_devpath(v->dev);</p><p> if ((rc = ums_enable(devdir_path, v->ums_path)) < 0) {//重點<br /> free(devdir_path);<br /> LOGE("Error enabling ums (%d)", rc);<br /> return;<br /> }<br /> free(devdir_path);<br /> volume_setstate(v, volstate_ums);<br /> pthread_mutex_unlock(mutex);<br />}
最主要的是ums_enable(),是這句話讓裝置掛載到主機端,繼續跟下去
在同目錄下的ums.c代碼中
int ums_enable(char *dev_fspath, char *lun_syspath)<br />{<br /> LOG_VOL("ums_enable(%s, %s):", dev_fspath, lun_syspath);<br /> int fd;<br /> char filename[255];<br /> sprintf(filename, "/sys/%s/file", lun_syspath);<br /> if ((fd = open(filename, O_WRONLY)) < 0) {<br /> LOGE("Unable to open '%s' (%s)", filename, strerror(errno));<br /> return -errno;<br /> }<br /> if (write(fd, dev_fspath, strlen(dev_fspath)) < 0) {<br /> LOGE("Unable to write to ums lunfile (%s)", strerror(errno));<br /> close(fd);<br /> return -errno;<br /> }</p><p> close(fd);<br /> return 0;<br />}
open 一個"/sys/devices/platform/tegra-udc.0/lun0/file"檔案
然後向file檔案 寫入一個 "/dev/block/vold/major:minor"的path路徑,而這個路徑對應的是各個存放裝置
我嘗試了寫入不同的路徑到file裡(通過adb 中寫入 如:echo "/dev/block/vold/179:0">/sys/devices/platform/tegra-udc.0/lun0/file)。
每寫一個路徑,就會掛載一個相應的存放裝置到host端,但是當你掛載下個裝置時候必須echo "">file中,先從host端unmount前一個裝置才能掛載當前裝置。
繼續跟蹤代碼到kernenl,發現/driver/usb/gadget/f_mass_storage.c作了某些動作,掛載了裝置
static ssize_t store_file(struct device *dev, struct device_attribute *attr,<br />const char *buf, size_t count)<br />{<br />struct lun*curlun = dev_to_lun(dev);<br />struct fsg_dev*fsg = dev_get_drvdata(dev);<br />intrc = 0;<br />DBG(fsg, "store_file: /"%s/"/n", buf);<br />#if 0<br />/* disabled because we need to allow closing the backing file if the media was removed */<br />if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {<br />LDBG(curlun, "eject attempt prevented/n");<br />return -EBUSY;/* "Door is locked" */<br />}<br />#endif<br />/* Remove a trailing newline */<br />if (count > 0 && buf[count-1] == '/n')<br />((char *) buf)[count-1] = 0;<br />/* Eject current medium */<br />down_write(&fsg->filesem);<br />if (backing_file_is_open(curlun)) {<br />close_backing_file(fsg, curlun);<br />curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;</p><p>}<br />/* Load new medium */<br />if (count > 0 && buf[0]) {<br />rc = open_backing_file(fsg, curlun, buf);<br />if (rc == 0)<br />curlun->unit_attention_data =<br />SS_NOT_READY_TO_READY_TRANSITION;</p><p>}<br />up_write(&fsg->filesem);<br />return (rc < 0 ? rc : count);<br />}
知道sysfs的原理的人 都知道static DEVICE_ATTR(file, 0444, show_file, store_file);是負責讀(cat/read)或直寫(echo/write)裝置屬性檔案的宏,具體實現就是上面這句(寫)。
看來看去 主要就是open_backing_file()函數的作用。還沒怎麼研究透,只知道肯定是這句起了作用,它開啟了vold目錄下的裝置節點,並且初始化了一些東西。看到的現象就是,host端只識別單裝置不同分區的掛載,但是不識別多存放裝置的同時掛載。
我不知道,到底是什麼問題,讓所有裝置只掛載到一個裝置節點上去了(衝突),而不是以往的/dev/sdb sdc sde等。
希望能夠學習解決
======================================================================
(二)第二個問題 其實也沒什麼,只是 先從UDC(usb device controller)的驅動走了下,當時沒注意。
不知道Android手機是不是驅動有這種只掛載單一存放裝置的限制,至少目前看是這樣的。想想也正常,手機一般只有一個SD插槽,自己本身記憶體有限,掛一個SD的存放裝置無可厚非。。。
希望是自己代碼的問題,還在解決中,希望有研究的達人,一起研究分享下這方面的經驗。謝謝,估計很快會寫(三),還在嘗試,希望寫下一篇的時候,能解決這個問題。