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