• 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.app.PendingIntent;
20 import android.content.BroadcastReceiver;
21 import android.content.ContentResolver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.hardware.usb.IUsbManager;
26 import android.hardware.usb.UsbConstants;
27 import android.hardware.usb.UsbDevice;
28 import android.hardware.usb.UsbEndpoint;
29 import android.hardware.usb.UsbInterface;
30 import android.hardware.usb.UsbManager;
31 import android.net.Uri;
32 import android.os.Binder;
33 import android.os.Bundle;
34 import android.os.Handler;
35 import android.os.Message;
36 import android.os.Parcelable;
37 import android.os.ParcelFileDescriptor;
38 import android.os.UEventObserver;
39 import android.provider.Settings;
40 import android.util.Slog;
41 
42 import java.io.File;
43 import java.io.FileDescriptor;
44 import java.io.FileReader;
45 import java.io.PrintWriter;
46 import java.util.HashMap;
47 import java.util.List;
48 
49 /**
50  * UsbHostManager manages USB state in host mode.
51  */
52 public class UsbHostManager {
53     private static final String TAG = UsbHostManager.class.getSimpleName();
54     private static final boolean LOG = false;
55 
56     // contains all connected USB devices
57     private final HashMap<String,UsbDevice> mDevices = new HashMap<String,UsbDevice>();
58 
59     // USB busses to exclude from USB host support
60     private final String[] mHostBlacklist;
61 
62     private final Context mContext;
63     private final Object mLock = new Object();
64     private final UsbSettingsManager mSettingsManager;
65 
UsbHostManager(Context context, UsbSettingsManager settingsManager)66     public UsbHostManager(Context context, UsbSettingsManager settingsManager) {
67         mContext = context;
68         mSettingsManager = settingsManager;
69         mHostBlacklist = context.getResources().getStringArray(
70                 com.android.internal.R.array.config_usbHostBlacklist);
71     }
72 
isBlackListed(String deviceName)73     private boolean isBlackListed(String deviceName) {
74         int count = mHostBlacklist.length;
75         for (int i = 0; i < count; i++) {
76             if (deviceName.startsWith(mHostBlacklist[i])) {
77                 return true;
78             }
79         }
80         return false;
81     }
82 
83     /* returns true if the USB device should not be accessible by applications */
isBlackListed(int clazz, int subClass, int protocol)84     private boolean isBlackListed(int clazz, int subClass, int protocol) {
85         // blacklist hubs
86         if (clazz == UsbConstants.USB_CLASS_HUB) return true;
87 
88         // blacklist HID boot devices (mouse and keyboard)
89         if (clazz == UsbConstants.USB_CLASS_HID &&
90                 subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT) {
91             return true;
92         }
93 
94         return false;
95     }
96 
97     /* 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)98     private void usbDeviceAdded(String deviceName, int vendorID, int productID,
99             int deviceClass, int deviceSubclass, int deviceProtocol,
100             /* array of quintuples containing id, class, subclass, protocol
101                and number of endpoints for each interface */
102             int[] interfaceValues,
103            /* array of quadruples containing address, attributes, max packet size
104               and interval for each endpoint */
105             int[] endpointValues) {
106 
107         if (isBlackListed(deviceName) ||
108                 isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
109             return;
110         }
111 
112         synchronized (mLock) {
113             if (mDevices.get(deviceName) != null) {
114                 Slog.w(TAG, "device already on mDevices list: " + deviceName);
115                 return;
116             }
117 
118             int numInterfaces = interfaceValues.length / 5;
119             Parcelable[] interfaces = new UsbInterface[numInterfaces];
120             try {
121                 // repackage interfaceValues as an array of UsbInterface
122                 int intf, endp, ival = 0, eval = 0;
123                 for (intf = 0; intf < numInterfaces; intf++) {
124                     int interfaceId = interfaceValues[ival++];
125                     int interfaceClass = interfaceValues[ival++];
126                     int interfaceSubclass = interfaceValues[ival++];
127                     int interfaceProtocol = interfaceValues[ival++];
128                     int numEndpoints = interfaceValues[ival++];
129 
130                     Parcelable[] endpoints = new UsbEndpoint[numEndpoints];
131                     for (endp = 0; endp < numEndpoints; endp++) {
132                         int address = endpointValues[eval++];
133                         int attributes = endpointValues[eval++];
134                         int maxPacketSize = endpointValues[eval++];
135                         int interval = endpointValues[eval++];
136                         endpoints[endp] = new UsbEndpoint(address, attributes,
137                                 maxPacketSize, interval);
138                     }
139 
140                     // don't allow if any interfaces are blacklisted
141                     if (isBlackListed(interfaceClass, interfaceSubclass, interfaceProtocol)) {
142                         return;
143                     }
144                     interfaces[intf] = new UsbInterface(interfaceId, interfaceClass,
145                             interfaceSubclass, interfaceProtocol, endpoints);
146                 }
147             } catch (Exception e) {
148                 // beware of index out of bound exceptions, which might happen if
149                 // a device does not set bNumEndpoints correctly
150                 Slog.e(TAG, "error parsing USB descriptors", e);
151                 return;
152             }
153 
154             UsbDevice device = new UsbDevice(deviceName, vendorID, productID,
155                     deviceClass, deviceSubclass, deviceProtocol, interfaces);
156             mDevices.put(deviceName, device);
157             mSettingsManager.deviceAttached(device);
158         }
159     }
160 
161     /* Called from JNI in monitorUsbHostBus to report USB device removal */
usbDeviceRemoved(String deviceName)162     private void usbDeviceRemoved(String deviceName) {
163         synchronized (mLock) {
164             UsbDevice device = mDevices.remove(deviceName);
165             if (device != null) {
166                 mSettingsManager.deviceDetached(device);
167             }
168         }
169     }
170 
systemReady()171     public void systemReady() {
172         synchronized (mLock) {
173             // Create a thread to call into native code to wait for USB host events.
174             // This thread will call us back on usbDeviceAdded and usbDeviceRemoved.
175             Runnable runnable = new Runnable() {
176                 public void run() {
177                     monitorUsbHostBus();
178                 }
179             };
180             new Thread(null, runnable, "UsbService host thread").start();
181         }
182     }
183 
184     /* Returns a list of all currently attached USB devices */
getDeviceList(Bundle devices)185     public void getDeviceList(Bundle devices) {
186         synchronized (mLock) {
187             for (String name : mDevices.keySet()) {
188                 devices.putParcelable(name, mDevices.get(name));
189             }
190         }
191     }
192 
193     /* Opens the specified USB device */
openDevice(String deviceName)194     public ParcelFileDescriptor openDevice(String deviceName) {
195         synchronized (mLock) {
196             if (isBlackListed(deviceName)) {
197                 throw new SecurityException("USB device is on a restricted bus");
198             }
199             UsbDevice device = mDevices.get(deviceName);
200             if (device == null) {
201                 // if it is not in mDevices, it either does not exist or is blacklisted
202                 throw new IllegalArgumentException(
203                         "device " + deviceName + " does not exist or is restricted");
204             }
205             mSettingsManager.checkPermission(device);
206             return nativeOpenDevice(deviceName);
207         }
208     }
209 
dump(FileDescriptor fd, PrintWriter pw)210     public void dump(FileDescriptor fd, PrintWriter pw) {
211         synchronized (mLock) {
212             pw.println("  USB Host State:");
213             for (String name : mDevices.keySet()) {
214                 pw.println("    " + name + ": " + mDevices.get(name));
215             }
216         }
217     }
218 
monitorUsbHostBus()219     private native void monitorUsbHostBus();
nativeOpenDevice(String deviceName)220     private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
221 }
222