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