146d0adf8256a42416584765625852b6e48497c90Mike Lockwood/* 246d0adf8256a42416584765625852b6e48497c90Mike Lockwood * Copyright (C) 2011 The Android Open Source Project 346d0adf8256a42416584765625852b6e48497c90Mike Lockwood * 446d0adf8256a42416584765625852b6e48497c90Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License"); 546d0adf8256a42416584765625852b6e48497c90Mike Lockwood * you may not use this file except in compliance with the License. 646d0adf8256a42416584765625852b6e48497c90Mike Lockwood * You may obtain a copy of the License at 746d0adf8256a42416584765625852b6e48497c90Mike Lockwood * 846d0adf8256a42416584765625852b6e48497c90Mike Lockwood * http://www.apache.org/licenses/LICENSE-2.0 946d0adf8256a42416584765625852b6e48497c90Mike Lockwood * 1046d0adf8256a42416584765625852b6e48497c90Mike Lockwood * Unless required by applicable law or agreed to in writing, software 1146d0adf8256a42416584765625852b6e48497c90Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS, 1246d0adf8256a42416584765625852b6e48497c90Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1346d0adf8256a42416584765625852b6e48497c90Mike Lockwood * See the License for the specific language governing permissions an 1446d0adf8256a42416584765625852b6e48497c90Mike Lockwood * limitations under the License. 1546d0adf8256a42416584765625852b6e48497c90Mike Lockwood */ 1646d0adf8256a42416584765625852b6e48497c90Mike Lockwood 1746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodpackage com.android.server.usb; 1846d0adf8256a42416584765625852b6e48497c90Mike Lockwood 1946d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.Context; 2046d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbConstants; 2146d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbDevice; 2246d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbEndpoint; 2346d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbInterface; 2446d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Bundle; 2546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.ParcelFileDescriptor; 26fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkeyimport android.os.Parcelable; 2746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.util.Slog; 2846d0adf8256a42416584765625852b6e48497c90Mike Lockwood 298b2c3a14603d163d7564e6f60286995079687690Jeff Sharkeyimport com.android.internal.annotations.GuardedBy; 308b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey 3146d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.FileDescriptor; 3246d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.PrintWriter; 3346d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.util.HashMap; 3446d0adf8256a42416584765625852b6e48497c90Mike Lockwood 3546d0adf8256a42416584765625852b6e48497c90Mike Lockwood/** 3646d0adf8256a42416584765625852b6e48497c90Mike Lockwood * UsbHostManager manages USB state in host mode. 3746d0adf8256a42416584765625852b6e48497c90Mike Lockwood */ 3846d0adf8256a42416584765625852b6e48497c90Mike Lockwoodpublic class UsbHostManager { 3946d0adf8256a42416584765625852b6e48497c90Mike Lockwood private static final String TAG = UsbHostManager.class.getSimpleName(); 4046d0adf8256a42416584765625852b6e48497c90Mike Lockwood private static final boolean LOG = false; 4146d0adf8256a42416584765625852b6e48497c90Mike Lockwood 4246d0adf8256a42416584765625852b6e48497c90Mike Lockwood // contains all connected USB devices 43fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>(); 4446d0adf8256a42416584765625852b6e48497c90Mike Lockwood 4546d0adf8256a42416584765625852b6e48497c90Mike Lockwood // USB busses to exclude from USB host support 4646d0adf8256a42416584765625852b6e48497c90Mike Lockwood private final String[] mHostBlacklist; 4746d0adf8256a42416584765625852b6e48497c90Mike Lockwood 4846d0adf8256a42416584765625852b6e48497c90Mike Lockwood private final Context mContext; 4946d0adf8256a42416584765625852b6e48497c90Mike Lockwood private final Object mLock = new Object(); 5046d0adf8256a42416584765625852b6e48497c90Mike Lockwood 518b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey @GuardedBy("mLock") 52fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey private UsbSettingsManager mCurrentSettings; 53fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey 54fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey public UsbHostManager(Context context) { 5546d0adf8256a42416584765625852b6e48497c90Mike Lockwood mContext = context; 5646d0adf8256a42416584765625852b6e48497c90Mike Lockwood mHostBlacklist = context.getResources().getStringArray( 5746d0adf8256a42416584765625852b6e48497c90Mike Lockwood com.android.internal.R.array.config_usbHostBlacklist); 5846d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 5946d0adf8256a42416584765625852b6e48497c90Mike Lockwood 60fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey public void setCurrentSettings(UsbSettingsManager settings) { 61fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey synchronized (mLock) { 62fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey mCurrentSettings = settings; 63fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey } 64fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey } 65fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey 66fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey private UsbSettingsManager getCurrentSettings() { 67fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey synchronized (mLock) { 68fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey return mCurrentSettings; 69fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey } 70fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey } 71fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey 7246d0adf8256a42416584765625852b6e48497c90Mike Lockwood private boolean isBlackListed(String deviceName) { 7346d0adf8256a42416584765625852b6e48497c90Mike Lockwood int count = mHostBlacklist.length; 7446d0adf8256a42416584765625852b6e48497c90Mike Lockwood for (int i = 0; i < count; i++) { 7546d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (deviceName.startsWith(mHostBlacklist[i])) { 7646d0adf8256a42416584765625852b6e48497c90Mike Lockwood return true; 7746d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 7846d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 7946d0adf8256a42416584765625852b6e48497c90Mike Lockwood return false; 8046d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 8146d0adf8256a42416584765625852b6e48497c90Mike Lockwood 8246d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* returns true if the USB device should not be accessible by applications */ 8346d0adf8256a42416584765625852b6e48497c90Mike Lockwood private boolean isBlackListed(int clazz, int subClass, int protocol) { 8446d0adf8256a42416584765625852b6e48497c90Mike Lockwood // blacklist hubs 8546d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (clazz == UsbConstants.USB_CLASS_HUB) return true; 8646d0adf8256a42416584765625852b6e48497c90Mike Lockwood 8746d0adf8256a42416584765625852b6e48497c90Mike Lockwood // blacklist HID boot devices (mouse and keyboard) 8846d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (clazz == UsbConstants.USB_CLASS_HID && 8946d0adf8256a42416584765625852b6e48497c90Mike Lockwood subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT) { 9046d0adf8256a42416584765625852b6e48497c90Mike Lockwood return true; 9146d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 9246d0adf8256a42416584765625852b6e48497c90Mike Lockwood 9346d0adf8256a42416584765625852b6e48497c90Mike Lockwood return false; 9446d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 9546d0adf8256a42416584765625852b6e48497c90Mike Lockwood 9646d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* Called from JNI in monitorUsbHostBus() to report new USB devices */ 9746d0adf8256a42416584765625852b6e48497c90Mike Lockwood private void usbDeviceAdded(String deviceName, int vendorID, int productID, 9846d0adf8256a42416584765625852b6e48497c90Mike Lockwood int deviceClass, int deviceSubclass, int deviceProtocol, 9946d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* array of quintuples containing id, class, subclass, protocol 10046d0adf8256a42416584765625852b6e48497c90Mike Lockwood and number of endpoints for each interface */ 10146d0adf8256a42416584765625852b6e48497c90Mike Lockwood int[] interfaceValues, 10246d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* array of quadruples containing address, attributes, max packet size 10346d0adf8256a42416584765625852b6e48497c90Mike Lockwood and interval for each endpoint */ 10446d0adf8256a42416584765625852b6e48497c90Mike Lockwood int[] endpointValues) { 10546d0adf8256a42416584765625852b6e48497c90Mike Lockwood 10646d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (isBlackListed(deviceName) || 10746d0adf8256a42416584765625852b6e48497c90Mike Lockwood isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) { 10846d0adf8256a42416584765625852b6e48497c90Mike Lockwood return; 10946d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 11046d0adf8256a42416584765625852b6e48497c90Mike Lockwood 11146d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 11246d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (mDevices.get(deviceName) != null) { 113fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood Slog.w(TAG, "device already on mDevices list: " + deviceName); 11446d0adf8256a42416584765625852b6e48497c90Mike Lockwood return; 11546d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 11646d0adf8256a42416584765625852b6e48497c90Mike Lockwood 11746d0adf8256a42416584765625852b6e48497c90Mike Lockwood int numInterfaces = interfaceValues.length / 5; 11846d0adf8256a42416584765625852b6e48497c90Mike Lockwood Parcelable[] interfaces = new UsbInterface[numInterfaces]; 11946d0adf8256a42416584765625852b6e48497c90Mike Lockwood try { 12046d0adf8256a42416584765625852b6e48497c90Mike Lockwood // repackage interfaceValues as an array of UsbInterface 12146d0adf8256a42416584765625852b6e48497c90Mike Lockwood int intf, endp, ival = 0, eval = 0; 12246d0adf8256a42416584765625852b6e48497c90Mike Lockwood for (intf = 0; intf < numInterfaces; intf++) { 12346d0adf8256a42416584765625852b6e48497c90Mike Lockwood int interfaceId = interfaceValues[ival++]; 12446d0adf8256a42416584765625852b6e48497c90Mike Lockwood int interfaceClass = interfaceValues[ival++]; 12546d0adf8256a42416584765625852b6e48497c90Mike Lockwood int interfaceSubclass = interfaceValues[ival++]; 12646d0adf8256a42416584765625852b6e48497c90Mike Lockwood int interfaceProtocol = interfaceValues[ival++]; 12746d0adf8256a42416584765625852b6e48497c90Mike Lockwood int numEndpoints = interfaceValues[ival++]; 12846d0adf8256a42416584765625852b6e48497c90Mike Lockwood 12946d0adf8256a42416584765625852b6e48497c90Mike Lockwood Parcelable[] endpoints = new UsbEndpoint[numEndpoints]; 13046d0adf8256a42416584765625852b6e48497c90Mike Lockwood for (endp = 0; endp < numEndpoints; endp++) { 13146d0adf8256a42416584765625852b6e48497c90Mike Lockwood int address = endpointValues[eval++]; 13246d0adf8256a42416584765625852b6e48497c90Mike Lockwood int attributes = endpointValues[eval++]; 13346d0adf8256a42416584765625852b6e48497c90Mike Lockwood int maxPacketSize = endpointValues[eval++]; 13446d0adf8256a42416584765625852b6e48497c90Mike Lockwood int interval = endpointValues[eval++]; 13546d0adf8256a42416584765625852b6e48497c90Mike Lockwood endpoints[endp] = new UsbEndpoint(address, attributes, 13646d0adf8256a42416584765625852b6e48497c90Mike Lockwood maxPacketSize, interval); 13746d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 13846d0adf8256a42416584765625852b6e48497c90Mike Lockwood 13946d0adf8256a42416584765625852b6e48497c90Mike Lockwood // don't allow if any interfaces are blacklisted 14046d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (isBlackListed(interfaceClass, interfaceSubclass, interfaceProtocol)) { 14146d0adf8256a42416584765625852b6e48497c90Mike Lockwood return; 14246d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 14346d0adf8256a42416584765625852b6e48497c90Mike Lockwood interfaces[intf] = new UsbInterface(interfaceId, interfaceClass, 14446d0adf8256a42416584765625852b6e48497c90Mike Lockwood interfaceSubclass, interfaceProtocol, endpoints); 14546d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 14646d0adf8256a42416584765625852b6e48497c90Mike Lockwood } catch (Exception e) { 14746d0adf8256a42416584765625852b6e48497c90Mike Lockwood // beware of index out of bound exceptions, which might happen if 14846d0adf8256a42416584765625852b6e48497c90Mike Lockwood // a device does not set bNumEndpoints correctly 149fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood Slog.e(TAG, "error parsing USB descriptors", e); 15046d0adf8256a42416584765625852b6e48497c90Mike Lockwood return; 15146d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 15246d0adf8256a42416584765625852b6e48497c90Mike Lockwood 15346d0adf8256a42416584765625852b6e48497c90Mike Lockwood UsbDevice device = new UsbDevice(deviceName, vendorID, productID, 15446d0adf8256a42416584765625852b6e48497c90Mike Lockwood deviceClass, deviceSubclass, deviceProtocol, interfaces); 15546d0adf8256a42416584765625852b6e48497c90Mike Lockwood mDevices.put(deviceName, device); 156fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey getCurrentSettings().deviceAttached(device); 15746d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 15846d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 15946d0adf8256a42416584765625852b6e48497c90Mike Lockwood 16046d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* Called from JNI in monitorUsbHostBus to report USB device removal */ 16146d0adf8256a42416584765625852b6e48497c90Mike Lockwood private void usbDeviceRemoved(String deviceName) { 16246d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 16346d0adf8256a42416584765625852b6e48497c90Mike Lockwood UsbDevice device = mDevices.remove(deviceName); 16446d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (device != null) { 165fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey getCurrentSettings().deviceDetached(device); 16646d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 16746d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 16846d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 16946d0adf8256a42416584765625852b6e48497c90Mike Lockwood 17046d0adf8256a42416584765625852b6e48497c90Mike Lockwood public void systemReady() { 17146d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 17246d0adf8256a42416584765625852b6e48497c90Mike Lockwood // Create a thread to call into native code to wait for USB host events. 17346d0adf8256a42416584765625852b6e48497c90Mike Lockwood // This thread will call us back on usbDeviceAdded and usbDeviceRemoved. 17446d0adf8256a42416584765625852b6e48497c90Mike Lockwood Runnable runnable = new Runnable() { 17546d0adf8256a42416584765625852b6e48497c90Mike Lockwood public void run() { 17646d0adf8256a42416584765625852b6e48497c90Mike Lockwood monitorUsbHostBus(); 17746d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 17846d0adf8256a42416584765625852b6e48497c90Mike Lockwood }; 17946d0adf8256a42416584765625852b6e48497c90Mike Lockwood new Thread(null, runnable, "UsbService host thread").start(); 18046d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 18146d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 18246d0adf8256a42416584765625852b6e48497c90Mike Lockwood 18346d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* Returns a list of all currently attached USB devices */ 18446d0adf8256a42416584765625852b6e48497c90Mike Lockwood public void getDeviceList(Bundle devices) { 18546d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 18646d0adf8256a42416584765625852b6e48497c90Mike Lockwood for (String name : mDevices.keySet()) { 18746d0adf8256a42416584765625852b6e48497c90Mike Lockwood devices.putParcelable(name, mDevices.get(name)); 18846d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 18946d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 19046d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 19146d0adf8256a42416584765625852b6e48497c90Mike Lockwood 19246d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* Opens the specified USB device */ 19346d0adf8256a42416584765625852b6e48497c90Mike Lockwood public ParcelFileDescriptor openDevice(String deviceName) { 19446d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 19546d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (isBlackListed(deviceName)) { 19646d0adf8256a42416584765625852b6e48497c90Mike Lockwood throw new SecurityException("USB device is on a restricted bus"); 19746d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 19846d0adf8256a42416584765625852b6e48497c90Mike Lockwood UsbDevice device = mDevices.get(deviceName); 19946d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (device == null) { 20046d0adf8256a42416584765625852b6e48497c90Mike Lockwood // if it is not in mDevices, it either does not exist or is blacklisted 20146d0adf8256a42416584765625852b6e48497c90Mike Lockwood throw new IllegalArgumentException( 20246d0adf8256a42416584765625852b6e48497c90Mike Lockwood "device " + deviceName + " does not exist or is restricted"); 20346d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 204fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey getCurrentSettings().checkPermission(device); 20546d0adf8256a42416584765625852b6e48497c90Mike Lockwood return nativeOpenDevice(deviceName); 20646d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 20746d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 20846d0adf8256a42416584765625852b6e48497c90Mike Lockwood 20946d0adf8256a42416584765625852b6e48497c90Mike Lockwood public void dump(FileDescriptor fd, PrintWriter pw) { 21046d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 21146d0adf8256a42416584765625852b6e48497c90Mike Lockwood pw.println(" USB Host State:"); 21246d0adf8256a42416584765625852b6e48497c90Mike Lockwood for (String name : mDevices.keySet()) { 21346d0adf8256a42416584765625852b6e48497c90Mike Lockwood pw.println(" " + name + ": " + mDevices.get(name)); 21446d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 21546d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 21646d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 21746d0adf8256a42416584765625852b6e48497c90Mike Lockwood 21846d0adf8256a42416584765625852b6e48497c90Mike Lockwood private native void monitorUsbHostBus(); 21946d0adf8256a42416584765625852b6e48497c90Mike Lockwood private native ParcelFileDescriptor nativeOpenDevice(String deviceName); 22046d0adf8256a42416584765625852b6e48497c90Mike Lockwood} 221