Home | History | Annotate | Download | only in usb
      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 
     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 
     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 */
     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 */
     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 */
    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 
    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 */
    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 */
    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 
    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 
    219     private native void monitorUsbHostBus();
    220     private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
    221 }
    222