MTP模式與USB儲存模式(MTP in Android)
MTP in Android
MTP的全稱是Media Transfer Protocol(媒體傳輸協議),它是微軟公司提出的一套媒體檔案傳輸協議。Android從3.0開始支援MTP。不過,在今天的智慧手機領域內,Google和微軟是一對冤家,為什麼Android中會使用MTP呢?請看下文。
一 背景知識介紹
筆者相信《程式設計師》雜誌的絕大多數讀者或多或少都使用過MTP。因為早在智慧手機普及前,數碼相機和MP3播放器等都使用了MTP的前身PTP(Picture
Transfer Protocol)進行媒體檔案傳輸。那時,只要通過USB資料線把它們連線上Windows作業系統,就能在“我的電腦“中見到這些裝置了。此後,使用者可以把它們當做U盤一樣使用,例如對其進行目錄、檔案的瀏覽和拷貝等操作。
既然可以通過MTP把智慧裝置當作U盤使用,那麼它和我們常用的USB大容量儲存(USB Mass Storage,簡稱UMS)有何不同呢?
-
UMS模式下,PC操作儲存裝置的粒度是裝置塊(FAT block),而非檔案系統。什麼意思?此處舉一個簡單例子。當Android手機通過UMS將sdcard掛載到PC後,PC就擁有對sdcard的絕對控制權。這樣,手機就無法同時訪問sdcard了。這種做法帶來的後果就是Camera或Music程式將因沒有外部儲存空間而提示無法進行操作(注意,有些廠商的手機對此進行過修改,使得Camera能短時間錄製一部分視訊到內部儲存空間)。這也是Android早期版本中一個很明顯的特點。另外,由於PC在操作sdcard時可能弄壞其檔案系統,這將導致sdcard重新掛載到手機後不能被識別。
-
如果Android手機的sdcard以MTP模式掛載到PC機上,sdcard的控制權其實還是屬於手機。只不過智慧手機通過MTP協議向PC機構建了一個虛擬檔案系統。PC機操作其中的檔案時,都會通過標準MTP協議向智慧手機發起請求。另外,Android把MTP功能整合在MediaProvider[1]中,其好處是PC機操作(例如拷貝或刪除等)媒體檔案時,媒體資料都會及時更新到媒體資料庫中。而UMS模式下,當sdcard掛載回手機後,Android還得花較長時間重新掃描媒體檔案以更新媒體資料庫。
MTP的好處還有很多,例如它可判斷PC機拷貝的媒體檔案是否受目標手機支援,甚至可以觸發對應的轉碼程式將其轉換成手機支援的格式。不過和UMS相比,MTP也有不足之處:
- 傳輸大檔案的速度較慢。
- MTP不能直接修改檔案本身。只能先拷貝到本地修改,完畢後再拷貝回去。
-
除了Windows外,Linux和MacOS對MTP支援還不是很完善。
下面我們將介紹MTP協議。
1.1 MTP協議介紹根據協議,MTP的使用者包括兩個部分,分別是Initiator和Responder。如圖1-1所示:
圖1-1 Initiator和Responder圖示
由圖1-1可知:
- Initiator:主要是指USB Host,例如PC機,筆記本等。協議規定所有MTP操作只能由Initator發起。
-
Responder:一般是諸如數碼相機、智慧手機等儲存媒體檔案的裝置。Responder在MTP中的作用就是處理Initator發起的請求。同時,它還會根據自身狀態的變化傳送Event以通知Initiator。
注意:後文我們將統一以PC代表Initiator,Android手機代表Responder。
與很多協議一樣,MTP也有自己的協議棧,如圖1-2所示:
圖1-2 MTP協議棧
由圖1-2可知,MTP協議棧由下到上分別是:
- Pyshical Layer(物理層):物理層在MTP協議中用來傳輸資料。目前有三種物理層可供MTP使用。它們分別是USB:其主要特點是傳輸檔案,同步媒體檔案時速度快,而且可以邊工作邊充電,這是目前用的最多的一種方式;IP:基於IP的MTP(簡稱MTP/IP)將通過UPnP來匹配和發現裝置。它是家庭網路中是最理想的傳輸方式;Bluetooth:MTP/BT是最省電,同時也是速度最慢的一種傳輸方式,用處較少。
- 傳輸層:MTP中,資料傳輸格式遵循PTP協議
-
命令層:實現了MTP協議中的各種命令。
如上文所述,MTP採用命令-應答方式來工作(Initator傳送命令給Responder處理,Responser反饋處理結果),這種方式的主要特點有:
- 所有MTP命令均以Package(資料包)的方式在裝置兩端進行傳遞。
-
Initiator必須接收到前一條訊息的處理結果(不論是成功還是超時)後,才能傳送下一條訊息。
下面我們將以PC通過MTP開啟一個檔案為例,按順序介紹其中涉及到幾個主要MTP命令:
- 當裝置第一次連線上PC後,Initiator(即PC)首先會發送一個名為GetDeviceInfo的請求以獲取裝置的資訊,這些資訊包括裝置所支援PTP版本的程度,以百分號表示(預設是100)、所支援的MTP命令(Operation Supported)、所支援的Event型別等。
- 接著PC端會發送OpenSession命令以建立一個會話,該會話一直保持到裝置從PC上斷開為止。此後所有命令(除GetDeviceInfo命令外)必須在此會話存活期間才能傳送。會話在MTP協議中由SessionID來標識,它是一個32位的無符號整型,由PC選擇並傳給手機。
- PC端如果要進行檔案操作的話,必須從根目錄開始定位目標檔案。由於Windows的特殊性,手機內部儲存卡在windows系統中顯示為碟符。注意,如果手機內部有兩塊儲存卡的話(如內部儲存卡和外部sd卡),Windows中會顯示為兩個碟符。PC端需要通過GetStorageIDs命令返回某個碟符對應的StorageID。在MTP中,StorageID是一個32位無符號整型,每一個StorageID代表了一個邏輯碟符。
- PC端可以根據上一步的StorageID號,利用GetStorageInfo操作去獲取儲存裝置的資訊,例如剩餘儲存空間、檔案系統型別、訪問許可權等。
- 接著,PC就會通過GetObjectHandles命令來獲取此碟符下的檔案和子目錄的Object Handles(一個Object Handle代表一個檔案或目錄。該值由Responder生成並保證唯一性)。有了Object Handle,PC就可以操作這些檔案或目錄了,例如繼續通過GetObjectHandles獲取某個目錄中子檔案和子目錄的資訊。
- 假設現在需拷貝一個檔案到手機上,那麼PC會通過SendObjectInfo命令將檔案資訊(如檔名、檔案大小)等傳遞給手機。而手機需要檢查目標目錄是否有足夠的空間和對應許可權。
- 如果一切正常,PC將通過SendObject把資料傳遞給手機。真正寫檔案到裝置儲存空間的則是手機中的Responder。Android實現的MTP還會在媒體檔案傳輸完畢後,將資訊更新到媒體資料庫中。
-
除此之外,PC還可利用SetObjectPropValue 命令來設定檔案的各種屬性值,如Audio BitRate(位元率),Sample Rate(取樣率),Number Of Channels(聲道)等。
以上為讀者描述了MTP使用的一個簡單案例。至於其中的各種MTP命令,讀者不妨閱讀參考文獻1,即《MTP Specification v1.0.pdf》。協議對各種命令都有非常精確的描述,例如表1-1,表1-2所示為GetDeviceInfo命令,返回值定義。其引數型別,傳遞方向都有詳細解釋(不得不說,和Linux比起來,微軟的開發/技術文件做得相當到位)。
表1-1 GetDeviceInfo命令定義
表1-2所示為GetDeviceInfo的返回資料集的定義。
表1-2 GetDeviceInfo返回資料集的定義
MTP協議既然由微軟提出,理所當然,Windows對其支援自然是不遺餘力。目前Windows作業系統中,MTP和多媒體框架緊密結合,並且已經成為Windows Media框架中的重要一部分。如WMP10(Windows Media Player 10)和WMP11均內建對MTP功能,其中WMP11還新增對Playlist和Album art的支援。
微軟除了提出MTP協議並在Windows作業系統中提供大力支援外,它對使用MTP協議的裝置也有所管理。所有標稱支援MTP協議的裝置,必須通過微軟的測試WLK(Windows Logo Kit)。WLK測試通過的裝置可以獲得一個徽標。關於WLK測試的詳細資訊,請讀者參考http://msdn.microsoft.com/zh-cn/library/windows/hardware/gg487530.aspx。從以上鍊接中也能下載到wpdmon,它是MTP開發中最常用的測試工具,可顯示出所有PC與手機進行MTP操作時傳送的命令、資料及返回值。圖1-3為筆者測試某臺Android手機的MTP功能時用wpdmon截獲的資訊示意圖:
圖1-3 wpdmon工具使用示意圖
下面我們來看MTP在Android平****的實現。
二 Android中的MTPAndroid從3.0開始整合MTP功能,主要原因有三個:
- 手機要支援UMS的話,必須有一個sd卡,因為sd卡往往採用Windows支援的分割槽格式。如果想把內部儲存空間通過UMS掛載到Windows上,則內部儲存空間需採用特定的分割槽格式。這對某些手機而言根本不可行。因為內部儲存空間本身可能是一個裝置,它們採用統一的分割槽格式。不能因為需要使用UMS,而再增加一塊特定分割槽格式的儲存裝置。
- UMS掛載到PC後,PC作業系統擁有絕對控制權。此時,Android系統將無法操作這些裝置。根據前文舉的Camera例子而言,這對越來越高階的Android版本而言是不可接受的。
-
另外一個不可忽略的事實就是Windows作業系統在普通勞動人民那兒依然佔據極高的市場份額。這恐怕也是明知Linux、MacOS對MTP支援力度不夠,Android也要整合它的一個重要原因吧。
要使用MTP功能,首先需要在設定中啟用USB連線模式為MTP,如圖1-4所示:
圖1-4 Settings中的MTP設定
圖1-4所示為參考機(Android 4.1版本)中“USB連線模式”設定。該操作實際上會觸發USB驅動做相應變動。本文不擬討論其中的過程,讀者可參考手機中init.platform-name.usb.rc檔案以檢視Android系統中USB的模式設定。從目前市面上釋出的數款Android 4.0及後續版本的機型來看,MTP/PTP大有取代UMS的趨勢。
根據前文所述,Android中的MTP和已有的MediaProvider模組結合緊密,以更好體現“Media Transfer”的特性。其主要結構如圖1-5所示:
圖1-5 Android MTP架構圖
由圖1-5可知,Android MTP架構由下到上分別是:
- C++層包括幾個主要物件,如MtpRequestPacke負責從USB驅動讀取資料,並結構化命令格式及其引數、MtpDataPacket負責結構化手機要返回給PC的資料包、MtpResponsePacket負責結構化手機要給PC返回的response。MtpServer負責解析來自PC的命令並呼叫相應的介面函式進行處理。
-
Java層包括UsbReceiver、MtpService、MtpServer等物件。其中UsbReceiver用來監視USB事件,判斷何時啟動或停止MtpService。MtpService負責啟動MtpServer和載入儲存裝置的資訊到資料庫。MtpServer負責通過jni介面去啟動/停止C++層中MtpServer以及處理Storage的新增和刪除。MediaProvider則負責查詢和更新資料庫。MtpDatabase名字雖然叫Database,但實際功能用於在MediaProvider和MtpServer之間轉換資料格式。例如把MTP傳遞過來的資訊(如檔案大小、檔案路徑等)轉換成MediaProvider需要的格式以方便其更新資料庫。
下面我們來看MTP的工作流程。
2.2 MTP流程分析我們先來看MTP模組啟動的流程,如圖1-6所示:
圖1-6 MTP主要模組啟動流程
由圖1-6可知:
- 當手機連上usb線後,UsbReceiver會收到來自系統的USB_STATE廣播事件。接著它需要從UsbManager中查詢USB的連結狀態,MTP的設定資訊和PTP的設定資訊。當用戶設定為使用MTP模式時,UsbReceiver將通過startService函式啟動MtpService。
- MtpService啟動,在其onStartCommand中將建立MtpDatabase物件和MtpServer物件。
-
UsbReceiver同時通過insert一條特殊uri(值為“content://media/none/mtp_connected”)的方式,觸發MdiaProvder呼叫MtpService的bindService函式。這樣,MediaProvider和MtpService就建立了緊密聯絡。
MtpServer是Android平****MTP協議處理的核心模組,它會單獨啟動一個執行緒用於接收PC端的命令,其程式碼如圖1-7所示:
圖1-7 MtpServer run函式程式碼片段
由圖1-7可知,MtpServer不斷從檔案描述符讀取請求,然後呼叫handleRequest進行處理。最後把處理結果返回給對端。
從這段程式碼讀者可以發現,Android MTP命令層和物理層之間的耦合度較低,這樣也方便將來實現MTP/IP功能。
接下來我們看看PC端傳送SendObjectInfo的處理流程,如圖1-8所示:
圖1-8 sendObjectInfo處理流程圖
由圖1-8可知SendObjectInfo的處理流程大體步驟如下:
- PC發SendObjectInfo命令給MtpServer。MtpServer需要檢查儲存裝置剩餘空間、可支援的最大檔案大小。如果一切正常的話,它會通過MediaProvider的insert函式往媒體資料庫中加入一條資料項。
- 接著PC通過SendObject將檔案內容傳遞給給MtpServer。而MtpServer就會建立該檔案,並把資料寫到檔案中。
-
當檔案資料傳送完畢,MtpServer呼叫endSendObject。而endObject則會觸發MediaScanner進行媒體檔案掃描。當然,掃描完後,該檔案攜帶的媒體資訊(假如是MP3檔案的話,則會把專輯資訊、歌手、流派、長度等內容)加入到媒體資料庫中。
通過對SendObjectInfo描述,我們也可看出,Android充分利用了其平臺本身的特性,真正將媒體傳輸協議和媒體檔案掃描恰到好處得結合起來,從而發揮了MTP最大功效。
三 總結本文主要對Android中的MTP進行了相關介紹。雖然MTP協議由微軟提供,但因為歷史原因,其使用程度相當廣泛,以至於Android也提供了最基本的MTP實現。
當然,如果要做到真正實用並通過微軟認證,手機廠商還需要在此基礎上做進一步的開發。結合筆者自己的使用經歷,國外大牌手機廠商例如Sony、Samsung、Nokia等對MTP的支援相當到位。相比而言,國內手機廠商的起步稍微晚一點,需要投入更多的精力才能超越。另外,隨著無線技術的普及,MTP基於IP的實現也將極大方面使用者的使用。筆者在此希望大家能一起努力,早日讓使用者從USB資料線中解放出來。