1 /* 2 * Copyright (C) 2010 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.UnsupportedAppUsage; 22 import android.app.ActivityThread; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.os.RemoteException; 26 27 import com.android.internal.util.Preconditions; 28 29 /** 30 * This class represents a USB device attached to the android device with the android device 31 * acting as the USB host. 32 * Each device contains one or more {@link UsbInterface}s, each of which contains a number of 33 * {@link UsbEndpoint}s (the channels via which data is transmitted over USB). 34 * 35 * <p> This class contains information (along with {@link UsbInterface} and {@link UsbEndpoint}) 36 * that describes the capabilities of the USB device. 37 * To communicate with the device, you open a {@link UsbDeviceConnection} for the device 38 * and use {@link UsbRequest} to send and receive data on an endpoint. 39 * {@link UsbDeviceConnection#controlTransfer} is used for control requests on endpoint zero. 40 * 41 * <div class="special reference"> 42 * <h3>Developer Guides</h3> 43 * <p>For more information about communicating with USB hardware, read the 44 * <a href="{@docRoot}guide/topics/connectivity/usb/index.html">USB</a> developer guide.</p> 45 * </div> 46 */ 47 public class UsbDevice implements Parcelable { 48 49 private static final String TAG = "UsbDevice"; 50 private static final boolean DEBUG = false; 51 52 private final @NonNull String mName; 53 private final @Nullable String mManufacturerName; 54 private final @Nullable String mProductName; 55 private final @NonNull String mVersion; 56 private final @NonNull UsbConfiguration[] mConfigurations; 57 private final @NonNull IUsbSerialReader mSerialNumberReader; 58 private final int mVendorId; 59 private final int mProductId; 60 private final int mClass; 61 private final int mSubclass; 62 private final int mProtocol; 63 64 /** All interfaces on the device. Initialized on first call to getInterfaceList */ 65 @UnsupportedAppUsage 66 private @Nullable UsbInterface[] mInterfaces; 67 68 /** 69 * Create a new UsbDevice object. Only called by {@link Builder#build(IUsbSerialReader)} 70 * 71 * @hide 72 */ UsbDevice(@onNull String name, int vendorId, int productId, int Class, int subClass, int protocol, @Nullable String manufacturerName, @Nullable String productName, @NonNull String version, @NonNull UsbConfiguration[] configurations, @NonNull IUsbSerialReader serialNumberReader)73 private UsbDevice(@NonNull String name, int vendorId, int productId, int Class, int subClass, 74 int protocol, @Nullable String manufacturerName, @Nullable String productName, 75 @NonNull String version, @NonNull UsbConfiguration[] configurations, 76 @NonNull IUsbSerialReader serialNumberReader) { 77 mName = Preconditions.checkNotNull(name); 78 mVendorId = vendorId; 79 mProductId = productId; 80 mClass = Class; 81 mSubclass = subClass; 82 mProtocol = protocol; 83 mManufacturerName = manufacturerName; 84 mProductName = productName; 85 mVersion = Preconditions.checkStringNotEmpty(version); 86 mConfigurations = Preconditions.checkArrayElementsNotNull(configurations, "configurations"); 87 mSerialNumberReader = Preconditions.checkNotNull(serialNumberReader); 88 89 // Make sure the binder belongs to the system 90 if (ActivityThread.isSystem()) { 91 Preconditions.checkArgument(mSerialNumberReader instanceof IUsbSerialReader.Stub); 92 } 93 } 94 95 /** 96 * Returns the name of the device. 97 * In the standard implementation, this is the path of the device file 98 * for the device in the usbfs file system. 99 * 100 * @return the device name 101 */ getDeviceName()102 public @NonNull String getDeviceName() { 103 return mName; 104 } 105 106 /** 107 * Returns the manufacturer name of the device. 108 * 109 * @return the manufacturer name, or {@code null} if the property could not be read 110 */ getManufacturerName()111 public @Nullable String getManufacturerName() { 112 return mManufacturerName; 113 } 114 115 /** 116 * Returns the product name of the device. 117 * 118 * @return the product name, or {@code null} if the property could not be read 119 */ getProductName()120 public @Nullable String getProductName() { 121 return mProductName; 122 } 123 124 /** 125 * Returns the version number of the device. 126 * 127 * @return the device version 128 */ getVersion()129 public @NonNull String getVersion() { 130 return mVersion; 131 } 132 133 /** 134 * Returns the serial number of the device. 135 * 136 * @return the serial number name, or {@code null} if the property could not be read 137 * 138 * @throws SecurityException if the app targets SDK >= {@value android.os.Build.VERSION_CODES#Q} 139 * and the app does not have permission to read from the device. 140 */ getSerialNumber()141 public @Nullable String getSerialNumber() { 142 try { 143 return mSerialNumberReader.getSerial(ActivityThread.currentPackageName()); 144 } catch (RemoteException e) { 145 e.rethrowFromSystemServer(); 146 return null; 147 } 148 } 149 150 /** 151 * Returns a unique integer ID for the device. 152 * This is a convenience for clients that want to use an integer to represent 153 * the device, rather than the device name. 154 * IDs are not persistent across USB disconnects. 155 * 156 * @return the device ID 157 */ getDeviceId()158 public int getDeviceId() { 159 return getDeviceId(mName); 160 } 161 162 /** 163 * Returns a vendor ID for the device. 164 * 165 * @return the device vendor ID 166 */ getVendorId()167 public int getVendorId() { 168 return mVendorId; 169 } 170 171 /** 172 * Returns a product ID for the device. 173 * 174 * @return the device product ID 175 */ getProductId()176 public int getProductId() { 177 return mProductId; 178 } 179 180 /** 181 * Returns the devices's class field. 182 * Some useful constants for USB device classes can be found in {@link UsbConstants}. 183 * 184 * @return the devices's class 185 */ getDeviceClass()186 public int getDeviceClass() { 187 return mClass; 188 } 189 190 /** 191 * Returns the device's subclass field. 192 * 193 * @return the device's subclass 194 */ getDeviceSubclass()195 public int getDeviceSubclass() { 196 return mSubclass; 197 } 198 199 /** 200 * Returns the device's protocol field. 201 * 202 * @return the device's protocol 203 */ getDeviceProtocol()204 public int getDeviceProtocol() { 205 return mProtocol; 206 } 207 208 /** 209 * Returns the number of {@link UsbConfiguration}s this device contains. 210 * 211 * @return the number of configurations 212 */ getConfigurationCount()213 public int getConfigurationCount() { 214 return mConfigurations.length; 215 } 216 217 /** 218 * Returns the {@link UsbConfiguration} at the given index. 219 * 220 * @return the configuration 221 */ getConfiguration(int index)222 public @NonNull UsbConfiguration getConfiguration(int index) { 223 return mConfigurations[index]; 224 } 225 getInterfaceList()226 private @Nullable UsbInterface[] getInterfaceList() { 227 if (mInterfaces == null) { 228 int configurationCount = mConfigurations.length; 229 int interfaceCount = 0; 230 for (int i = 0; i < configurationCount; i++) { 231 UsbConfiguration configuration = mConfigurations[i]; 232 interfaceCount += configuration.getInterfaceCount(); 233 } 234 235 mInterfaces = new UsbInterface[interfaceCount]; 236 int offset = 0; 237 for (int i = 0; i < configurationCount; i++) { 238 UsbConfiguration configuration = mConfigurations[i]; 239 interfaceCount = configuration.getInterfaceCount(); 240 for (int j = 0; j < interfaceCount; j++) { 241 mInterfaces[offset++] = configuration.getInterface(j); 242 } 243 } 244 } 245 246 return mInterfaces; 247 } 248 249 /** 250 * Returns the number of {@link UsbInterface}s this device contains. 251 * For devices with multiple configurations, you will probably want to use 252 * {@link UsbConfiguration#getInterfaceCount} instead. 253 * 254 * @return the number of interfaces 255 */ getInterfaceCount()256 public int getInterfaceCount() { 257 return getInterfaceList().length; 258 } 259 260 /** 261 * Returns the {@link UsbInterface} at the given index. 262 * For devices with multiple configurations, you will probably want to use 263 * {@link UsbConfiguration#getInterface} instead. 264 * 265 * @return the interface 266 */ getInterface(int index)267 public @NonNull UsbInterface getInterface(int index) { 268 return getInterfaceList()[index]; 269 } 270 271 @Override equals(Object o)272 public boolean equals(Object o) { 273 if (o instanceof UsbDevice) { 274 return ((UsbDevice)o).mName.equals(mName); 275 } else if (o instanceof String) { 276 return ((String)o).equals(mName); 277 } else { 278 return false; 279 } 280 } 281 282 @Override hashCode()283 public int hashCode() { 284 return mName.hashCode(); 285 } 286 287 @Override toString()288 public String toString() { 289 StringBuilder builder = new StringBuilder("UsbDevice[mName=" + mName + 290 ",mVendorId=" + mVendorId + ",mProductId=" + mProductId + 291 ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + 292 ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName + 293 ",mVersion=" + mVersion + ",mSerialNumberReader=" + mSerialNumberReader 294 + ",mConfigurations=["); 295 for (int i = 0; i < mConfigurations.length; i++) { 296 builder.append("\n"); 297 builder.append(mConfigurations[i].toString()); 298 } 299 builder.append("]"); 300 return builder.toString(); 301 } 302 303 public static final @android.annotation.NonNull Parcelable.Creator<UsbDevice> CREATOR = 304 new Parcelable.Creator<UsbDevice>() { 305 public UsbDevice createFromParcel(Parcel in) { 306 String name = in.readString(); 307 int vendorId = in.readInt(); 308 int productId = in.readInt(); 309 int clasz = in.readInt(); 310 int subClass = in.readInt(); 311 int protocol = in.readInt(); 312 String manufacturerName = in.readString(); 313 String productName = in.readString(); 314 String version = in.readString(); 315 IUsbSerialReader serialNumberReader = 316 IUsbSerialReader.Stub.asInterface(in.readStrongBinder()); 317 UsbConfiguration[] configurations = in.readParcelableArray( 318 UsbConfiguration.class.getClassLoader(), UsbConfiguration.class); 319 UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, 320 manufacturerName, productName, version, configurations, 321 serialNumberReader); 322 return device; 323 } 324 325 public UsbDevice[] newArray(int size) { 326 return new UsbDevice[size]; 327 } 328 }; 329 describeContents()330 public int describeContents() { 331 return 0; 332 } 333 writeToParcel(Parcel parcel, int flags)334 public void writeToParcel(Parcel parcel, int flags) { 335 parcel.writeString(mName); 336 parcel.writeInt(mVendorId); 337 parcel.writeInt(mProductId); 338 parcel.writeInt(mClass); 339 parcel.writeInt(mSubclass); 340 parcel.writeInt(mProtocol); 341 parcel.writeString(mManufacturerName); 342 parcel.writeString(mProductName); 343 parcel.writeString(mVersion); 344 parcel.writeStrongBinder(mSerialNumberReader.asBinder()); 345 parcel.writeParcelableArray(mConfigurations, 0); 346 } 347 getDeviceId(String name)348 public static int getDeviceId(String name) { 349 return native_get_device_id(name); 350 } 351 getDeviceName(int id)352 public static String getDeviceName(int id) { 353 return native_get_device_name(id); 354 } 355 native_get_device_id(String name)356 private static native int native_get_device_id(String name); native_get_device_name(int id)357 private static native String native_get_device_name(int id); 358 359 /** 360 * @hide 361 */ 362 public static class Builder { 363 private final @NonNull String mName; 364 private final int mVendorId; 365 private final int mProductId; 366 private final int mClass; 367 private final int mSubclass; 368 private final int mProtocol; 369 private final @Nullable String mManufacturerName; 370 private final @Nullable String mProductName; 371 private final @NonNull String mVersion; 372 private final @NonNull UsbConfiguration[] mConfigurations; 373 374 // Temporary storage for serial number. Serial number reader need to be wrapped in a 375 // IUsbSerialReader as they might be used as PII. 376 public final @Nullable String serialNumber; 377 Builder(@onNull String name, int vendorId, int productId, int Class, int subClass, int protocol, @Nullable String manufacturerName, @Nullable String productName, @NonNull String version, @NonNull UsbConfiguration[] configurations, @Nullable String serialNumber)378 public Builder(@NonNull String name, int vendorId, int productId, int Class, int subClass, 379 int protocol, @Nullable String manufacturerName, @Nullable String productName, 380 @NonNull String version, @NonNull UsbConfiguration[] configurations, 381 @Nullable String serialNumber) { 382 mName = Preconditions.checkNotNull(name); 383 mVendorId = vendorId; 384 mProductId = productId; 385 mClass = Class; 386 mSubclass = subClass; 387 mProtocol = protocol; 388 mManufacturerName = manufacturerName; 389 mProductName = productName; 390 mVersion = Preconditions.checkStringNotEmpty(version); 391 mConfigurations = configurations; 392 this.serialNumber = serialNumber; 393 } 394 395 /** 396 * Create a new {@link UsbDevice} 397 * 398 * @param serialReader The method to read the serial number. 399 * 400 * @return The usb device 401 */ build(@onNull IUsbSerialReader serialReader)402 public UsbDevice build(@NonNull IUsbSerialReader serialReader) { 403 return new UsbDevice(mName, mVendorId, mProductId, mClass, mSubclass, mProtocol, 404 mManufacturerName, mProductName, mVersion, mConfigurations, serialReader); 405 } 406 } 407 } 408