1 /* 2 * Copyright (C) 2019 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.car.usb.handler; 18 19 import android.hardware.usb.UsbDevice; 20 import android.hardware.usb.UsbInterface; 21 import android.util.Log; 22 23 import org.xmlpull.v1.XmlPullParser; 24 25 /** 26 * This class is used to describe a USB device. When used in HashMaps all values must be specified, 27 * but wildcards can be used for any of the fields in the package meta-data. 28 */ 29 class UsbDeviceFilter { 30 private static final String TAG = UsbDeviceFilter.class.getSimpleName(); 31 32 // USB Vendor ID (or -1 for unspecified) 33 public final int mVendorId; 34 // USB Product ID (or -1 for unspecified) 35 public final int mProductId; 36 // USB device or interface class (or -1 for unspecified) 37 public final int mClass; 38 // USB device subclass (or -1 for unspecified) 39 public final int mSubclass; 40 // USB device protocol (or -1 for unspecified) 41 public final int mProtocol; 42 // USB device manufacturer name string (or null for unspecified) 43 public final String mManufacturerName; 44 // USB device product name string (or null for unspecified) 45 public final String mProductName; 46 // USB device serial number string (or null for unspecified) 47 public final String mSerialNumber; 48 49 // USB device in AOAP mode manufacturer 50 public final String mAoapManufacturer; 51 // USB device in AOAP mode model 52 public final String mAoapModel; 53 // USB device in AOAP mode description string 54 public final String mAoapDescription; 55 // USB device in AOAP mode version 56 public final String mAoapVersion; 57 // USB device in AOAP mode URI 58 public final String mAoapUri; 59 // USB device in AOAP mode serial 60 public final String mAoapSerial; 61 // USB device in AOAP mode verification service 62 public final String mAoapService; 63 UsbDeviceFilter(int vid, int pid, int clasz, int subclass, int protocol, String manufacturer, String product, String serialnum, String aoapManufacturer, String aoapModel, String aoapDescription, String aoapVersion, String aoapUri, String aoapSerial, String aoapService)64 UsbDeviceFilter(int vid, int pid, int clasz, int subclass, int protocol, 65 String manufacturer, String product, String serialnum, 66 String aoapManufacturer, String aoapModel, String aoapDescription, 67 String aoapVersion, String aoapUri, String aoapSerial, 68 String aoapService) { 69 mVendorId = vid; 70 mProductId = pid; 71 mClass = clasz; 72 mSubclass = subclass; 73 mProtocol = protocol; 74 mManufacturerName = manufacturer; 75 mProductName = product; 76 mSerialNumber = serialnum; 77 78 mAoapManufacturer = aoapManufacturer; 79 mAoapModel = aoapModel; 80 mAoapDescription = aoapDescription; 81 mAoapVersion = aoapVersion; 82 mAoapUri = aoapUri; 83 mAoapSerial = aoapSerial; 84 mAoapService = aoapService; 85 } 86 read(XmlPullParser parser, boolean aoapData)87 public static UsbDeviceFilter read(XmlPullParser parser, boolean aoapData) { 88 int vendorId = -1; 89 int productId = -1; 90 int deviceClass = -1; 91 int deviceSubclass = -1; 92 int deviceProtocol = -1; 93 String manufacturerName = null; 94 String productName = null; 95 String serialNumber = null; 96 97 String aoapManufacturer = null; 98 String aoapModel = null; 99 String aoapDescription = null; 100 String aoapVersion = null; 101 String aoapUri = null; 102 String aoapSerial = null; 103 String aoapService = null; 104 105 int count = parser.getAttributeCount(); 106 for (int i = 0; i < count; i++) { 107 String name = parser.getAttributeName(i); 108 String value = parser.getAttributeValue(i); 109 // Attribute values are ints or strings 110 if (!aoapData && "manufacturer-name".equals(name)) { 111 manufacturerName = value; 112 } else if (!aoapData && "product-name".equals(name)) { 113 productName = value; 114 } else if (!aoapData && "serial-number".equals(name)) { 115 serialNumber = value; 116 } else if (aoapData && "manufacturer".equals(name)) { 117 aoapManufacturer = value; 118 } else if (aoapData && "model".equals(name)) { 119 aoapModel = value; 120 } else if (aoapData && "description".equals(name)) { 121 aoapDescription = value; 122 } else if (aoapData && "version".equals(name)) { 123 aoapVersion = value; 124 } else if (aoapData && "uri".equals(name)) { 125 aoapUri = value; 126 } else if (aoapData && "serial".equals(name)) { 127 aoapSerial = value; 128 } else if (aoapData && "service".equals(name)) { 129 aoapService = value; 130 } else if (!aoapData) { 131 int intValue = -1; 132 int radix = 10; 133 if (value != null && value.length() > 2 && value.charAt(0) == '0' 134 && (value.charAt(1) == 'x' || value.charAt(1) == 'X')) { 135 // allow hex values starting with 0x or 0X 136 radix = 16; 137 value = value.substring(2); 138 } 139 try { 140 intValue = Integer.parseInt(value, radix); 141 } catch (NumberFormatException e) { 142 Log.e(TAG, "invalid number for field " + name, e); 143 continue; 144 } 145 if ("vendor-id".equals(name)) { 146 vendorId = intValue; 147 } else if ("product-id".equals(name)) { 148 productId = intValue; 149 } else if ("class".equals(name)) { 150 deviceClass = intValue; 151 } else if ("subclass".equals(name)) { 152 deviceSubclass = intValue; 153 } else if ("protocol".equals(name)) { 154 deviceProtocol = intValue; 155 } 156 } 157 } 158 return new UsbDeviceFilter(vendorId, productId, 159 deviceClass, deviceSubclass, deviceProtocol, 160 manufacturerName, productName, serialNumber, aoapManufacturer, 161 aoapModel, aoapDescription, aoapVersion, aoapUri, aoapSerial, 162 aoapService); 163 } 164 matches(int clasz, int subclass, int protocol)165 private boolean matches(int clasz, int subclass, int protocol) { 166 return ((mClass == -1 || clasz == mClass) 167 && (mSubclass == -1 || subclass == mSubclass) 168 && (mProtocol == -1 || protocol == mProtocol)); 169 } 170 matches(UsbDevice device)171 public boolean matches(UsbDevice device) { 172 if (mVendorId != -1 && device.getVendorId() != mVendorId) { 173 return false; 174 } 175 if (mProductId != -1 && device.getProductId() != mProductId) { 176 return false; 177 } 178 if (mManufacturerName != null && device.getManufacturerName() == null) { 179 return false; 180 } 181 if (mProductName != null && device.getProductName() == null) { 182 return false; 183 } 184 if (mSerialNumber != null && device.getSerialNumber() == null) { 185 return false; 186 } 187 if (mManufacturerName != null && device.getManufacturerName() != null 188 && !mManufacturerName.equals(device.getManufacturerName())) { 189 return false; 190 } 191 if (mProductName != null && device.getProductName() != null 192 && !mProductName.equals(device.getProductName())) { 193 return false; 194 } 195 if (mSerialNumber != null && device.getSerialNumber() != null 196 && !mSerialNumber.equals(device.getSerialNumber())) { 197 return false; 198 } 199 200 // check device class/subclass/protocol 201 if (matches(device.getDeviceClass(), device.getDeviceSubclass(), 202 device.getDeviceProtocol())) { 203 return true; 204 } 205 206 // if device doesn't match, check the interfaces 207 int count = device.getInterfaceCount(); 208 for (int i = 0; i < count; i++) { 209 UsbInterface intf = device.getInterface(i); 210 if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(), 211 intf.getInterfaceProtocol())) { 212 return true; 213 } 214 } 215 216 return false; 217 } 218 219 @Override equals(Object obj)220 public boolean equals(Object obj) { 221 // can't compare if we have wildcard strings 222 if (mVendorId == -1 || mProductId == -1 223 || mClass == -1 || mSubclass == -1 || mProtocol == -1) { 224 return false; 225 } 226 if (obj instanceof UsbDeviceFilter) { 227 UsbDeviceFilter filter = (UsbDeviceFilter) obj; 228 229 if (filter.mVendorId != mVendorId 230 || filter.mProductId != mProductId 231 || filter.mClass != mClass 232 || filter.mSubclass != mSubclass 233 || filter.mProtocol != mProtocol) { 234 return false; 235 } 236 if ((filter.mManufacturerName != null && mManufacturerName == null) 237 || (filter.mManufacturerName == null && mManufacturerName != null) 238 || (filter.mProductName != null && mProductName == null) 239 || (filter.mProductName == null && mProductName != null) 240 || (filter.mSerialNumber != null && mSerialNumber == null) 241 || (filter.mSerialNumber == null && mSerialNumber != null)) { 242 return false; 243 } 244 if ((filter.mManufacturerName != null && mManufacturerName != null 245 && !mManufacturerName.equals(filter.mManufacturerName)) 246 || (filter.mProductName != null && mProductName != null 247 && !mProductName.equals(filter.mProductName)) 248 || (filter.mSerialNumber != null && mSerialNumber != null 249 && !mSerialNumber.equals(filter.mSerialNumber))) { 250 return false; 251 } 252 return true; 253 } 254 if (obj instanceof UsbDevice) { 255 UsbDevice device = (UsbDevice) obj; 256 if (device.getVendorId() != mVendorId 257 || device.getProductId() != mProductId 258 || device.getDeviceClass() != mClass 259 || device.getDeviceSubclass() != mSubclass 260 || device.getDeviceProtocol() != mProtocol) { 261 return false; 262 } 263 if ((mManufacturerName != null && device.getManufacturerName() == null) 264 || (mManufacturerName == null && device.getManufacturerName() != null) 265 || (mProductName != null && device.getProductName() == null) 266 || (mProductName == null && device.getProductName() != null) 267 || (mSerialNumber != null && device.getSerialNumber() == null) 268 || (mSerialNumber == null && device.getSerialNumber() != null)) { 269 return false; 270 } 271 if ((device.getManufacturerName() != null 272 && !mManufacturerName.equals(device.getManufacturerName())) 273 || (device.getProductName() != null 274 && !mProductName.equals(device.getProductName())) 275 || (device.getSerialNumber() != null 276 && !mSerialNumber.equals(device.getSerialNumber()))) { 277 return false; 278 } 279 return true; 280 } 281 return false; 282 } 283 284 @Override hashCode()285 public int hashCode() { 286 return (((mVendorId << 16) | mProductId) 287 ^ ((mClass << 16) | (mSubclass << 8) | mProtocol)); 288 } 289 290 @Override toString()291 public String toString() { 292 return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId 293 + ",mClass=" + mClass + ",mSubclass=" + mSubclass 294 + ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName 295 + ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber + "]"; 296 } 297 } 298