您的位置:首页 > 移动开发 > Android开发

Android5.0 OTG模块传输速度

2015-08-25 09:34 726 查看

对OTG的分析:

/article/1391047.html

文章中有提到这部分是在Vold模块中进行处理:

这是一个在线浏览Linux内核源码的网站:http://lxr.linux.no/

Linux内核早就提供了OTG的驱动,在http://lxr.linux.no/linux+v3.1.6/drivers/usb/gadget/目录下,Linux将usb与otg两个功能模块给独立开了,主要的驱动是file_storage.c,该驱动主要负责终端设备的存储设备节点的操作,比如,从电脑,在该终端的磁盘上面创建文件,都会通过这个驱动来完成存储任务。另外一个驱动主要是负责USB通信的,是结尾为"_udc.c"的驱动源码,该目录下有好几个以"_udc.c"结尾的文件,这是针对不同型号的处理器而增加的,不同厂家提供不同的驱动。

这里只是简单的介绍,Android在vold中处理otg,就是将要共享的磁盘设备写到一个标志文件里面,再广播一下大容量存储连接的状态。

OTG体系架构:

/article/7829415.html

对OTG的使用

http://www.crifan.com/android_phone_support_usb_host/

Android OTG功能开发

http://happyboy200032.blog.163.com/blog/static/469031132015265541168/

OTG驱动分析:

/article/9637546.html

驱动分析:

/article/9001587.html

/article/3677507.html

http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763105392230e54f7636d918d027fa3c215cc7902155a66e1b821201019d3c0776303ae5e5c9daa702d691765eadb9e871981edd27574de30340141c014&p=882a9645d7d21de70be2966d4c4e92&newp=c9759a46d6c210fc57efdf35554896231610db2151d4d2162e&user=baidu&fm=sc&query=Android+OTG&qid=996d9fd6000ab43f&p1=7

Android4.0 OTG 数据上报过程分析:

http://blog.chinaunix.net/uid-25909619-id-3255681.html

/article/2694054.html

OTG应用开发:

/article/8386969.html

底层插入上报过程分析:

/article/8959982.html

Android USB/MTP相关

/article/9030079.html

Nenux 5支持OTG

http://bbs.gfan.com/android-4257863-1-1.html

应用层分析:
1.首先拿到UsbManager:
manager = (UsbManager) getSystemService(Context.USB_SERVICE);
2.通过PID,VID得到目标设备:
HashMap<String,UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while (deviceIterator.hasNext())
{
UsbDevice device = deviceIterator.next();
if((DEVICE_PID == device.getProductId())
&& (DEVICE_VID == device.getVendorId())
)
{
mUsbDevice = device;
break;
}
}

3.通过UsbManager建立设备连接:
UsbDeviceConnection connection = manager.openDevice(mUsbDevice);

4.获取输入输出端点
private void getEndpoint(UsbDeviceConnection connection, UsbInterface intf)
{
if (intf.getEndpoint(1) != null)
{
epOut = intf.getEndpoint(1);
}

if (intf.getEndpoint(0) != null)
{
epIn = intf.getEndpoint(0);
}
}

端点位于USB 外设内部,所有通信数据的来源或目的都基于这些端点,是一个可寻址的FIFO。 每个USB 外设有一个唯一的地址,可能包含最多十六个端点。主机通过发出器件地址和每次数据传输的端点号,向一个具体端点(FIFO)发送数据。
详细参看:
http://wenku.baidu.com/link?url=_GRI7jquZTi6XHe5jo0_KRdfqMJjzbg_uenQ-lmesKKA1xKsBqC8if87tk7ULdEY87M9kKwhJSDyPxqdM2KeqduYyTFI9ftIMb3wFwgSuka

5.从4中的epIn端点中获取数据(这个函数应该是阻塞的):
out = mDeviceConnection.bulkTransfer(epIn, byte2, byte2.length, 0);

6.bulkTransfer调用的是native_bulk_request
/**
* Performs a bulk transaction on the given endpoint.
* The direction of the transfer is determined by the direction of the endpoint.
*
* @param endpoint the endpoint for this transaction
* @param buffer buffer for data to send or receive
* @param offset the index of the first byte in the buffer to send or receive
* @param length the length of the data to send or receive
* @param timeout in milliseconds
* @return length of data transferred (or zero) for success,
* or negative value for failure
*/
public int bulkTransfer(UsbEndpoint endpoint,
byte[] buffer, int offset, int length, int timeout) {
checkBounds(buffer, offset, length);
return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout);
}


7.android_hardware_UsbDeviceConnection.cpp中的native_bulk_request:
android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz,
jint endpoint, jbyteArray buffer, jint start, jint length, jint timeout)
{
struct usb_device* device = get_device_from_object(env, thiz);
if (!device) {
ALOGE("device is closed in native_control_request");
return -1;
}

jbyte* bufferBytes = NULL;
if (buffer) {
bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
}

jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout);

if (bufferBytes) {
env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
}

return result;
}
8.最后的usb_device_bulk_transfer是Usbhost.c中的函数:
int usb_device_bulk_transfer(struct usb_device *device,
int endpoint,
void* buffer,
int length,
unsigned int timeout)
{
struct usbdevfs_bulktransfer  ctrl;

// need to limit request size to avoid EINVAL
if (length > MAX_USBFS_BUFFER_SIZE)
length = MAX_USBFS_BUFFER_SIZE;

memset(&ctrl, 0, sizeof(ctrl));
ctrl.ep = endpoint;
ctrl.len = length;
ctrl.data = buffer;
ctrl.timeout = timeout;
return ioctl(device->fd, USBDEVFS_BULK, &ctrl);
}


框架层代码是在\frameworks\base\core\java\android\hardware\usb目录下:
UsbDeviceConnection用来收发数据,在UsbManager中被实例化
/**

* This class is used for sending and receiving data and control messages to a USB device.

* Instances of this class are created by
{@link UsbManager#openDevice}.

*/
UsbDevice包含设备Name,VendorId,ProductId,Class类型,SubClass类型,Protocol类型这六项信息。
Usbmanager通过Bundler机制获取Usb设备的哈希表:
/**
* Returns a HashMap containing all USB devices currently attached.
* USB device name is the key for the returned HashMap.
* The result will be empty if no devices are attached, or if
* USB host mode is inactive or unsupported.
*
* @return HashMap containing all connected USB devices.
*/
public HashMap<String,UsbDevice> getDeviceList() {
Bundle bundle = new Bundle();
try {
mService.getDeviceList(bundle);
HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>();
for (String name : bundle.keySet()) {
result.put(name, (UsbDevice)bundle.get(name));
}
return result;
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in getDeviceList", e);
return null;
}
}

而UsbManager的构造函数为
/**
* Returns a new instance of this class.
*
* @param context the caller's {@link android.content.Context}
* @return UsbManager instance.
*/
public static UsbManager getInstance(Context context) {
IBinder b = ServiceManager.getService(Context.USB_SERVICE);
return new UsbManager(context, IUsbManager.Stub.asInterface(b));
}

因此这里调用的mService.getDeviceList(bundler);的实现是在UsbService.java中:
/* Returns a list of all currently attached USB devices (host mdoe) */
@Override
public void getDeviceList(Bundle devices) {
if (mHostManager != null) {
mHostManager.getDeviceList(devices);
}
}

UsbHostManager.java
// contains all connected USB devices
private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>();

...
...

/* Returns a list of all currently attached USB devices */
public void getDeviceList(Bundle devices) {
synchronized (mLock) {
for (String name : mDevices.keySet()) {
devices.putParcelable(name, mDevices.get(name));
}
}
}


而Usb设备的侦测和记录是在这个函数里:
/* Called from JNI in monitorUsbHostBus() to report new USB devices */
private void usbDeviceAdded(String deviceName, int vendorID, int productID,
int deviceClass, int deviceSubclass, int deviceProtocol,
/* array of quintuples containing id, class, subclass, protocol
and number of endpoints for each interface */
int[] interfaceValues,
/* array of quadruples containing address, attributes, max packet size
and interval for each endpoint */
int[] endpointValues) {

if (isBlackListed(deviceName) ||
isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
return;
}

synchronized (mLock) {
if (mDevices.get(deviceName) != null) {
Slog.w(TAG, "device already on mDevices list: " + deviceName);
return;
}

int numInterfaces = interfaceValues.length / 5;
Parcelable[] interfaces = new UsbInterface[numInterfaces];
try {
// repackage interfaceValues as an array of UsbInterface
int intf, endp, ival = 0, eval = 0;
for (intf = 0; intf < numInterfaces; intf++) {
int interfaceId = interfaceValues[ival++];
int interfaceClass = interfaceValues[ival++];
int interfaceSubclass = interfaceValues[ival++];
int interfaceProtocol = interfaceValues[ival++];
int numEndpoints = interfaceValues[ival++];

Parcelable[] endpoints = new UsbEndpoint[numEndpoints];
for (endp = 0; endp < numEndpoints; endp++) {
int address = endpointValues[eval++];
int attributes = endpointValues[eval++];
int maxPacketSize = endpointValues[eval++];
int interval = endpointValues[eval++];
endpoints[endp] = new UsbEndpoint(address, attributes,
maxPacketSize, interval);
}

// don't allow if any interfaces are blacklisted
if (isBlackListed(interfaceClass, interfaceSubclass, interfaceProtocol)) {
return;
}
interfaces[intf] = new UsbInterface(interfaceId, interfaceClass,
interfaceSubclass, interfaceProtocol, endpoints);
}
} catch (Exception e) {
// beware of index out of bound exceptions, which might happen if
// a device does not set bNumEndpoints correctly
Slog.e(TAG, "error parsing USB descriptors", e);
return;
}
<span style="color:#ff0000;">
UsbDevice device = new UsbDevice(deviceName, vendorID, productID,
deviceClass, deviceSubclass, deviceProtocol, interfaces);
mDevices.put(deviceName, device);
getCurrentSettings().deviceAttached(device);</span>
}
}


这里的interfaceValues包含设备的相关信息,每个设备5项,因此将数组总长度除以5就得到了设备的个数(代码写得不好)在这里,将数组信息转换成UsbInterface类来存储。
这里的endpointValues包含设备的端点信息,每个端点4项,只不过端点个数在interfaceValues中携带了,因此直接取这个数组就能得到设备的各个端点信息。
UsbDevice:
public class UsbDevice implements Parcelable {

private static final String TAG = "UsbDevice";

private final String mName;
private final int mVendorId;
private final int mProductId;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
private final Parcelable[] mInterfaces;
}


UsbInterface:
public class UsbInterface implements Parcelable {

private final int mId;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
private final Parcelable[] mEndpoints;
}


UsbEndpoint
public class UsbEndpoint implements Parcelable {

private final int mAddress;
private final int mAttributes;
private final int mMaxPacketSize;
private final int mInterval;
}

从上面的分析也体现了一个设备有多个接口,每个接口有多个端点

Native层的分析
通过Native层的分析可以知道设备信息是怎么报送到java层的:
系统开机时,在UsbHostManager中便启动了一个usb设备相关的服务
public void systemReady() {
synchronized (mLock) {
// Create a thread to call into native code to wait for USB host events.
// This thread will call us back on usbDeviceAdded and usbDeviceRemoved.
Runnable runnable = new Runnable() {
public void run() {
monitorUsbHostBus();
}
};
new Thread(null, runnable, "UsbService host thread").start();
}
}

跑的是一个jni函数monitorUsbHostBus
private native void monitorUsbHostBus();

jni函数实现是在:com_android_server_UsbHostManager.cpp (\frameworks\base\services\jni)

static void android_server_UsbHostManager_monitorUsbHostBus(JNIEnv *env, jobject thiz)
{
struct usb_host_context* context = usb_host_init();
if (!context) {
ALOGE("usb_host_init failed");
return;
}
// this will never return so it is safe to pass thiz directly
usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)thiz);
}


Usbhost.c (\system\core\libusbhost)
void usb_host_run(struct usb_host_context *context,
usb_device_added_cb added_cb,
usb_device_removed_cb removed_cb,
usb_discovery_done_cb discovery_done_cb,
void *client_data)
{
int done;

done = usb_host_load(context, added_cb, removed_cb, discovery_done_cb, client_data);

while (!done) {

done = usb_host_read_event(context);
}
} /* usb_host_run() */


int usb_host_load(struct usb_host_context *context,
usb_device_added_cb added_cb,
usb_device_removed_cb removed_cb,
usb_discovery_done_cb discovery_done_cb,
void *client_data)
{
int done = 0;
int i;

context->cb_added = added_cb;
context->cb_removed = removed_cb;
context->data = client_data;

D("Created device discovery thread\n");

/* watch for files added and deleted within USB_FS_DIR */
for (i = 0; i < MAX_USBFS_WD_COUNT; i++)
context->wds[i] = -1;

/* watch the root for new subdirectories */
context->wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);
if (context->wdd < 0) {
fprintf(stderr, "inotify_add_watch failed\n");
if (discovery_done_cb)
discovery_done_cb(client_data);
return done;
}

watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);

/* check for existing devices first, after we have inotify set up */
done = find_existing_devices(added_cb, client_data);
if (discovery_done_cb)
done |= discovery_done_cb(client_data);

return done;
} /* usb_host_load() */

在usbhost.c中可以看到注册了usb_device_added,usb_device_removed两个回调函数。
这里usb_host_load函数中通过notify机制使得设备监听IN_CREATE,IN_DELETE两个类型的事件。监听到事件后通过jni调用java中的相应函数实现回调:
method_usbDeviceAdded = env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;IIIII[I[I)V");
static int usb_device_added(const char *devname, void* client_data) {
...
env->CallVoidMethod(thiz, method_usbDeviceAdded,
deviceName, vendorId, productId, deviceClass,
deviceSubClass, protocol, interfaceArray, endpointArray);
...
}


然后再通过usb_host_read_event读取监听的事件
int usb_host_read_event(struct usb_host_context *context)
{
struct inotify_event* event;
char event_buf[512];
char path[100];
int i, ret, done = 0;
int offset = 0;
int wd;

ret = read(context->fd, event_buf, sizeof(event_buf));
if (ret >= (int)sizeof(struct inotify_event)) {
while (offset < ret) {
event = (struct inotify_event*)&event_buf[offset];
done = 0;
wd = event->wd;
if (wd == context->wdd) {
if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {
watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
done = find_existing_devices(context->cb_added, context->data);
} else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) {
for (i = 0; i < MAX_USBFS_WD_COUNT; i++) {
if (context->wds[i] >= 0) {
inotify_rm_watch(context->fd, context->wds[i]);
context->wds[i] = -1;
}
}
}
} else if (wd == context->wds[0]) {
i = atoi(event->name);
snprintf(path, sizeof(path), USB_FS_DIR "/%s", event->name);
D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
"new" : "gone", path, i);
if (i > 0 && i < MAX_USBFS_WD_COUNT) {
if (event->mask & IN_CREATE) {
ret = inotify_add_watch(context->fd, path,
IN_CREATE | IN_DELETE);
if (ret >= 0)
context->wds[i] = ret;
done = find_existing_devices_bus(path, context->cb_added,
context->data);
} else if (event->mask & IN_DELETE) {
inotify_rm_watch(context->fd, context->wds[i]);
context->wds[i] = -1;
}
}
} else {
for (i = 1; (i < MAX_USBFS_WD_COUNT) && !done; i++) {
if (wd == context->wds[i]) {
snprintf(path, sizeof(path), USB_FS_DIR "/%03d/%s", i, event->name);
if (event->mask == IN_CREATE) {
D("new device %s\n", path);
done = context->cb_added(path, context->data);
} else if (event->mask == IN_DELETE) {
D("gone device %s\n", path);
done = context->cb_removed(path, context->data);
}
}
}
}

offset += sizeof(struct inotify_event) + event->len;
}
}

return done;
} /* usb_host_read_event() */


这里要关注下usb_host_context
struct usb_host_context {
int                         fd;
usb_device_added_cb         cb_added;
usb_device_removed_cb       cb_removed;
void                        *data;
int                         wds[MAX_USBFS_WD_COUNT];
int                         wdd;
};

其中wdd是watch descriptor ,wds是

(Linux notify机制参见:/article/7800985.html,单独博客表述。)

UsbResolverActivity中会通过IUsbmanager.Stub.asInterface(b);获取service






内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: