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中,其好处是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命令定义
Operation Code |
0x1001 |
GetDeviceInfo对应命令的数字编号是0x1001 |
Data |
DeviceInfo dataset |
手机端返回的设备信息数据集 |
Data Direction |
R->I |
数据传输方向是手机到PC |
ResponseCode Options |
OK, Parameter_Not_Supported |
手机给PC的返回值 |
表1-2所示为GetDeviceInfo的返回数据集的定义。
表1-2 GetDeviceInfo返回数据集的定义
Dataset field |
Field order |
Size (bytes) |
Datatype |
Comments |
Standard Version |
1 |
2 |
UINT16 |
手机对PTP协议的支持程度,以%表示,默认是100 |
MTP Vendor Extension ID |
2 |
4 |
UINT32 |
手机对PTP厂商扩展协议的支持,默认是0xFFFFFFFF |
MTP Version |
3 |
2 |
UINT16 |
手机支持的MTP标准的版本,以%表示 |
MTP Extensions |
4 |
Variable |
String |
手机支持的MTP扩展集 |
Functional Mode |
5 |
2 |
UINT16 |
手机允许的模式 |
Operations Supported |
6 |
Variable |
Operation Code Array |
在当前功能模式下,手机支持的所有操作 |
Event Supported |
7 |
Variable |
Event Code Array |
在当前功能模式下,手机能产生的所有事件 |
Device Properties Supported |
8 |
Variable |
Device Property Code Array |
在当前功能模式下,手机支持的所有设备属性 |
Capture Formats |
9 |
Variable |
Object Format Code Array |
手机可以自己生成的文件格式,不包括拷贝到手机上文件格式 |
Playback Formats |
10 |
Variable |
Object Format Code Array |
手机可以解析和理解的所有格式类型 |
Manufacturer |
11 |
Variable |
String |
人可读的手机制造商的标识 |
Model |
12 |
Variable |
String |
人可读的手机型号 |
Device Version |
13 |
Variable |
String |
手机的软件或固件版本 |
Serial Number |
14 |
Variable |
String |
能标明手机MTP功能的唯一序列号 |
1.2 OS对MTP的支持及认证
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平台中的实现。