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