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