blob: 08c9eea6e012000a4f8f17f1ea2410e55356dca8 [file] [log] [blame]
Mike Lockwoode7d511e2010-12-30 13:39:37 -05001/*
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
Mike Lockwoodc4308f02011-03-01 08:04:54 -080017package android.hardware.usb;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050018
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Mathew Inwoodbcbe4402018-08-08 15:42:59 +010021import android.annotation.UnsupportedAppUsage;
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -070022import android.app.ActivityThread;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050023import android.os.Parcel;
24import android.os.Parcelable;
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -070025import android.os.RemoteException;
26
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -070027import com.android.internal.util.Preconditions;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050028
Mike Lockwoode7d511e2010-12-30 13:39:37 -050029/**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -040030 * 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.
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080040 *
41 * <div class="special reference">
42 * <h3>Developer Guides</h3>
43 * <p>For more information about communicating with USB hardware, read the
Dave Friedmandf0fd34d2017-04-10 14:50:24 -070044 * <a href="{@docRoot}guide/topics/connectivity/usb/index.html">USB</a> developer guide.</p>
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080045 * </div>
Mike Lockwoode7d511e2010-12-30 13:39:37 -050046 */
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050047public class UsbDevice implements Parcelable {
Mike Lockwoode7d511e2010-12-30 13:39:37 -050048
49 private static final String TAG = "UsbDevice";
Paul McLean0a8f0692014-12-22 14:57:45 -070050 private static final boolean DEBUG = false;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050051
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -070052 private final @NonNull String mName;
53 private final @Nullable String mManufacturerName;
54 private final @Nullable String mProductName;
55 private final @NonNull String mVersion;
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -070056 private final @NonNull UsbConfiguration[] mConfigurations;
57 private final @NonNull IUsbSerialReader mSerialNumberReader;
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050058 private final int mVendorId;
59 private final int mProductId;
60 private final int mClass;
61 private final int mSubclass;
62 private final int mProtocol;
Mike Lockwood7531aa22014-01-13 10:31:01 -080063
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -070064 /** All interfaces on the device. Initialized on first call to getInterfaceList */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +010065 @UnsupportedAppUsage
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -070066 private @Nullable UsbInterface[] mInterfaces;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050067
68 /**
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -070069 * Create a new UsbDevice object. Only called by {@link Builder#build(IUsbSerialReader)}
70 *
Mike Lockwoode7d511e2010-12-30 13:39:37 -050071 * @hide
72 */
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -070073 private UsbDevice(@NonNull String name, int vendorId, int productId, int Class, int subClass,
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -070074 int protocol, @Nullable String manufacturerName, @Nullable String productName,
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -070075 @NonNull String version, @NonNull UsbConfiguration[] configurations,
76 @NonNull IUsbSerialReader serialNumberReader) {
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -070077 mName = Preconditions.checkNotNull(name);
Mike Lockwoode7d511e2010-12-30 13:39:37 -050078 mVendorId = vendorId;
79 mProductId = productId;
80 mClass = Class;
81 mSubclass = subClass;
82 mProtocol = protocol;
Robin Cutshaw575ca852012-05-01 19:45:25 -040083 mManufacturerName = manufacturerName;
84 mProductName = productName;
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -070085 mVersion = Preconditions.checkStringNotEmpty(version);
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -070086 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 }
Mike Lockwoode7d511e2010-12-30 13:39:37 -050093 }
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 */
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700102 public @NonNull String getDeviceName() {
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500103 return mName;
104 }
105
106 /**
Robin Cutshaw575ca852012-05-01 19:45:25 -0400107 * Returns the manufacturer name of the device.
108 *
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700109 * @return the manufacturer name, or {@code null} if the property could not be read
Robin Cutshaw575ca852012-05-01 19:45:25 -0400110 */
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700111 public @Nullable String getManufacturerName() {
Robin Cutshaw575ca852012-05-01 19:45:25 -0400112 return mManufacturerName;
113 }
114
115 /**
116 * Returns the product name of the device.
117 *
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700118 * @return the product name, or {@code null} if the property could not be read
Robin Cutshaw575ca852012-05-01 19:45:25 -0400119 */
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700120 public @Nullable String getProductName() {
Robin Cutshaw575ca852012-05-01 19:45:25 -0400121 return mProductName;
122 }
123
124 /**
Mike Lockwoodc9bb40e2015-04-29 13:05:55 -0700125 * Returns the version number of the device.
126 *
127 * @return the device version
128 */
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700129 public @NonNull String getVersion() {
Mike Lockwoodc9bb40e2015-04-29 13:05:55 -0700130 return mVersion;
131 }
132
133 /**
Robin Cutshaw575ca852012-05-01 19:45:25 -0400134 * Returns the serial number of the device.
135 *
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700136 * @return the serial number name, or {@code null} if the property could not be read
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -0700137 *
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.
Robin Cutshaw575ca852012-05-01 19:45:25 -0400140 */
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700141 public @Nullable String getSerialNumber() {
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -0700142 try {
143 return mSerialNumberReader.getSerial(ActivityThread.currentPackageName());
144 } catch (RemoteException e) {
145 e.rethrowFromSystemServer();
146 return null;
147 }
Robin Cutshaw575ca852012-05-01 19:45:25 -0400148 }
149
150 /**
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500151 * 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 */
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 */
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 */
176 public int getProductId() {
177 return mProductId;
178 }
179
180 /**
181 * Returns the devices's class field.
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400182 * Some useful constants for USB device classes can be found in {@link UsbConstants}.
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500183 *
184 * @return the devices's class
185 */
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 */
195 public int getDeviceSubclass() {
196 return mSubclass;
197 }
198
199 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400200 * Returns the device's protocol field.
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500201 *
202 * @return the device's protocol
203 */
204 public int getDeviceProtocol() {
205 return mProtocol;
206 }
207
208 /**
Mike Lockwood7531aa22014-01-13 10:31:01 -0800209 * Returns the number of {@link UsbConfiguration}s this device contains.
210 *
211 * @return the number of configurations
212 */
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 */
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700222 public @NonNull UsbConfiguration getConfiguration(int index) {
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -0700223 return mConfigurations[index];
Mike Lockwood7531aa22014-01-13 10:31:01 -0800224 }
225
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700226 private @Nullable UsbInterface[] getInterfaceList() {
Mike Lockwood7531aa22014-01-13 10:31:01 -0800227 if (mInterfaces == null) {
228 int configurationCount = mConfigurations.length;
229 int interfaceCount = 0;
230 for (int i = 0; i < configurationCount; i++) {
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -0700231 UsbConfiguration configuration = mConfigurations[i];
Mike Lockwood7531aa22014-01-13 10:31:01 -0800232 interfaceCount += configuration.getInterfaceCount();
233 }
234
235 mInterfaces = new UsbInterface[interfaceCount];
236 int offset = 0;
237 for (int i = 0; i < configurationCount; i++) {
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -0700238 UsbConfiguration configuration = mConfigurations[i];
Mike Lockwood7531aa22014-01-13 10:31:01 -0800239 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 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400250 * Returns the number of {@link UsbInterface}s this device contains.
Mike Lockwood7531aa22014-01-13 10:31:01 -0800251 * For devices with multiple configurations, you will probably want to use
252 * {@link UsbConfiguration#getInterfaceCount} instead.
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500253 *
254 * @return the number of interfaces
255 */
256 public int getInterfaceCount() {
Mike Lockwood7531aa22014-01-13 10:31:01 -0800257 return getInterfaceList().length;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500258 }
259
260 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400261 * Returns the {@link UsbInterface} at the given index.
Mike Lockwood7531aa22014-01-13 10:31:01 -0800262 * For devices with multiple configurations, you will probably want to use
263 * {@link UsbConfiguration#getInterface} instead.
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500264 *
265 * @return the interface
266 */
Philip P. Moltmannf2d83ed2016-10-17 12:14:41 -0700267 public @NonNull UsbInterface getInterface(int index) {
Mike Lockwood7531aa22014-01-13 10:31:01 -0800268 return getInterfaceList()[index];
269 }
270
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500271 @Override
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
Mike Lockwoodc6f23e82011-03-09 12:05:20 -0500283 public int hashCode() {
284 return mName.hashCode();
285 }
286
287 @Override
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500288 public String toString() {
Mike Lockwood7531aa22014-01-13 10:31:01 -0800289 StringBuilder builder = new StringBuilder("UsbDevice[mName=" + mName +
290 ",mVendorId=" + mVendorId + ",mProductId=" + mProductId +
291 ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
Robin Cutshaw575ca852012-05-01 19:45:25 -0400292 ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName +
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -0700293 ",mVersion=" + mVersion + ",mSerialNumberReader=" + mSerialNumberReader
294 + ",mConfigurations=[");
Mike Lockwood7531aa22014-01-13 10:31:01 -0800295 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();
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500301 }
302
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700303 public static final @android.annotation.NonNull Parcelable.Creator<UsbDevice> CREATOR =
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500304 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();
Robin Cutshaw575ca852012-05-01 19:45:25 -0400312 String manufacturerName = in.readString();
313 String productName = in.readString();
Mike Lockwoodc9bb40e2015-04-29 13:05:55 -0700314 String version = in.readString();
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -0700315 IUsbSerialReader serialNumberReader =
316 IUsbSerialReader.Stub.asInterface(in.readStrongBinder());
317 UsbConfiguration[] configurations = in.readParcelableArray(
318 UsbConfiguration.class.getClassLoader(), UsbConfiguration.class);
Mike Lockwood7531aa22014-01-13 10:31:01 -0800319 UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol,
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -0700320 manufacturerName, productName, version, configurations,
321 serialNumberReader);
Mike Lockwood7531aa22014-01-13 10:31:01 -0800322 return device;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500323 }
324
325 public UsbDevice[] newArray(int size) {
326 return new UsbDevice[size];
327 }
328 };
329
330 public int describeContents() {
331 return 0;
332 }
333
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);
Robin Cutshaw575ca852012-05-01 19:45:25 -0400341 parcel.writeString(mManufacturerName);
342 parcel.writeString(mProductName);
Mike Lockwoodc9bb40e2015-04-29 13:05:55 -0700343 parcel.writeString(mVersion);
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -0700344 parcel.writeStrongBinder(mSerialNumberReader.asBinder());
Mike Lockwood7531aa22014-01-13 10:31:01 -0800345 parcel.writeParcelableArray(mConfigurations, 0);
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500346 }
347
348 public static int getDeviceId(String name) {
349 return native_get_device_id(name);
350 }
351
352 public static String getDeviceName(int id) {
353 return native_get_device_name(id);
354 }
355
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500356 private static native int native_get_device_id(String name);
357 private static native String native_get_device_name(int id);
Philip P. Moltmanna2c6eea2018-08-24 09:50:40 -0700358
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
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 */
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 }
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500407}