1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.usb; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SystemApi; 22 import android.content.Context; 23 import android.os.Build; 24 import android.os.ParcelFileDescriptor; 25 26 import com.android.internal.util.Preconditions; 27 28 import dalvik.system.CloseGuard; 29 30 import java.io.FileDescriptor; 31 import java.nio.BufferOverflowException; 32 import java.nio.ByteBuffer; 33 import java.util.concurrent.TimeoutException; 34 35 /** 36 * This class is used for sending and receiving data and control messages to a USB device. 37 * Instances of this class are created by {@link UsbManager#openDevice}. 38 */ 39 public class UsbDeviceConnection { 40 41 private static final String TAG = "UsbDeviceConnection"; 42 43 private final UsbDevice mDevice; 44 45 private Context mContext; 46 47 // used by the JNI code 48 private long mNativeContext; 49 50 private final CloseGuard mCloseGuard = CloseGuard.get(); 51 52 /** 53 * UsbDevice should only be instantiated by UsbService implementation 54 * @hide 55 */ UsbDeviceConnection(UsbDevice device)56 public UsbDeviceConnection(UsbDevice device) { 57 mDevice = device; 58 } 59 open(String name, ParcelFileDescriptor pfd, @NonNull Context context)60 /* package */ boolean open(String name, ParcelFileDescriptor pfd, @NonNull Context context) { 61 mContext = context.getApplicationContext(); 62 boolean wasOpened = native_open(name, pfd.getFileDescriptor()); 63 64 if (wasOpened) { 65 mCloseGuard.open("close"); 66 } 67 68 return wasOpened; 69 } 70 71 /** 72 * @return The application context the connection was created for. 73 * 74 * @hide 75 */ getContext()76 public @Nullable Context getContext() { 77 return mContext; 78 } 79 80 /** 81 * Releases all system resources related to the device. 82 * Once the object is closed it cannot be used again. 83 * The client must call {@link UsbManager#openDevice} again 84 * to retrieve a new instance to reestablish communication with the device. 85 */ close()86 public void close() { 87 if (mNativeContext != 0) { 88 native_close(); 89 mCloseGuard.close(); 90 } 91 } 92 93 /** 94 * Returns the native file descriptor for the device, or 95 * -1 if the device is not opened. 96 * This is intended for passing to native code to access the device. 97 * 98 * @return the native file descriptor 99 */ getFileDescriptor()100 public int getFileDescriptor() { 101 return native_get_fd(); 102 } 103 104 /** 105 * Returns the raw USB descriptors for the device. 106 * This can be used to access descriptors not supported directly 107 * via the higher level APIs. 108 * 109 * @return raw USB descriptors 110 */ getRawDescriptors()111 public byte[] getRawDescriptors() { 112 return native_get_desc(); 113 } 114 115 /** 116 * Claims exclusive access to a {@link android.hardware.usb.UsbInterface}. 117 * This must be done before sending or receiving data on any 118 * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface. 119 * 120 * @param intf the interface to claim 121 * @param force true to disconnect kernel driver if necessary 122 * @return true if the interface was successfully claimed 123 */ claimInterface(UsbInterface intf, boolean force)124 public boolean claimInterface(UsbInterface intf, boolean force) { 125 return native_claim_interface(intf.getId(), force); 126 } 127 128 /** 129 * Releases exclusive access to a {@link android.hardware.usb.UsbInterface}. 130 * 131 * @return true if the interface was successfully released 132 */ releaseInterface(UsbInterface intf)133 public boolean releaseInterface(UsbInterface intf) { 134 return native_release_interface(intf.getId()); 135 } 136 137 /** 138 * Sets the current {@link android.hardware.usb.UsbInterface}. 139 * Used to select between two interfaces with the same ID but different alternate setting. 140 * 141 * @return true if the interface was successfully selected 142 */ setInterface(UsbInterface intf)143 public boolean setInterface(UsbInterface intf) { 144 return native_set_interface(intf.getId(), intf.getAlternateSetting()); 145 } 146 147 /** 148 * Sets the device's current {@link android.hardware.usb.UsbConfiguration}. 149 * 150 * @return true if the configuration was successfully set 151 */ setConfiguration(UsbConfiguration configuration)152 public boolean setConfiguration(UsbConfiguration configuration) { 153 return native_set_configuration(configuration.getId()); 154 } 155 156 /** 157 * Performs a control transaction on endpoint zero for this device. 158 * The direction of the transfer is determined by the request type. 159 * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is 160 * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write, 161 * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer 162 * is a read. 163 * <p> 164 * This method transfers data starting from index 0 in the buffer. 165 * To specify a different offset, use 166 * {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}. 167 * </p> 168 * 169 * @param requestType request type for this transaction 170 * @param request request ID for this transaction 171 * @param value value field for this transaction 172 * @param index index field for this transaction 173 * @param buffer buffer for data portion of transaction, 174 * or null if no data needs to be sent or received 175 * @param length the length of the data to send or receive 176 * @param timeout in milliseconds 177 * @return length of data transferred (or zero) for success, 178 * or negative value for failure 179 */ controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout)180 public int controlTransfer(int requestType, int request, int value, 181 int index, byte[] buffer, int length, int timeout) { 182 return controlTransfer(requestType, request, value, index, buffer, 0, length, timeout); 183 } 184 185 /** 186 * Performs a control transaction on endpoint zero for this device. 187 * The direction of the transfer is determined by the request type. 188 * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is 189 * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write, 190 * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer 191 * is a read. 192 * 193 * @param requestType request type for this transaction 194 * @param request request ID for this transaction 195 * @param value value field for this transaction 196 * @param index index field for this transaction 197 * @param buffer buffer for data portion of transaction, 198 * or null if no data needs to be sent or received 199 * @param offset the index of the first byte in the buffer to send or receive 200 * @param length the length of the data to send or receive 201 * @param timeout in milliseconds 202 * @return length of data transferred (or zero) for success, 203 * or negative value for failure 204 */ controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int offset, int length, int timeout)205 public int controlTransfer(int requestType, int request, int value, int index, 206 byte[] buffer, int offset, int length, int timeout) { 207 checkBounds(buffer, offset, length); 208 return native_control_request(requestType, request, value, index, 209 buffer, offset, length, timeout); 210 } 211 212 /** 213 * Performs a bulk transaction on the given endpoint. 214 * The direction of the transfer is determined by the direction of the endpoint. 215 * <p> 216 * This method transfers data starting from index 0 in the buffer. 217 * To specify a different offset, use 218 * {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)}. 219 * </p> 220 * 221 * @param endpoint the endpoint for this transaction 222 * @param buffer buffer for data to send or receive; can be {@code null} to wait for next 223 * transaction without reading data 224 * @param length the length of the data to send or receive 225 * @param timeout in milliseconds, 0 is infinite 226 * @return length of data transferred (or zero) for success, 227 * or negative value for failure 228 */ bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout)229 public int bulkTransfer(UsbEndpoint endpoint, 230 byte[] buffer, int length, int timeout) { 231 return bulkTransfer(endpoint, buffer, 0, length, timeout); 232 } 233 234 /** 235 * Performs a bulk transaction on the given endpoint. 236 * The direction of the transfer is determined by the direction of the endpoint. 237 * 238 * @param endpoint the endpoint for this transaction 239 * @param buffer buffer for data to send or receive 240 * @param offset the index of the first byte in the buffer to send or receive 241 * @param length the length of the data to send or receive 242 * @param timeout in milliseconds, 0 is infinite 243 * @return length of data transferred (or zero) for success, 244 * or negative value for failure 245 */ bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int offset, int length, int timeout)246 public int bulkTransfer(UsbEndpoint endpoint, 247 byte[] buffer, int offset, int length, int timeout) { 248 checkBounds(buffer, offset, length); 249 return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout); 250 } 251 252 /** 253 * Reset USB port for the connected device. 254 * 255 * @return true if reset succeeds. 256 * 257 * @hide 258 */ 259 @SystemApi resetDevice()260 public boolean resetDevice() { 261 return native_reset_device(); 262 } 263 264 /** 265 * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation 266 * <p>Note that this may return requests queued on multiple 267 * {@link android.hardware.usb.UsbEndpoint}s. When multiple endpoints are in use, 268 * {@link android.hardware.usb.UsbRequest#getEndpoint} and {@link 269 * android.hardware.usb.UsbRequest#getClientData} can be useful in determining how to process 270 * the result of this function.</p> 271 * 272 * @return a completed USB request, or null if an error occurred 273 * 274 * @throws IllegalArgumentException Before API {@value Build.VERSION_CODES#O}: if the number of 275 * bytes read or written is more than the limit of the 276 * request's buffer. The number of bytes is determined by the 277 * {@code length} parameter of 278 * {@link UsbRequest#queue(ByteBuffer, int)} 279 * @throws BufferOverflowException In API {@value Build.VERSION_CODES#O} and after: if the 280 * number of bytes read or written is more than the limit of the 281 * request's buffer. The number of bytes is determined by the 282 * {@code length} parameter of 283 * {@link UsbRequest#queue(ByteBuffer, int)} 284 */ requestWait()285 public UsbRequest requestWait() { 286 UsbRequest request = null; 287 try { 288 // -1 is special value indicating infinite wait 289 request = native_request_wait(-1); 290 } catch (TimeoutException e) { 291 // Does not happen, infinite timeout 292 } 293 294 if (request != null) { 295 request.dequeue( 296 mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O); 297 } 298 return request; 299 } 300 301 /** 302 * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation 303 * <p>Note that this may return requests queued on multiple 304 * {@link android.hardware.usb.UsbEndpoint}s. When multiple endpoints are in use, 305 * {@link android.hardware.usb.UsbRequest#getEndpoint} and {@link 306 * android.hardware.usb.UsbRequest#getClientData} can be useful in determining how to process 307 * the result of this function.</p> 308 * <p>Android processes {@link UsbRequest UsbRequests} asynchronously. Hence it is not 309 * guaranteed that {@link #requestWait(long) requestWait(0)} returns a request that has been 310 * queued right before even if the request could have been processed immediately.</p> 311 * 312 * @param timeout timeout in milliseconds. If 0 this method does not wait. 313 * 314 * @return a completed USB request, or {@code null} if an error occurred 315 * 316 * @throws BufferOverflowException if the number of bytes read or written is more than the 317 * limit of the request's buffer. The number of bytes is 318 * determined by the {@code length} parameter of 319 * {@link UsbRequest#queue(ByteBuffer, int)} 320 * @throws TimeoutException if no request was received in {@code timeout} milliseconds. 321 */ requestWait(long timeout)322 public UsbRequest requestWait(long timeout) throws TimeoutException { 323 timeout = Preconditions.checkArgumentNonnegative(timeout, "timeout"); 324 325 UsbRequest request = native_request_wait(timeout); 326 if (request != null) { 327 request.dequeue(true); 328 } 329 return request; 330 } 331 332 /** 333 * Returns the serial number for the device. 334 * This will return null if the device has not been opened. 335 * 336 * @return the device serial number 337 */ getSerial()338 public String getSerial() { 339 return native_get_serial(); 340 } 341 checkBounds(byte[] buffer, int start, int length)342 private static void checkBounds(byte[] buffer, int start, int length) { 343 final int bufferLength = (buffer != null ? buffer.length : 0); 344 if (length < 0 || start < 0 || start + length > bufferLength) { 345 throw new IllegalArgumentException("Buffer start or length out of bounds."); 346 } 347 } 348 349 @Override finalize()350 protected void finalize() throws Throwable { 351 try { 352 mCloseGuard.warnIfOpen(); 353 } finally { 354 super.finalize(); 355 } 356 } 357 native_open(String deviceName, FileDescriptor pfd)358 private native boolean native_open(String deviceName, FileDescriptor pfd); native_close()359 private native void native_close(); native_get_fd()360 private native int native_get_fd(); native_get_desc()361 private native byte[] native_get_desc(); native_claim_interface(int interfaceID, boolean force)362 private native boolean native_claim_interface(int interfaceID, boolean force); native_release_interface(int interfaceID)363 private native boolean native_release_interface(int interfaceID); native_set_interface(int interfaceID, int alternateSetting)364 private native boolean native_set_interface(int interfaceID, int alternateSetting); native_set_configuration(int configurationID)365 private native boolean native_set_configuration(int configurationID); native_control_request(int requestType, int request, int value, int index, byte[] buffer, int offset, int length, int timeout)366 private native int native_control_request(int requestType, int request, int value, 367 int index, byte[] buffer, int offset, int length, int timeout); native_bulk_request(int endpoint, byte[] buffer, int offset, int length, int timeout)368 private native int native_bulk_request(int endpoint, byte[] buffer, 369 int offset, int length, int timeout); native_request_wait(long timeout)370 private native UsbRequest native_request_wait(long timeout) throws TimeoutException; native_get_serial()371 private native String native_get_serial(); native_reset_device()372 private native boolean native_reset_device(); 373 } 374