Android5.0 OTG模块传输速度



对OTG的分析:

http://blog.csdn.net/gzshun/article/details/7171781

文章中有提到这部分是在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体系架构:

http://blog.csdn.net/srw11/article/details/39154053

对OTG的使用

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

Android OTG功能开发

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

OTG驱动分析:

http://blog.csdn.net/ling1874/article/details/5758883

驱动分析:

http://blog.csdn.net/fanqipin/article/details/8450694

http://blog.csdn.net/xubin341719/article/details/7707056

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

http://blog.csdn.net/kangear/article/details/38140537

OTG应用开发:

http://blog.csdn.net/tianruxishui/article/details/37905313


底层插入上报过程分析:

http://blog.csdn.net/cosmoslhf/article/details/13022923

Android USB/MTP相关

http://blog.csdn.net/kv110/article/details/39934319

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)发送数据。
详细参看:

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机制参见: http://blog.csdn.net/myarrow/article/details/7096460,单独博客表述。)


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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值