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