summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/UsbService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/UsbService.java')
-rw-r--r--services/java/com/android/server/UsbService.java133
1 files changed, 130 insertions, 3 deletions
diff --git a/services/java/com/android/server/UsbService.java b/services/java/com/android/server/UsbService.java
index 8ef03d4..5c03fb2 100644
--- a/services/java/com/android/server/UsbService.java
+++ b/services/java/com/android/server/UsbService.java
@@ -19,10 +19,18 @@ package com.android.server;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.hardware.IUsbManager;
+import android.hardware.UsbConstants;
+import android.hardware.UsbDevice;
+import android.hardware.UsbEndpoint;
+import android.hardware.UsbInterface;
import android.hardware.UsbManager;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.os.Parcelable;
+import android.os.ParcelFileDescriptor;
import android.os.UEventObserver;
import android.provider.Settings;
import android.util.Log;
@@ -32,11 +40,12 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
+import java.util.HashMap;
/**
* <p>UsbService monitors for changes to USB state.
*/
-class UsbService {
+class UsbService extends IUsbManager.Stub {
private static final String TAG = UsbService.class.getSimpleName();
private static final boolean LOG = false;
@@ -68,10 +77,12 @@ class UsbService {
private int mLastConnected = -1;
private int mLastConfiguration = -1;
- // lists of enabled and disabled USB functions
+ // lists of enabled and disabled USB functions (for USB device mode)
private final ArrayList<String> mEnabledFunctions = new ArrayList<String>();
private final ArrayList<String> mDisabledFunctions = new ArrayList<String>();
+ private final HashMap<String,UsbDevice> mDevices = new HashMap<String,UsbDevice>();
+
private boolean mSystemReady;
private final Context mContext;
@@ -186,8 +197,106 @@ class UsbService {
}
}
+ // called from JNI in monitorUsbHostBus()
+ private void usbDeviceAdded(String deviceName, int vendorID, int productID,
+ int deviceClass, int deviceSubclass, int deviceProtocol,
+ /* array of quintuples containing id, class, subclass, protocol
+ and number of endpoints for each interface */
+ int[] interfaceValues,
+ /* array of quadruples containing address, attributes, max packet size
+ and interval for each endpoint */
+ int[] endpointValues) {
+
+ // ignore hubs
+ if (deviceClass == UsbConstants.USB_CLASS_HUB) {
+ return;
+ }
+
+ synchronized (mDevices) {
+ if (mDevices.get(deviceName) != null) {
+ Log.w(TAG, "device already on mDevices list: " + deviceName);
+ return;
+ }
+
+ int numInterfaces = interfaceValues.length / 5;
+ Parcelable[] interfaces = new UsbInterface[numInterfaces];
+ try {
+ // repackage interfaceValues as an array of UsbInterface
+ int intf, endp, ival = 0, eval = 0;
+ boolean hasGoodInterface = false;
+ for (intf = 0; intf < numInterfaces; intf++) {
+ int interfaceId = interfaceValues[ival++];
+ int interfaceClass = interfaceValues[ival++];
+ int interfaceSubclass = interfaceValues[ival++];
+ int interfaceProtocol = interfaceValues[ival++];
+ int numEndpoints = interfaceValues[ival++];
+
+ Parcelable[] endpoints = new UsbEndpoint[numEndpoints];
+ for (endp = 0; endp < numEndpoints; endp++) {
+ int address = endpointValues[eval++];
+ int attributes = endpointValues[eval++];
+ int maxPacketSize = endpointValues[eval++];
+ int interval = endpointValues[eval++];
+ endpoints[endp] = new UsbEndpoint(address, attributes,
+ maxPacketSize, interval);
+ }
+
+ if (interfaceClass != UsbConstants.USB_CLASS_HUB) {
+ hasGoodInterface = true;
+ }
+ interfaces[intf] = new UsbInterface(interfaceId, interfaceClass,
+ interfaceSubclass, interfaceProtocol, endpoints);
+ }
+
+ if (!hasGoodInterface) {
+ return;
+ }
+ } catch (Exception e) {
+ // beware of index out of bound exceptions, which might happen if
+ // a device does not set bNumEndpoints correctly
+ Log.e(TAG, "error parsing USB descriptors", e);
+ return;
+ }
+
+ UsbDevice device = new UsbDevice(deviceName, vendorID, productID,
+ deviceClass, deviceSubclass, deviceProtocol, interfaces);
+ mDevices.put(deviceName, device);
+
+ Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+ intent.putExtra(UsbManager.EXTRA_DEVICE_NAME, deviceName);
+ intent.putExtra(UsbManager.EXTRA_VENDOR_ID, vendorID);
+ intent.putExtra(UsbManager.EXTRA_PRODUCT_ID, productID);
+ intent.putExtra(UsbManager.EXTRA_DEVICE_CLASS, deviceClass);
+ intent.putExtra(UsbManager.EXTRA_DEVICE_SUBCLASS, deviceSubclass);
+ intent.putExtra(UsbManager.EXTRA_DEVICE_PROTOCOL, deviceProtocol);
+ intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+ Log.d(TAG, "usbDeviceAdded, sending " + intent);
+ mContext.sendBroadcast(intent);
+ }
+ }
+
+ // called from JNI in monitorUsbHostBus()
+ private void usbDeviceRemoved(String deviceName) {
+ synchronized (mDevices) {
+ UsbDevice device = mDevices.remove(deviceName);
+ if (device != null) {
+ Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
+ intent.putExtra(UsbManager.EXTRA_DEVICE_NAME, deviceName);
+ Log.d(TAG, "usbDeviceRemoved, sending " + intent);
+ mContext.sendBroadcast(intent);
+ }
+ }
+ }
+
private void initHostSupport() {
- // temporarily disabled
+ // Create a thread to call into native code to wait for USB host events.
+ // This thread will call us back on usbDeviceAdded and usbDeviceRemoved.
+ Runnable runnable = new Runnable() {
+ public void run() {
+ monitorUsbHostBus();
+ }
+ };
+ new Thread(null, runnable, "UsbService host thread").start();
}
void systemReady() {
@@ -208,6 +317,21 @@ class UsbService {
mHandler.sendEmptyMessageDelayed(MSG_UPDATE, delayed ? UPDATE_DELAY : 0);
}
+ /* Returns a list of all currently attached USB devices */
+ public void getDeviceList(Bundle devices) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
+ synchronized (mDevices) {
+ for (String name : mDevices.keySet()) {
+ devices.putParcelable(name, mDevices.get(name));
+ }
+ }
+ }
+
+ public ParcelFileDescriptor openDevice(String deviceName) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null);
+ return nativeOpenDevice(deviceName);
+ }
+
private final Handler mHandler = new Handler() {
private void addEnabledFunctions(Intent intent) {
// include state of all USB functions in our extras
@@ -249,4 +373,7 @@ class UsbService {
}
}
};
+
+ private native void monitorUsbHostBus();
+ private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
}