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