• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions an
14  * limitations under the License.
15  */
16 
17 package com.android.server.usb;
18 
19 import android.content.Context;
20 import android.hardware.usb.UsbConstants;
21 import android.hardware.usb.UsbDevice;
22 import android.hardware.usb.UsbEndpoint;
23 import android.hardware.usb.UsbInterface;
24 import android.os.Bundle;
25 import android.os.ParcelFileDescriptor;
26 import android.os.Parcelable;
27 import android.util.Slog;
28 
29 import com.android.internal.annotations.GuardedBy;
30 
31 import java.io.FileDescriptor;
32 import java.io.PrintWriter;
33 import java.util.HashMap;
34 
35 /**
36  * UsbHostManager manages USB state in host mode.
37  */
38 public class UsbHostManager {
39     private static final String TAG = UsbHostManager.class.getSimpleName();
40     private static final boolean LOG = false;
41 
42     // contains all connected USB devices
43     private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>();
44 
45     // USB busses to exclude from USB host support
46     private final String[] mHostBlacklist;
47 
48     private final Context mContext;
49     private final Object mLock = new Object();
50 
51     @GuardedBy("mLock")
52     private UsbSettingsManager mCurrentSettings;
53 
UsbHostManager(Context context)54     public UsbHostManager(Context context) {
55         mContext = context;
56         mHostBlacklist = context.getResources().getStringArray(
57                 com.android.internal.R.array.config_usbHostBlacklist);
58     }
59 
setCurrentSettings(UsbSettingsManager settings)60     public void setCurrentSettings(UsbSettingsManager settings) {
61         synchronized (mLock) {
62             mCurrentSettings = settings;
63         }
64     }
65 
getCurrentSettings()66     private UsbSettingsManager getCurrentSettings() {
67         synchronized (mLock) {
68             return mCurrentSettings;
69         }
70     }
71 
isBlackListed(String deviceName)72     private boolean isBlackListed(String deviceName) {
73         int count = mHostBlacklist.length;
74         for (int i = 0; i < count; i++) {
75             if (deviceName.startsWith(mHostBlacklist[i])) {
76                 return true;
77             }
78         }
79         return false;
80     }
81 
82     /* returns true if the USB device should not be accessible by applications */
isBlackListed(int clazz, int subClass, int protocol)83     private boolean isBlackListed(int clazz, int subClass, int protocol) {
84         // blacklist hubs
85         if (clazz == UsbConstants.USB_CLASS_HUB) return true;
86 
87         // blacklist HID boot devices (mouse and keyboard)
88         if (clazz == UsbConstants.USB_CLASS_HID &&
89                 subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT) {
90             return true;
91         }
92 
93         return false;
94     }
95 
96     /* Called from JNI in monitorUsbHostBus() to report new USB devices */
usbDeviceAdded(String deviceName, int vendorID, int productID, int deviceClass, int deviceSubclass, int deviceProtocol, int[] interfaceValues, int[] endpointValues)97     private void usbDeviceAdded(String deviceName, int vendorID, int productID,
98             int deviceClass, int deviceSubclass, int deviceProtocol,
99             /* array of quintuples containing id, class, subclass, protocol
100                and number of endpoints for each interface */
101             int[] interfaceValues,
102            /* array of quadruples containing address, attributes, max packet size
103               and interval for each endpoint */
104             int[] endpointValues) {
105 
106         if (isBlackListed(deviceName) ||
107                 isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
108             return;
109         }
110 
111         synchronized (mLock) {
112             if (mDevices.get(deviceName) != null) {
113                 Slog.w(TAG, "device already on mDevices list: " + deviceName);
114                 return;
115             }
116 
117             int numInterfaces = interfaceValues.length / 5;
118             Parcelable[] interfaces = new UsbInterface[numInterfaces];
119             try {
120                 // repackage interfaceValues as an array of UsbInterface
121                 int intf, endp, ival = 0, eval = 0;
122                 for (intf = 0; intf < numInterfaces; intf++) {
123                     int interfaceId = interfaceValues[ival++];
124                     int interfaceClass = interfaceValues[ival++];
125                     int interfaceSubclass = interfaceValues[ival++];
126                     int interfaceProtocol = interfaceValues[ival++];
127                     int numEndpoints = interfaceValues[ival++];
128 
129                     Parcelable[] endpoints = new UsbEndpoint[numEndpoints];
130                     for (endp = 0; endp < numEndpoints; endp++) {
131                         int address = endpointValues[eval++];
132                         int attributes = endpointValues[eval++];
133                         int maxPacketSize = endpointValues[eval++];
134                         int interval = endpointValues[eval++];
135                         endpoints[endp] = new UsbEndpoint(address, attributes,
136                                 maxPacketSize, interval);
137                     }
138 
139                     // don't allow if any interfaces are blacklisted
140                     if (isBlackListed(interfaceClass, interfaceSubclass, interfaceProtocol)) {
141                         return;
142                     }
143                     interfaces[intf] = new UsbInterface(interfaceId, interfaceClass,
144                             interfaceSubclass, interfaceProtocol, endpoints);
145                 }
146             } catch (Exception e) {
147                 // beware of index out of bound exceptions, which might happen if
148                 // a device does not set bNumEndpoints correctly
149                 Slog.e(TAG, "error parsing USB descriptors", e);
150                 return;
151             }
152 
153             UsbDevice device = new UsbDevice(deviceName, vendorID, productID,
154                     deviceClass, deviceSubclass, deviceProtocol, interfaces);
155             mDevices.put(deviceName, device);
156             getCurrentSettings().deviceAttached(device);
157         }
158     }
159 
160     /* Called from JNI in monitorUsbHostBus to report USB device removal */
usbDeviceRemoved(String deviceName)161     private void usbDeviceRemoved(String deviceName) {
162         synchronized (mLock) {
163             UsbDevice device = mDevices.remove(deviceName);
164             if (device != null) {
165                 getCurrentSettings().deviceDetached(device);
166             }
167         }
168     }
169 
systemReady()170     public void systemReady() {
171         synchronized (mLock) {
172             // Create a thread to call into native code to wait for USB host events.
173             // This thread will call us back on usbDeviceAdded and usbDeviceRemoved.
174             Runnable runnable = new Runnable() {
175                 public void run() {
176                     monitorUsbHostBus();
177                 }
178             };
179             new Thread(null, runnable, "UsbService host thread").start();
180         }
181     }
182 
183     /* Returns a list of all currently attached USB devices */
getDeviceList(Bundle devices)184     public void getDeviceList(Bundle devices) {
185         synchronized (mLock) {
186             for (String name : mDevices.keySet()) {
187                 devices.putParcelable(name, mDevices.get(name));
188             }
189         }
190     }
191 
192     /* Opens the specified USB device */
openDevice(String deviceName)193     public ParcelFileDescriptor openDevice(String deviceName) {
194         synchronized (mLock) {
195             if (isBlackListed(deviceName)) {
196                 throw new SecurityException("USB device is on a restricted bus");
197             }
198             UsbDevice device = mDevices.get(deviceName);
199             if (device == null) {
200                 // if it is not in mDevices, it either does not exist or is blacklisted
201                 throw new IllegalArgumentException(
202                         "device " + deviceName + " does not exist or is restricted");
203             }
204             getCurrentSettings().checkPermission(device);
205             return nativeOpenDevice(deviceName);
206         }
207     }
208 
dump(FileDescriptor fd, PrintWriter pw)209     public void dump(FileDescriptor fd, PrintWriter pw) {
210         synchronized (mLock) {
211             pw.println("  USB Host State:");
212             for (String name : mDevices.keySet()) {
213                 pw.println("    " + name + ": " + mDevices.get(name));
214             }
215         }
216     }
217 
monitorUsbHostBus()218     private native void monitorUsbHostBus();
nativeOpenDevice(String deviceName)219     private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
220 }
221