1 /* 2 * Copyright (C) 2017 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 package com.android.server.usb.descriptors; 17 18 import android.hardware.usb.UsbConstants; 19 import android.hardware.usb.UsbDeviceConnection; 20 import android.util.Log; 21 22 import com.android.server.usb.descriptors.report.ReportCanvas; 23 import com.android.server.usb.descriptors.report.Reporting; 24 import com.android.server.usb.descriptors.report.UsbStrings; 25 26 /* 27 * Some notes about UsbDescriptor and its subclasses. 28 * 29 * It is assumed that the user of the UsbDescriptorParser knows what they are doing 30 * so NO PROTECTION is implemented against "improper" use. Such uses are specifically: 31 * allocating a UsbDescriptor (subclass) object outside of the context of parsing/reading 32 * a rawdescriptor stream and perhaps accessing fields which have not been inialized (by 33 * parsing/reading or course). 34 */ 35 36 /** 37 * @hide 38 * Common superclass for all USB Descriptors. 39 */ 40 public abstract class UsbDescriptor implements Reporting { 41 private static final String TAG = "UsbDescriptor"; 42 43 protected int mHierarchyLevel; 44 45 protected final int mLength; // 0:1 bLength Number Size of the Descriptor in Bytes (18 bytes) 46 // we store this as an int because Java bytes are SIGNED. 47 protected final byte mType; // 1:1 bDescriptorType Constant Device Descriptor (0x01) 48 49 private byte[] mRawData; 50 51 private static final int SIZE_STRINGBUFFER = 256; 52 private static byte[] sStringBuffer = new byte[SIZE_STRINGBUFFER]; 53 54 // Status 55 public static final int STATUS_UNPARSED = 0; 56 public static final int STATUS_PARSED_OK = 1; 57 public static final int STATUS_PARSED_UNDERRUN = 2; 58 public static final int STATUS_PARSED_OVERRUN = 3; 59 public static final int STATUS_PARSE_EXCEPTION = 4; 60 61 private int mStatus = STATUS_UNPARSED; 62 63 private static String[] sStatusStrings = { 64 "UNPARSED", "PARSED - OK", "PARSED - UNDERRUN", "PARSED - OVERRUN"}; 65 66 private int mOverUnderRunCount; 67 68 // Descriptor Type IDs 69 public static final byte DESCRIPTORTYPE_DEVICE = 0x01; // 1 70 public static final byte DESCRIPTORTYPE_CONFIG = 0x02; // 2 71 public static final byte DESCRIPTORTYPE_STRING = 0x03; // 3 72 public static final byte DESCRIPTORTYPE_INTERFACE = 0x04; // 4 73 public static final byte DESCRIPTORTYPE_ENDPOINT = 0x05; // 5 74 public static final byte DESCRIPTORTYPE_INTERFACEASSOC = 0x0B; // 11 75 public static final byte DESCRIPTORTYPE_BOS = 0x0F; // 15 76 public static final byte DESCRIPTORTYPE_CAPABILITY = 0x10; // 16 77 78 public static final byte DESCRIPTORTYPE_HID = 0x21; // 33 79 public static final byte DESCRIPTORTYPE_REPORT = 0x22; // 34 80 public static final byte DESCRIPTORTYPE_PHYSICAL = 0x23; // 35 81 public static final byte DESCRIPTORTYPE_CLASSSPECIFIC_INTERFACE = 0x24; // 36 82 public static final byte DESCRIPTORTYPE_CLASSSPECIFIC_ENDPOINT = 0x25; // 37 83 public static final byte DESCRIPTORTYPE_HUB = 0x29; // 41 84 public static final byte DESCRIPTORTYPE_SUPERSPEED_HUB = 0x2A; // 42 85 public static final byte DESCRIPTORTYPE_ENDPOINT_COMPANION = 0x30; // 48 86 87 // Class IDs 88 public static final int CLASSID_DEVICE = 0x00; 89 public static final int CLASSID_AUDIO = 0x01; 90 public static final int CLASSID_COM = 0x02; 91 public static final int CLASSID_HID = 0x03; 92 // public static final int CLASSID_??? = 0x04; 93 public static final int CLASSID_PHYSICAL = 0x05; 94 public static final int CLASSID_IMAGE = 0x06; 95 public static final int CLASSID_PRINTER = 0x07; 96 public static final int CLASSID_STORAGE = 0x08; 97 public static final int CLASSID_HUB = 0x09; 98 public static final int CLASSID_CDC_CONTROL = 0x0A; 99 public static final int CLASSID_SMART_CARD = 0x0B; 100 //public static final int CLASSID_??? = 0x0C; 101 public static final int CLASSID_SECURITY = 0x0D; 102 public static final int CLASSID_VIDEO = 0x0E; 103 public static final int CLASSID_HEALTHCARE = 0x0F; 104 public static final int CLASSID_AUDIOVIDEO = 0x10; 105 public static final int CLASSID_BILLBOARD = 0x11; 106 public static final int CLASSID_TYPECBRIDGE = 0x12; 107 public static final int CLASSID_DIAGNOSTIC = 0xDC; 108 public static final int CLASSID_WIRELESS = 0xE0; 109 public static final int CLASSID_MISC = 0xEF; 110 public static final int CLASSID_APPSPECIFIC = 0xFE; 111 public static final int CLASSID_VENDSPECIFIC = 0xFF; 112 113 // Audio Subclass codes 114 public static final int AUDIO_SUBCLASS_UNDEFINED = 0x00; 115 public static final int AUDIO_AUDIOCONTROL = 0x01; 116 public static final int AUDIO_AUDIOSTREAMING = 0x02; 117 public static final int AUDIO_MIDISTREAMING = 0x03; 118 119 // Request IDs 120 public static final int REQUEST_GET_STATUS = 0x00; 121 public static final int REQUEST_CLEAR_FEATURE = 0x01; 122 public static final int REQUEST_SET_FEATURE = 0x03; 123 public static final int REQUEST_GET_ADDRESS = 0x05; 124 public static final int REQUEST_GET_DESCRIPTOR = 0x06; 125 public static final int REQUEST_SET_DESCRIPTOR = 0x07; 126 public static final int REQUEST_GET_CONFIGURATION = 0x08; 127 public static final int REQUEST_SET_CONFIGURATION = 0x09; 128 129 // USB control transfer timeout 130 public static final int USB_CONTROL_TRANSFER_TIMEOUT_MS = 200; 131 132 /** 133 * @throws IllegalArgumentException 134 */ UsbDescriptor(int length, byte type)135 UsbDescriptor(int length, byte type) { 136 // a descriptor has at least a length byte and type byte 137 // one could imagine an empty one otherwise 138 if (length < 2) { 139 // huh? 140 throw new IllegalArgumentException(); 141 } 142 143 mLength = length; 144 mType = type; 145 } 146 getLength()147 public int getLength() { 148 return mLength; 149 } 150 getType()151 public byte getType() { 152 return mType; 153 } 154 getStatus()155 public int getStatus() { 156 return mStatus; 157 } 158 setStatus(int status)159 public void setStatus(int status) { 160 mStatus = status; 161 } 162 getOverUnderRunCount()163 public int getOverUnderRunCount() { 164 return mOverUnderRunCount; 165 } getStatusString()166 public String getStatusString() { 167 return sStatusStrings[mStatus]; 168 } 169 getRawData()170 public byte[] getRawData() { 171 return mRawData; 172 } 173 174 /** 175 * Called by the parser for any necessary cleanup. 176 */ postParse(ByteStream stream)177 public void postParse(ByteStream stream) { 178 // Status 179 int bytesRead = stream.getReadCount(); 180 if (bytesRead < mLength) { 181 // Too cold... 182 stream.advance(mLength - bytesRead); 183 mStatus = STATUS_PARSED_UNDERRUN; 184 mOverUnderRunCount = mLength - bytesRead; 185 Log.w(TAG, "UNDERRUN t:0x" + Integer.toHexString(mType) 186 + " r: " + bytesRead + " < l: " + mLength); 187 } else if (bytesRead > mLength) { 188 // Too hot... 189 stream.reverse(bytesRead - mLength); 190 mStatus = STATUS_PARSED_OVERRUN; 191 mOverUnderRunCount = bytesRead - mLength; 192 Log.w(TAG, "OVERRRUN t:0x" + Integer.toHexString(mType) 193 + " r: " + bytesRead + " > l: " + mLength); 194 } else { 195 // Just right! 196 mStatus = STATUS_PARSED_OK; 197 } 198 } 199 200 /** 201 * Reads data fields from specified raw-data stream. 202 */ parseRawDescriptors(ByteStream stream)203 public int parseRawDescriptors(ByteStream stream) { 204 int numRead = stream.getReadCount(); 205 int dataLen = mLength - numRead; 206 if (dataLen > 0) { 207 mRawData = new byte[dataLen]; 208 for (int index = 0; index < dataLen; index++) { 209 mRawData[index] = stream.getByte(); 210 } 211 } 212 return mLength; 213 } 214 215 /** 216 * Gets a string for the specified index from the USB Device's string descriptors. 217 */ getUsbDescriptorString(UsbDeviceConnection connection, byte strIndex)218 public static String getUsbDescriptorString(UsbDeviceConnection connection, byte strIndex) { 219 String usbStr = ""; 220 if (strIndex != 0) { 221 try { 222 int rdo = connection.controlTransfer( 223 UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_STANDARD, 224 REQUEST_GET_DESCRIPTOR, 225 (DESCRIPTORTYPE_STRING << 8) | strIndex, 226 0, 227 sStringBuffer, 228 0xFF, 229 USB_CONTROL_TRANSFER_TIMEOUT_MS); 230 if (rdo >= 0) { 231 usbStr = new String(sStringBuffer, 2, rdo - 2, "UTF-16LE"); 232 } else { 233 usbStr = "?"; 234 } 235 } catch (Exception e) { 236 Log.e(TAG, "Can not communicate with USB device", e); 237 } 238 } 239 return usbStr; 240 } 241 reportParseStatus(ReportCanvas canvas)242 private void reportParseStatus(ReportCanvas canvas) { 243 int status = getStatus(); 244 switch (status) { 245 case UsbDescriptor.STATUS_PARSED_OK: 246 break; // no need to report 247 248 case UsbDescriptor.STATUS_UNPARSED: 249 case UsbDescriptor.STATUS_PARSED_UNDERRUN: 250 case UsbDescriptor.STATUS_PARSED_OVERRUN: 251 canvas.writeParagraph("status: " + getStatusString() 252 + " [" + getOverUnderRunCount() + "]", true); 253 break; 254 } 255 } 256 257 @Override report(ReportCanvas canvas)258 public void report(ReportCanvas canvas) { 259 String descTypeStr = UsbStrings.getDescriptorName(getType()); 260 String text = descTypeStr + ": " + ReportCanvas.getHexString(getType()) 261 + " Len: " + getLength(); 262 if (mHierarchyLevel != 0) { 263 canvas.writeHeader(mHierarchyLevel, text); 264 } else { 265 canvas.writeParagraph(text, false); 266 } 267 268 if (getStatus() != STATUS_PARSED_OK) { 269 reportParseStatus(canvas); 270 } 271 } 272 273 @Override shortReport(ReportCanvas canvas)274 public void shortReport(ReportCanvas canvas) { 275 String descTypeStr = UsbStrings.getDescriptorName(getType()); 276 String text = descTypeStr + ": " + ReportCanvas.getHexString(getType()) 277 + " Len: " + getLength(); 278 canvas.writeParagraph(text, false); 279 } 280 281 /* 282 * Logging Helpers 283 */ getDescriptorName(byte descriptorType, int descriptorLength)284 static String getDescriptorName(byte descriptorType, int descriptorLength) { 285 String name = UsbStrings.getDescriptorName(descriptorType); 286 if (name != null) { 287 return name; 288 } else { 289 return "Unknown Descriptor Type " + descriptorType 290 + " 0x" + Integer.toHexString(descriptorType) 291 + " length:" + descriptorLength; 292 } 293 } 294 logDescriptorName(byte descriptorType, int descriptorLength)295 static void logDescriptorName(byte descriptorType, int descriptorLength) { 296 if (UsbDescriptorParser.DEBUG) { 297 Log.d(TAG, "----> " + getDescriptorName(descriptorType, descriptorLength)); 298 } 299 } 300 } 301