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