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