UsbHostManager.java revision 46d0adf8256a42416584765625852b6e48497c90
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.app.PendingIntent; 2046d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.BroadcastReceiver; 2146d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.ContentResolver; 2246d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.Context; 2346d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.Intent; 2446d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.IntentFilter; 2546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.IUsbManager; 2646d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbConstants; 2746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbDevice; 2846d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbEndpoint; 2946d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbInterface; 3046d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbManager; 3146d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.net.Uri; 3246d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Binder; 3346d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Bundle; 3446d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Handler; 3546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Message; 3646d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Parcelable; 3746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.ParcelFileDescriptor; 3846d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.UEventObserver; 3946d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.provider.Settings; 4046d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.util.Log; 4146d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.util.Slog; 4246d0adf8256a42416584765625852b6e48497c90Mike Lockwood 4346d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.File; 4446d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.FileDescriptor; 4546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.FileReader; 4646d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.PrintWriter; 4746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.util.HashMap; 4846d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.util.List; 4946d0adf8256a42416584765625852b6e48497c90Mike Lockwood 5046d0adf8256a42416584765625852b6e48497c90Mike Lockwood/** 5146d0adf8256a42416584765625852b6e48497c90Mike Lockwood * UsbHostManager manages USB state in host mode. 5246d0adf8256a42416584765625852b6e48497c90Mike Lockwood */ 5346d0adf8256a42416584765625852b6e48497c90Mike Lockwoodpublic class UsbHostManager { 5446d0adf8256a42416584765625852b6e48497c90Mike Lockwood private static final String TAG = UsbHostManager.class.getSimpleName(); 5546d0adf8256a42416584765625852b6e48497c90Mike Lockwood private static final boolean LOG = false; 5646d0adf8256a42416584765625852b6e48497c90Mike Lockwood 5746d0adf8256a42416584765625852b6e48497c90Mike Lockwood // contains all connected USB devices 5846d0adf8256a42416584765625852b6e48497c90Mike Lockwood private final HashMap<String,UsbDevice> mDevices = new HashMap<String,UsbDevice>(); 5946d0adf8256a42416584765625852b6e48497c90Mike Lockwood 6046d0adf8256a42416584765625852b6e48497c90Mike Lockwood // USB busses to exclude from USB host support 6146d0adf8256a42416584765625852b6e48497c90Mike Lockwood private final String[] mHostBlacklist; 6246d0adf8256a42416584765625852b6e48497c90Mike Lockwood 6346d0adf8256a42416584765625852b6e48497c90Mike Lockwood private final Context mContext; 6446d0adf8256a42416584765625852b6e48497c90Mike Lockwood private final Object mLock = new Object(); 6546d0adf8256a42416584765625852b6e48497c90Mike Lockwood private final UsbSettingsManager mSettingsManager; 6646d0adf8256a42416584765625852b6e48497c90Mike Lockwood 6746d0adf8256a42416584765625852b6e48497c90Mike Lockwood public UsbHostManager(Context context, UsbSettingsManager settingsManager) { 6846d0adf8256a42416584765625852b6e48497c90Mike Lockwood mContext = context; 6946d0adf8256a42416584765625852b6e48497c90Mike Lockwood mSettingsManager = settingsManager; 7046d0adf8256a42416584765625852b6e48497c90Mike Lockwood mHostBlacklist = context.getResources().getStringArray( 7146d0adf8256a42416584765625852b6e48497c90Mike Lockwood com.android.internal.R.array.config_usbHostBlacklist); 7246d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 7346d0adf8256a42416584765625852b6e48497c90Mike Lockwood 7446d0adf8256a42416584765625852b6e48497c90Mike Lockwood private boolean isBlackListed(String deviceName) { 7546d0adf8256a42416584765625852b6e48497c90Mike Lockwood int count = mHostBlacklist.length; 7646d0adf8256a42416584765625852b6e48497c90Mike Lockwood for (int i = 0; i < count; i++) { 7746d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (deviceName.startsWith(mHostBlacklist[i])) { 7846d0adf8256a42416584765625852b6e48497c90Mike Lockwood return true; 7946d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 8046d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 8146d0adf8256a42416584765625852b6e48497c90Mike Lockwood return false; 8246d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 8346d0adf8256a42416584765625852b6e48497c90Mike Lockwood 8446d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* returns true if the USB device should not be accessible by applications */ 8546d0adf8256a42416584765625852b6e48497c90Mike Lockwood private boolean isBlackListed(int clazz, int subClass, int protocol) { 8646d0adf8256a42416584765625852b6e48497c90Mike Lockwood // blacklist hubs 8746d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (clazz == UsbConstants.USB_CLASS_HUB) return true; 8846d0adf8256a42416584765625852b6e48497c90Mike Lockwood 8946d0adf8256a42416584765625852b6e48497c90Mike Lockwood // blacklist HID boot devices (mouse and keyboard) 9046d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (clazz == UsbConstants.USB_CLASS_HID && 9146d0adf8256a42416584765625852b6e48497c90Mike Lockwood subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT) { 9246d0adf8256a42416584765625852b6e48497c90Mike Lockwood return true; 9346d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 9446d0adf8256a42416584765625852b6e48497c90Mike Lockwood 9546d0adf8256a42416584765625852b6e48497c90Mike Lockwood return false; 9646d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 9746d0adf8256a42416584765625852b6e48497c90Mike Lockwood 9846d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* Called from JNI in monitorUsbHostBus() to report new USB devices */ 9946d0adf8256a42416584765625852b6e48497c90Mike Lockwood private void usbDeviceAdded(String deviceName, int vendorID, int productID, 10046d0adf8256a42416584765625852b6e48497c90Mike Lockwood int deviceClass, int deviceSubclass, int deviceProtocol, 10146d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* array of quintuples containing id, class, subclass, protocol 10246d0adf8256a42416584765625852b6e48497c90Mike Lockwood and number of endpoints for each interface */ 10346d0adf8256a42416584765625852b6e48497c90Mike Lockwood int[] interfaceValues, 10446d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* array of quadruples containing address, attributes, max packet size 10546d0adf8256a42416584765625852b6e48497c90Mike Lockwood and interval for each endpoint */ 10646d0adf8256a42416584765625852b6e48497c90Mike Lockwood int[] endpointValues) { 10746d0adf8256a42416584765625852b6e48497c90Mike Lockwood 10846d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (isBlackListed(deviceName) || 10946d0adf8256a42416584765625852b6e48497c90Mike Lockwood isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) { 11046d0adf8256a42416584765625852b6e48497c90Mike Lockwood return; 11146d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 11246d0adf8256a42416584765625852b6e48497c90Mike Lockwood 11346d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 11446d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (mDevices.get(deviceName) != null) { 11546d0adf8256a42416584765625852b6e48497c90Mike Lockwood Log.w(TAG, "device already on mDevices list: " + deviceName); 11646d0adf8256a42416584765625852b6e48497c90Mike Lockwood return; 11746d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 11846d0adf8256a42416584765625852b6e48497c90Mike Lockwood 11946d0adf8256a42416584765625852b6e48497c90Mike Lockwood int numInterfaces = interfaceValues.length / 5; 12046d0adf8256a42416584765625852b6e48497c90Mike Lockwood Parcelable[] interfaces = new UsbInterface[numInterfaces]; 12146d0adf8256a42416584765625852b6e48497c90Mike Lockwood try { 12246d0adf8256a42416584765625852b6e48497c90Mike Lockwood // repackage interfaceValues as an array of UsbInterface 12346d0adf8256a42416584765625852b6e48497c90Mike Lockwood int intf, endp, ival = 0, eval = 0; 12446d0adf8256a42416584765625852b6e48497c90Mike Lockwood for (intf = 0; intf < numInterfaces; intf++) { 12546d0adf8256a42416584765625852b6e48497c90Mike Lockwood int interfaceId = interfaceValues[ival++]; 12646d0adf8256a42416584765625852b6e48497c90Mike Lockwood int interfaceClass = interfaceValues[ival++]; 12746d0adf8256a42416584765625852b6e48497c90Mike Lockwood int interfaceSubclass = interfaceValues[ival++]; 12846d0adf8256a42416584765625852b6e48497c90Mike Lockwood int interfaceProtocol = interfaceValues[ival++]; 12946d0adf8256a42416584765625852b6e48497c90Mike Lockwood int numEndpoints = interfaceValues[ival++]; 13046d0adf8256a42416584765625852b6e48497c90Mike Lockwood 13146d0adf8256a42416584765625852b6e48497c90Mike Lockwood Parcelable[] endpoints = new UsbEndpoint[numEndpoints]; 13246d0adf8256a42416584765625852b6e48497c90Mike Lockwood for (endp = 0; endp < numEndpoints; endp++) { 13346d0adf8256a42416584765625852b6e48497c90Mike Lockwood int address = endpointValues[eval++]; 13446d0adf8256a42416584765625852b6e48497c90Mike Lockwood int attributes = endpointValues[eval++]; 13546d0adf8256a42416584765625852b6e48497c90Mike Lockwood int maxPacketSize = endpointValues[eval++]; 13646d0adf8256a42416584765625852b6e48497c90Mike Lockwood int interval = endpointValues[eval++]; 13746d0adf8256a42416584765625852b6e48497c90Mike Lockwood endpoints[endp] = new UsbEndpoint(address, attributes, 13846d0adf8256a42416584765625852b6e48497c90Mike Lockwood maxPacketSize, interval); 13946d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 14046d0adf8256a42416584765625852b6e48497c90Mike Lockwood 14146d0adf8256a42416584765625852b6e48497c90Mike Lockwood // don't allow if any interfaces are blacklisted 14246d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (isBlackListed(interfaceClass, interfaceSubclass, interfaceProtocol)) { 14346d0adf8256a42416584765625852b6e48497c90Mike Lockwood return; 14446d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 14546d0adf8256a42416584765625852b6e48497c90Mike Lockwood interfaces[intf] = new UsbInterface(interfaceId, interfaceClass, 14646d0adf8256a42416584765625852b6e48497c90Mike Lockwood interfaceSubclass, interfaceProtocol, endpoints); 14746d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 14846d0adf8256a42416584765625852b6e48497c90Mike Lockwood } catch (Exception e) { 14946d0adf8256a42416584765625852b6e48497c90Mike Lockwood // beware of index out of bound exceptions, which might happen if 15046d0adf8256a42416584765625852b6e48497c90Mike Lockwood // a device does not set bNumEndpoints correctly 15146d0adf8256a42416584765625852b6e48497c90Mike Lockwood Log.e(TAG, "error parsing USB descriptors", e); 15246d0adf8256a42416584765625852b6e48497c90Mike Lockwood return; 15346d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 15446d0adf8256a42416584765625852b6e48497c90Mike Lockwood 15546d0adf8256a42416584765625852b6e48497c90Mike Lockwood UsbDevice device = new UsbDevice(deviceName, vendorID, productID, 15646d0adf8256a42416584765625852b6e48497c90Mike Lockwood deviceClass, deviceSubclass, deviceProtocol, interfaces); 15746d0adf8256a42416584765625852b6e48497c90Mike Lockwood mDevices.put(deviceName, device); 15846d0adf8256a42416584765625852b6e48497c90Mike Lockwood mSettingsManager.deviceAttached(device); 15946d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 16046d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 16146d0adf8256a42416584765625852b6e48497c90Mike Lockwood 16246d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* Called from JNI in monitorUsbHostBus to report USB device removal */ 16346d0adf8256a42416584765625852b6e48497c90Mike Lockwood private void usbDeviceRemoved(String deviceName) { 16446d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 16546d0adf8256a42416584765625852b6e48497c90Mike Lockwood UsbDevice device = mDevices.remove(deviceName); 16646d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (device != null) { 16746d0adf8256a42416584765625852b6e48497c90Mike Lockwood mSettingsManager.deviceDetached(device); 16846d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 16946d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 17046d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 17146d0adf8256a42416584765625852b6e48497c90Mike Lockwood 17246d0adf8256a42416584765625852b6e48497c90Mike Lockwood public void systemReady() { 17346d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 17446d0adf8256a42416584765625852b6e48497c90Mike Lockwood // Create a thread to call into native code to wait for USB host events. 17546d0adf8256a42416584765625852b6e48497c90Mike Lockwood // This thread will call us back on usbDeviceAdded and usbDeviceRemoved. 17646d0adf8256a42416584765625852b6e48497c90Mike Lockwood Runnable runnable = new Runnable() { 17746d0adf8256a42416584765625852b6e48497c90Mike Lockwood public void run() { 17846d0adf8256a42416584765625852b6e48497c90Mike Lockwood monitorUsbHostBus(); 17946d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 18046d0adf8256a42416584765625852b6e48497c90Mike Lockwood }; 18146d0adf8256a42416584765625852b6e48497c90Mike Lockwood new Thread(null, runnable, "UsbService host thread").start(); 18246d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 18346d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 18446d0adf8256a42416584765625852b6e48497c90Mike Lockwood 18546d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* Returns a list of all currently attached USB devices */ 18646d0adf8256a42416584765625852b6e48497c90Mike Lockwood public void getDeviceList(Bundle devices) { 18746d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 18846d0adf8256a42416584765625852b6e48497c90Mike Lockwood for (String name : mDevices.keySet()) { 18946d0adf8256a42416584765625852b6e48497c90Mike Lockwood devices.putParcelable(name, mDevices.get(name)); 19046d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 19146d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 19246d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 19346d0adf8256a42416584765625852b6e48497c90Mike Lockwood 19446d0adf8256a42416584765625852b6e48497c90Mike Lockwood /* Opens the specified USB device */ 19546d0adf8256a42416584765625852b6e48497c90Mike Lockwood public ParcelFileDescriptor openDevice(String deviceName) { 19646d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 19746d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (isBlackListed(deviceName)) { 19846d0adf8256a42416584765625852b6e48497c90Mike Lockwood throw new SecurityException("USB device is on a restricted bus"); 19946d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 20046d0adf8256a42416584765625852b6e48497c90Mike Lockwood UsbDevice device = mDevices.get(deviceName); 20146d0adf8256a42416584765625852b6e48497c90Mike Lockwood if (device == null) { 20246d0adf8256a42416584765625852b6e48497c90Mike Lockwood // if it is not in mDevices, it either does not exist or is blacklisted 20346d0adf8256a42416584765625852b6e48497c90Mike Lockwood throw new IllegalArgumentException( 20446d0adf8256a42416584765625852b6e48497c90Mike Lockwood "device " + deviceName + " does not exist or is restricted"); 20546d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 20646d0adf8256a42416584765625852b6e48497c90Mike Lockwood mSettingsManager.checkPermission(device); 20746d0adf8256a42416584765625852b6e48497c90Mike Lockwood return nativeOpenDevice(deviceName); 20846d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 20946d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 21046d0adf8256a42416584765625852b6e48497c90Mike Lockwood 21146d0adf8256a42416584765625852b6e48497c90Mike Lockwood public void dump(FileDescriptor fd, PrintWriter pw) { 21246d0adf8256a42416584765625852b6e48497c90Mike Lockwood synchronized (mLock) { 21346d0adf8256a42416584765625852b6e48497c90Mike Lockwood pw.println(" USB Host State:"); 21446d0adf8256a42416584765625852b6e48497c90Mike Lockwood for (String name : mDevices.keySet()) { 21546d0adf8256a42416584765625852b6e48497c90Mike Lockwood pw.println(" " + name + ": " + mDevices.get(name)); 21646d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 21746d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 21846d0adf8256a42416584765625852b6e48497c90Mike Lockwood } 21946d0adf8256a42416584765625852b6e48497c90Mike Lockwood 22046d0adf8256a42416584765625852b6e48497c90Mike Lockwood private native void monitorUsbHostBus(); 22146d0adf8256a42416584765625852b6e48497c90Mike Lockwood private native ParcelFileDescriptor nativeOpenDevice(String deviceName); 22246d0adf8256a42416584765625852b6e48497c90Mike Lockwood} 223