diff options
author | Mike Lockwood <lockwood@google.com> | 2014-01-13 10:31:01 -0800 |
---|---|---|
committer | Mike Lockwood <lockwood@google.com> | 2014-02-27 09:59:02 -0800 |
commit | 7531aa22355cf03f51def61ba67f1636bf85f408 (patch) | |
tree | 6053ba2a5de4c98879a3b05e4fcc6154e54f252f /core | |
parent | dfae159bb8a25a84dc24591d791ce1d743ba4252 (diff) | |
download | frameworks_base-7531aa22355cf03f51def61ba67f1636bf85f408.zip frameworks_base-7531aa22355cf03f51def61ba67f1636bf85f408.tar.gz frameworks_base-7531aa22355cf03f51def61ba67f1636bf85f408.tar.bz2 |
Add support for USB devices with multiple configurations and alternate interfaces
Added UsbConfiguration class, as well as accessors to UsbDevice to get configuration list
Added methods to UsbDeviceConnection to select configurations and alternate interfaces.
Also added accessors for USB descriptor name strings and fixed some memory leaks in the JNI code.
Bug: 12425052
Change-Id: Idb990f4d5c054a8cb997eb3f440f6da9f83bce05
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/hardware/usb/UsbConfiguration.java | 178 | ||||
-rw-r--r-- | core/java/android/hardware/usb/UsbDevice.java | 90 | ||||
-rw-r--r-- | core/java/android/hardware/usb/UsbDeviceConnection.java | 21 | ||||
-rw-r--r-- | core/java/android/hardware/usb/UsbInterface.java | 66 | ||||
-rw-r--r-- | core/java/com/android/internal/os/ZygoteInit.java | 2 | ||||
-rw-r--r-- | core/jni/android_hardware_UsbDeviceConnection.cpp | 33 |
6 files changed, 364 insertions, 26 deletions
diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java new file mode 100644 index 0000000..92d6f75 --- /dev/null +++ b/core/java/android/hardware/usb/UsbConfiguration.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.usb; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A class representing a configuration on a {@link UsbDevice}. + * A USB configuration can have one or more interfaces, each one providing a different + * piece of functionality, separate from the other interfaces. + * An interface will have one or more {@link UsbEndpoint}s, which are the + * channels by which the host transfers data with the device. + * + * <div class="special reference"> + * <h3>Developer Guides</h3> + * <p>For more information about communicating with USB hardware, read the + * <a href="{@docRoot}guide/topics/usb/index.html">USB</a> developer guide.</p> + * </div> + */ +public class UsbConfiguration implements Parcelable { + + private final int mId; + private final String mName; + private final int mAttributes; + private final int mMaxPower; + private Parcelable[] mInterfaces; + + /** + * Mask for "self-powered" bit in the configuration's attributes. + * @see #getAttributes + */ + public static final int ATTR_SELF_POWERED_MASK = 1 << 6; + + /** + * Mask for "remote wakeup" bit in the configuration's attributes. + * @see #getAttributes + */ + public static final int ATTR_REMOTE_WAKEUP_MASK = 1 << 5; + + /** + * UsbConfiguration should only be instantiated by UsbService implementation + * @hide + */ + public UsbConfiguration(int id, String name, int attributes, int maxPower) { + mId = id; + mName = name; + mAttributes = attributes; + mMaxPower = maxPower; + } + + /** + * Returns the configuration's ID field. + * This is an integer that uniquely identifies the configuration on the device. + * + * @return the configuration's ID + */ + public int getId() { + return mId; + } + + /** + * Returns the configuration's name. + * + * @return the configuration's name + */ + public String getName() { + return mName; + } + + /** + * Returns the configuration's attributes field. + * This field contains a bit field with the following flags: + * + * Bit 7: always set to 1 + * Bit 6: self-powered + * Bit 5: remote wakeup enabled + * Bit 0-4: reserved + * @see #ATTR_SELF_POWERED_MASK + * @see #ATTR_REMOTE_WAKEUP_MASK + * @return the configuration's attributes + */ + public int getAttributes() { + return mAttributes; + } + + /** + * Returns the configuration's max power consumption, in milliamps. + * + * @return the configuration's max power + */ + public int getMaxPower() { + return mMaxPower * 2; + } + + /** + * Returns the number of {@link UsbInterface}s this configuration contains. + * + * @return the number of endpoints + */ + public int getInterfaceCount() { + return mInterfaces.length; + } + + /** + * Returns the {@link UsbInterface} at the given index. + * + * @return the interface + */ + public UsbInterface getInterface(int index) { + return (UsbInterface)mInterfaces[index]; + } + + /** + * Only used by UsbService implementation + * @hide + */ + public void setInterfaces(Parcelable[] interfaces) { + mInterfaces = interfaces; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("UsbConfiguration[mId=" + mId + + ",mName=" + mName + ",mAttributes=" + mAttributes + + ",mMaxPower=" + mMaxPower + ",mInterfaces=["); + for (int i = 0; i < mInterfaces.length; i++) { + builder.append("\n"); + builder.append(mInterfaces[i].toString()); + } + builder.append("]"); + return builder.toString(); + } + + public static final Parcelable.Creator<UsbConfiguration> CREATOR = + new Parcelable.Creator<UsbConfiguration>() { + public UsbConfiguration createFromParcel(Parcel in) { + int id = in.readInt(); + String name = in.readString(); + int attributes = in.readInt(); + int maxPower = in.readInt(); + Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader()); + UsbConfiguration configuration = new UsbConfiguration(id, name, attributes, maxPower); + configuration.setInterfaces(interfaces); + return configuration; + } + + public UsbConfiguration[] newArray(int size) { + return new UsbConfiguration[size]; + } + }; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mId); + parcel.writeString(mName); + parcel.writeInt(mAttributes); + parcel.writeInt(mMaxPower); + parcel.writeParcelableArray(mInterfaces, 0); + } +} diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java index b0ba9c1..d90e06e 100644 --- a/core/java/android/hardware/usb/UsbDevice.java +++ b/core/java/android/hardware/usb/UsbDevice.java @@ -50,7 +50,10 @@ public class UsbDevice implements Parcelable { private final int mClass; private final int mSubclass; private final int mProtocol; - private final Parcelable[] mInterfaces; + private Parcelable[] mConfigurations; + + // list of all interfaces on the device + private UsbInterface[] mInterfaces; /** * UsbDevice should only be instantiated by UsbService implementation @@ -58,8 +61,7 @@ public class UsbDevice implements Parcelable { */ public UsbDevice(String name, int vendorId, int productId, int Class, int subClass, int protocol, - String manufacturerName, String productName, String serialNumber, - Parcelable[] interfaces) { + String manufacturerName, String productName, String serialNumber) { mName = name; mVendorId = vendorId; mProductId = productId; @@ -69,7 +71,6 @@ public class UsbDevice implements Parcelable { mManufacturerName = manufacturerName; mProductName = productName; mSerialNumber = serialNumber; - mInterfaces = interfaces; } /** @@ -169,21 +170,74 @@ public class UsbDevice implements Parcelable { } /** + * Returns the number of {@link UsbConfiguration}s this device contains. + * + * @return the number of configurations + */ + public int getConfigurationCount() { + return mConfigurations.length; + } + + /** + * Returns the {@link UsbConfiguration} at the given index. + * + * @return the configuration + */ + public UsbConfiguration getConfiguration(int index) { + return (UsbConfiguration)mConfigurations[index]; + } + + private UsbInterface[] getInterfaceList() { + if (mInterfaces == null) { + int configurationCount = mConfigurations.length; + int interfaceCount = 0; + for (int i = 0; i < configurationCount; i++) { + UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i]; + interfaceCount += configuration.getInterfaceCount(); + } + + mInterfaces = new UsbInterface[interfaceCount]; + int offset = 0; + for (int i = 0; i < configurationCount; i++) { + UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i]; + interfaceCount = configuration.getInterfaceCount(); + for (int j = 0; j < interfaceCount; j++) { + mInterfaces[offset++] = configuration.getInterface(j); + } + } + } + + return mInterfaces; + } + + /** * Returns the number of {@link UsbInterface}s this device contains. + * For devices with multiple configurations, you will probably want to use + * {@link UsbConfiguration#getInterfaceCount} instead. * * @return the number of interfaces */ public int getInterfaceCount() { - return mInterfaces.length; + return getInterfaceList().length; } /** * Returns the {@link UsbInterface} at the given index. + * For devices with multiple configurations, you will probably want to use + * {@link UsbConfiguration#getInterface} instead. * * @return the interface */ public UsbInterface getInterface(int index) { - return (UsbInterface)mInterfaces[index]; + return getInterfaceList()[index]; + } + + /** + * Only used by UsbService implementation + * @hide + */ + public void setConfigurations(Parcelable[] configuration) { + mConfigurations = configuration; } @Override @@ -204,11 +258,17 @@ public class UsbDevice implements Parcelable { @Override public String toString() { - return "UsbDevice[mName=" + mName + ",mVendorId=" + mVendorId + - ",mProductId=" + mProductId + ",mClass=" + mClass + - ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + + StringBuilder builder = new StringBuilder("UsbDevice[mName=" + mName + + ",mVendorId=" + mVendorId + ",mProductId=" + mProductId + + ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName + - ",mSerialNumber=" + mSerialNumber + ",mInterfaces=" + mInterfaces + "]"; + ",mSerialNumber=" + mSerialNumber + ",mConfigurations=["); + for (int i = 0; i < mConfigurations.length; i++) { + builder.append("\n"); + builder.append(mConfigurations[i].toString()); + } + builder.append("]"); + return builder.toString(); } public static final Parcelable.Creator<UsbDevice> CREATOR = @@ -223,9 +283,11 @@ public class UsbDevice implements Parcelable { String manufacturerName = in.readString(); String productName = in.readString(); String serialNumber = in.readString(); - Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader()); - return new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, - manufacturerName, productName, serialNumber, interfaces); + Parcelable[] configurations = in.readParcelableArray(UsbInterface.class.getClassLoader()); + UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, + manufacturerName, productName, serialNumber); + device.setConfigurations(configurations); + return device; } public UsbDevice[] newArray(int size) { @@ -247,7 +309,7 @@ public class UsbDevice implements Parcelable { parcel.writeString(mManufacturerName); parcel.writeString(mProductName); parcel.writeString(mSerialNumber); - parcel.writeParcelableArray(mInterfaces, 0); + parcel.writeParcelableArray(mConfigurations, 0); } public static int getDeviceId(String name) { diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index 389475f..6283951 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -101,6 +101,25 @@ public class UsbDeviceConnection { } /** + * Sets the current {@link android.hardware.usb.UsbInterface}. + * Used to select between two interfaces with the same ID but different alternate setting. + * + * @return true if the interface was successfully released + */ + public boolean setInterface(UsbInterface intf) { + return native_set_interface(intf.getId(), intf.getAlternateSetting()); + } + + /** + * Sets the device's current {@link android.hardware.usb.UsbConfiguration}. + * + * @return true if the configuration was successfully set + */ + public boolean setConfiguration(UsbConfiguration configuration) { + return native_set_configuration(configuration.getId()); + } + + /** * Performs a control transaction on endpoint zero for this device. * The direction of the transfer is determined by the request type. * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is @@ -236,6 +255,8 @@ public class UsbDeviceConnection { private native byte[] native_get_desc(); private native boolean native_claim_interface(int interfaceID, boolean force); private native boolean native_release_interface(int interfaceID); + private native boolean native_set_interface(int interfaceID, int alternateSetting); + private native boolean native_set_configuration(int configurationID); private native int native_control_request(int requestType, int request, int value, int index, byte[] buffer, int offset, int length, int timeout); private native int native_bulk_request(int endpoint, byte[] buffer, diff --git a/core/java/android/hardware/usb/UsbInterface.java b/core/java/android/hardware/usb/UsbInterface.java index e94baa1..de01a88 100644 --- a/core/java/android/hardware/usb/UsbInterface.java +++ b/core/java/android/hardware/usb/UsbInterface.java @@ -35,27 +35,31 @@ import android.os.Parcelable; public class UsbInterface implements Parcelable { private final int mId; + private final int mAlternateSetting; + private final String mName; private final int mClass; private final int mSubclass; private final int mProtocol; - private final Parcelable[] mEndpoints; + private Parcelable[] mEndpoints; /** * UsbInterface should only be instantiated by UsbService implementation * @hide */ - public UsbInterface(int id, int Class, int subClass, int protocol, - Parcelable[] endpoints) { + public UsbInterface(int id, int alternateSetting, String name, + int Class, int subClass, int protocol) { mId = id; + mAlternateSetting = alternateSetting; + mName = name; mClass = Class; mSubclass = subClass; mProtocol = protocol; - mEndpoints = endpoints; } /** - * Returns the interface's ID field. - * This is an integer that uniquely identifies the interface on the device. + * Returns the interface's bInterfaceNumber field. + * This is an integer that along with the alternate setting uniquely identifies + * the interface on the device. * * @return the interface's ID */ @@ -64,6 +68,28 @@ public class UsbInterface implements Parcelable { } /** + * Returns the interface's bAlternateSetting field. + * This is an integer that along with the ID uniquely identifies + * the interface on the device. + * {@link UsbDeviceConnection#setInterface} can be used to switch between + * two interfaces with the same ID but different alternate setting. + * + * @return the interface's alternate setting + */ + public int getAlternateSetting() { + return mAlternateSetting; + } + + /** + * Returns the interface's name. + * + * @return the interface's name + */ + public String getName() { + return mName; + } + + /** * Returns the interface's class field. * Some useful constants for USB classes can be found in {@link UsbConstants} * @@ -109,22 +135,42 @@ public class UsbInterface implements Parcelable { return (UsbEndpoint)mEndpoints[index]; } + /** + * Only used by UsbService implementation + * @hide + */ + public void setEndpoints(Parcelable[] endpoints) { + mEndpoints = endpoints; + } + @Override public String toString() { - return "UsbInterface[mId=" + mId + ",mClass=" + mClass + + StringBuilder builder = new StringBuilder("UsbInterface[mId=" + mId + + ",mAlternateSetting=" + mAlternateSetting + + ",mName=" + mName + ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + - ",mEndpoints=" + mEndpoints + "]"; + ",mEndpoints=["); + for (int i = 0; i < mEndpoints.length; i++) { + builder.append("\n"); + builder.append(mEndpoints[i].toString()); + } + builder.append("]"); + return builder.toString(); } public static final Parcelable.Creator<UsbInterface> CREATOR = new Parcelable.Creator<UsbInterface>() { public UsbInterface createFromParcel(Parcel in) { int id = in.readInt(); + int alternateSetting = in.readInt(); + String name = in.readString(); int Class = in.readInt(); int subClass = in.readInt(); int protocol = in.readInt(); Parcelable[] endpoints = in.readParcelableArray(UsbEndpoint.class.getClassLoader()); - return new UsbInterface(id, Class, subClass, protocol, endpoints); + UsbInterface intf = new UsbInterface(id, alternateSetting, name, Class, subClass, protocol); + intf.setEndpoints(endpoints); + return intf; } public UsbInterface[] newArray(int size) { @@ -138,6 +184,8 @@ public class UsbInterface implements Parcelable { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(mId); + parcel.writeInt(mAlternateSetting); + parcel.writeString(mName); parcel.writeInt(mClass); parcel.writeInt(mSubclass); parcel.writeInt(mProtocol); diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index bf62745..05c57e8 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -244,9 +244,11 @@ public class ZygoteInit { } static void preload() { + Log.d(TAG, "begin preload"); preloadClasses(); preloadResources(); preloadOpenGL(); + Log.d(TAG, "end preload"); } private static void preloadOpenGL() { diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp index c10b963..467a9a1 100644 --- a/core/jni/android_hardware_UsbDeviceConnection.cpp +++ b/core/jni/android_hardware_UsbDeviceConnection.cpp @@ -123,20 +123,45 @@ android_hardware_UsbDeviceConnection_claim_interface(JNIEnv *env, jobject thiz, return (ret == 0) ? JNI_TRUE : JNI_FALSE; } -static jint +static jboolean android_hardware_UsbDeviceConnection_release_interface(JNIEnv *env, jobject thiz, jint interfaceID) { struct usb_device* device = get_device_from_object(env, thiz); if (!device) { ALOGE("device is closed in native_release_interface"); - return -1; + return JNI_FALSE; } int ret = usb_device_release_interface(device, interfaceID); if (ret == 0) { // allow kernel to reconnect its driver usb_device_connect_kernel_driver(device, interfaceID, true); } - return ret; + return (ret == 0) ? JNI_TRUE : JNI_FALSE; +} + +static jboolean +android_hardware_UsbDeviceConnection_set_interface(JNIEnv *env, jobject thiz, jint interfaceID, + jint alternateSetting) +{ + struct usb_device* device = get_device_from_object(env, thiz); + if (!device) { + ALOGE("device is closed in native_set_interface"); + return JNI_FALSE; + } + int ret = usb_device_set_interface(device, interfaceID, alternateSetting); + return (ret == 0) ? JNI_TRUE : JNI_FALSE; +} + +static jboolean +android_hardware_UsbDeviceConnection_set_configuration(JNIEnv *env, jobject thiz, jint configurationID) +{ + struct usb_device* device = get_device_from_object(env, thiz); + if (!device) { + ALOGE("device is closed in native_set_configuration"); + return JNI_FALSE; + } + int ret = usb_device_set_configuration(device, configurationID); + return (ret == 0) ? JNI_TRUE : JNI_FALSE; } static jint @@ -229,6 +254,8 @@ static JNINativeMethod method_table[] = { {"native_get_desc", "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc}, {"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface}, {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface}, + {"native_set_interface","(II)Z", (void *)android_hardware_UsbDeviceConnection_set_interface}, + {"native_set_configuration","(I)Z", (void *)android_hardware_UsbDeviceConnection_set_configuration}, {"native_control_request", "(IIII[BIII)I", (void *)android_hardware_UsbDeviceConnection_control_request}, {"native_bulk_request", "(I[BIII)I", |