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_AUDIO_INTERFACE = 0x24; // 36 82 public static final byte DESCRIPTORTYPE_AUDIO_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 /** 130 * @throws IllegalArgumentException 131 */ UsbDescriptor(int length, byte type)132 UsbDescriptor(int length, byte type) { 133 // a descriptor has at least a length byte and type byte 134 // one could imagine an empty one otherwise 135 if (length < 2) { 136 // huh? 137 throw new IllegalArgumentException(); 138 } 139 140 mLength = length; 141 mType = type; 142 } 143 getLength()144 public int getLength() { 145 return mLength; 146 } 147 getType()148 public byte getType() { 149 return mType; 150 } 151 getStatus()152 public int getStatus() { 153 return mStatus; 154 } 155 setStatus(int status)156 public void setStatus(int status) { 157 mStatus = status; 158 } 159 getOverUnderRunCount()160 public int getOverUnderRunCount() { 161 return mOverUnderRunCount; 162 } 163 getStatusString()164 public String getStatusString() { 165 return sStatusStrings[mStatus]; 166 } 167 getRawData()168 public byte[] getRawData() { 169 return mRawData; 170 } 171 172 /** 173 * Called by the parser for any necessary cleanup. 174 */ postParse(ByteStream stream)175 public void postParse(ByteStream stream) { 176 // Status 177 int bytesRead = stream.getReadCount(); 178 if (bytesRead < mLength) { 179 // Too cold... 180 stream.advance(mLength - bytesRead); 181 mStatus = STATUS_PARSED_UNDERRUN; 182 mOverUnderRunCount = mLength - bytesRead; 183 Log.w(TAG, "UNDERRUN t:0x" + Integer.toHexString(mType) 184 + " r: " + bytesRead + " < l: " + mLength); 185 } else if (bytesRead > mLength) { 186 // Too hot... 187 stream.reverse(bytesRead - mLength); 188 mStatus = STATUS_PARSED_OVERRUN; 189 mOverUnderRunCount = bytesRead - mLength; 190 Log.w(TAG, "OVERRRUN t:0x" + Integer.toHexString(mType) 191 + " r: " + bytesRead + " > l: " + mLength); 192 } else { 193 // Just right! 194 mStatus = STATUS_PARSED_OK; 195 } 196 } 197 198 /** 199 * Reads data fields from specified raw-data stream. 200 */ parseRawDescriptors(ByteStream stream)201 public int parseRawDescriptors(ByteStream stream) { 202 int numRead = stream.getReadCount(); 203 int dataLen = mLength - numRead; 204 if (dataLen > 0) { 205 mRawData = new byte[dataLen]; 206 for (int index = 0; index < dataLen; index++) { 207 mRawData[index] = stream.getByte(); 208 } 209 } 210 return mLength; 211 } 212 213 /** 214 * Gets a string for the specified index from the USB Device's string descriptors. 215 */ getUsbDescriptorString(UsbDeviceConnection connection, byte strIndex)216 public static String getUsbDescriptorString(UsbDeviceConnection connection, byte strIndex) { 217 String usbStr = ""; 218 if (strIndex != 0) { 219 try { 220 int rdo = connection.controlTransfer( 221 UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_STANDARD, 222 REQUEST_GET_DESCRIPTOR, 223 (DESCRIPTORTYPE_STRING << 8) | strIndex, 224 0, 225 sStringBuffer, 226 0xFF, 227 0); 228 if (rdo >= 0) { 229 usbStr = new String(sStringBuffer, 2, rdo - 2, "UTF-16LE"); 230 } else { 231 usbStr = "?"; 232 } 233 } catch (Exception e) { 234 Log.e(TAG, "Can not communicate with USB device", e); 235 } 236 } 237 return usbStr; 238 } 239 reportParseStatus(ReportCanvas canvas)240 private void reportParseStatus(ReportCanvas canvas) { 241 int status = getStatus(); 242 switch (status) { 243 case UsbDescriptor.STATUS_PARSED_OK: 244 break; // no need to report 245 246 case UsbDescriptor.STATUS_UNPARSED: 247 case UsbDescriptor.STATUS_PARSED_UNDERRUN: 248 case UsbDescriptor.STATUS_PARSED_OVERRUN: 249 canvas.writeParagraph("status: " + getStatusString() 250 + " [" + getOverUnderRunCount() + "]", true); 251 break; 252 } 253 } 254 255 @Override report(ReportCanvas canvas)256 public void report(ReportCanvas canvas) { 257 String descTypeStr = UsbStrings.getDescriptorName(getType()); 258 String text = descTypeStr + ": " + ReportCanvas.getHexString(getType()) 259 + " Len: " + getLength(); 260 if (mHierarchyLevel != 0) { 261 canvas.writeHeader(mHierarchyLevel, text); 262 } else { 263 canvas.writeParagraph(text, false); 264 } 265 266 if (getStatus() != STATUS_PARSED_OK) { 267 reportParseStatus(canvas); 268 } 269 } 270 271 @Override shortReport(ReportCanvas canvas)272 public void shortReport(ReportCanvas canvas) { 273 String descTypeStr = UsbStrings.getDescriptorName(getType()); 274 String text = descTypeStr + ": " + ReportCanvas.getHexString(getType()) 275 + " Len: " + getLength(); 276 canvas.writeParagraph(text, false); 277 } 278 } 279