Loading services/java/com/android/server/UsbService.java +113 −56 Original line number Original line Diff line number Diff line Loading @@ -44,7 +44,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashMap; /** /** * <p>UsbService monitors for changes to USB state. * UsbService monitors for changes to USB state. * This includes code for both USB host support (where the android device is the host) * as well as USB device support (android device is connected to a USB host). * Accessory mode is a special case of USB device mode, where the android device is * connected to a USB host that supports the android accessory protocol. */ */ class UsbService extends IUsbManager.Stub { class UsbService extends IUsbManager.Stub { private static final String TAG = UsbService.class.getSimpleName(); private static final String TAG = UsbService.class.getSimpleName(); Loading @@ -63,7 +67,9 @@ class UsbService extends IUsbManager.Stub { private static final String USB_COMPOSITE_CLASS_PATH = private static final String USB_COMPOSITE_CLASS_PATH = "/sys/class/usb_composite"; "/sys/class/usb_composite"; private static final int MSG_UPDATE = 0; private static final int MSG_UPDATE_STATE = 0; private static final int MSG_FUNCTION_ENABLED = 1; private static final int MSG_FUNCTION_DISABLED = 2; // Delay for debouncing USB disconnects. // Delay for debouncing USB disconnects. // We often get rapid connect/disconnect events when enabling USB functions, // We often get rapid connect/disconnect events when enabling USB functions, Loading @@ -79,7 +85,6 @@ class UsbService extends IUsbManager.Stub { private int mLastConfiguration = -1; private int mLastConfiguration = -1; // lists of enabled and disabled USB functions (for USB device mode) // lists of enabled and disabled USB functions (for USB device mode) // synchronize on mEnabledFunctions when using either of these lists private final ArrayList<String> mEnabledFunctions = new ArrayList<String>(); private final ArrayList<String> mEnabledFunctions = new ArrayList<String>(); private final ArrayList<String> mDisabledFunctions = new ArrayList<String>(); private final ArrayList<String> mDisabledFunctions = new ArrayList<String>(); Loading @@ -90,12 +95,35 @@ class UsbService extends IUsbManager.Stub { private final String[] mHostBlacklist; private final String[] mHostBlacklist; private boolean mSystemReady; private boolean mSystemReady; private UsbAccessory mCurrentAccessory; private UsbAccessory mCurrentAccessory; // functions to restore after exiting accessory mode private final ArrayList<String> mAccessoryRestoreFunctions = new ArrayList<String>(); private final Context mContext; private final Context mContext; private final Object mLock = new Object(); private final void functionEnabled(String function, boolean enabled) { /* synchronized (mEnabledFunctions) { * Handles USB function enable/disable events (device mode) */ private final void functionEnabledLocked(String function, boolean enabled) { boolean enteringAccessoryMode = (enabled && UsbManager.USB_FUNCTION_ACCESSORY.equals(function)); if (enteringAccessoryMode) { // keep a list of functions to reenable after exiting accessory mode mAccessoryRestoreFunctions.clear(); int count = mEnabledFunctions.size(); for (int i = 0; i < count; i++) { String f = mEnabledFunctions.get(i); // RNDIS should not be restored and adb is handled automatically if (!UsbManager.USB_FUNCTION_RNDIS.equals(f) && !UsbManager.USB_FUNCTION_ADB.equals(f) && !UsbManager.USB_FUNCTION_ACCESSORY.equals(f)) { mAccessoryRestoreFunctions.add(f); } } } if (enabled) { if (enabled) { if (!mEnabledFunctions.contains(function)) { if (!mEnabledFunctions.contains(function)) { mEnabledFunctions.add(function); mEnabledFunctions.add(function); Loading @@ -107,9 +135,8 @@ class UsbService extends IUsbManager.Stub { } } mEnabledFunctions.remove(function); mEnabledFunctions.remove(function); } } } if (enabled && UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) { if (enteringAccessoryMode) { String[] strings = nativeGetAccessoryStrings(); String[] strings = nativeGetAccessoryStrings(); if (strings != null) { if (strings != null) { Log.d(TAG, "entering USB accessory mode"); Log.d(TAG, "entering USB accessory mode"); Loading @@ -136,6 +163,9 @@ class UsbService extends IUsbManager.Stub { } } } } /* * Listens for uevent messages from the kernel to monitor the USB state (device mode) */ private final UEventObserver mUEventObserver = new UEventObserver() { private final UEventObserver mUEventObserver = new UEventObserver() { @Override @Override public void onUEvent(UEventObserver.UEvent event) { public void onUEvent(UEventObserver.UEvent event) { Loading @@ -143,7 +173,7 @@ class UsbService extends IUsbManager.Stub { Slog.v(TAG, "USB UEVENT: " + event.toString()); Slog.v(TAG, "USB UEVENT: " + event.toString()); } } synchronized (this) { synchronized (mLock) { String name = event.get("SWITCH_NAME"); String name = event.get("SWITCH_NAME"); String state = event.get("SWITCH_STATE"); String state = event.get("SWITCH_STATE"); if (name != null && state != null) { if (name != null && state != null) { Loading Loading @@ -172,8 +202,11 @@ class UsbService extends IUsbManager.Stub { if (function != null && enabledStr != null) { if (function != null && enabledStr != null) { // Note: we do not broadcast a change when a function is enabled or disabled. // Note: we do not broadcast a change when a function is enabled or disabled. // We just record the state change for the next broadcast. // We just record the state change for the next broadcast. boolean enabled = "1".equals(enabledStr); int what = ("1".equals(enabledStr) ? functionEnabled(function, enabled); MSG_FUNCTION_ENABLED : MSG_FUNCTION_DISABLED); Message msg = Message.obtain(mHandler, what); msg.obj = function; mHandler.sendMessage(msg); } } } } } } Loading @@ -197,6 +230,7 @@ class UsbService extends IUsbManager.Stub { private final void init() { private final void init() { char[] buffer = new char[1024]; char[] buffer = new char[1024]; // Read initial USB state (device mode) mConfiguration = -1; mConfiguration = -1; try { try { FileReader file = new FileReader(USB_CONNECTED_PATH); FileReader file = new FileReader(USB_CONNECTED_PATH); Loading @@ -217,8 +251,8 @@ class UsbService extends IUsbManager.Stub { if (mConfiguration < 0) if (mConfiguration < 0) return; return; // Read initial list of enabled and disabled functions (device mode) try { try { synchronized (mEnabledFunctions) { File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles(); File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles(); for (int i = 0; i < files.length; i++) { for (int i = 0; i < files.length; i++) { File file = new File(files[i], "enable"); File file = new File(files[i], "enable"); Loading @@ -233,7 +267,6 @@ class UsbService extends IUsbManager.Stub { mDisabledFunctions.add(functionName); mDisabledFunctions.add(functionName); } } } } } } catch (FileNotFoundException e) { } catch (FileNotFoundException e) { Slog.w(TAG, "This kernel does not have USB composite class support"); Slog.w(TAG, "This kernel does not have USB composite class support"); } catch (Exception e) { } catch (Exception e) { Loading @@ -251,6 +284,7 @@ class UsbService extends IUsbManager.Stub { return false; return false; } } /* returns true if the USB device should not be accessible by applications (host mode) */ private boolean isBlackListed(int clazz, int subClass, int protocol) { private boolean isBlackListed(int clazz, int subClass, int protocol) { // blacklist hubs // blacklist hubs if (clazz == UsbConstants.USB_CLASS_HUB) return true; if (clazz == UsbConstants.USB_CLASS_HUB) return true; Loading @@ -264,7 +298,7 @@ class UsbService extends IUsbManager.Stub { return false; return false; } } // called from JNI in monitorUsbHostBus() /* Called from JNI in monitorUsbHostBus() to report new USB devices (host mode) */ private void usbDeviceAdded(String deviceName, int vendorID, int productID, private void usbDeviceAdded(String deviceName, int vendorID, int productID, int deviceClass, int deviceSubclass, int deviceProtocol, int deviceClass, int deviceSubclass, int deviceProtocol, /* array of quintuples containing id, class, subclass, protocol /* array of quintuples containing id, class, subclass, protocol Loading @@ -279,7 +313,7 @@ class UsbService extends IUsbManager.Stub { return; return; } } synchronized (mDevices) { synchronized (mLock) { if (mDevices.get(deviceName) != null) { if (mDevices.get(deviceName) != null) { Log.w(TAG, "device already on mDevices list: " + deviceName); Log.w(TAG, "device already on mDevices list: " + deviceName); return; return; Loading Loading @@ -338,9 +372,9 @@ class UsbService extends IUsbManager.Stub { } } } } // called from JNI in monitorUsbHostBus() /* Called from JNI in monitorUsbHostBus to report USB device removal (host mode) */ private void usbDeviceRemoved(String deviceName) { private void usbDeviceRemoved(String deviceName) { synchronized (mDevices) { synchronized (mLock) { UsbDevice device = mDevices.remove(deviceName); UsbDevice device = mDevices.remove(deviceName); if (device != null) { if (device != null) { Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED); Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED); Loading @@ -363,7 +397,7 @@ class UsbService extends IUsbManager.Stub { } } void systemReady() { void systemReady() { synchronized (this) { synchronized (mLock) { if (mContext.getResources().getBoolean( if (mContext.getResources().getBoolean( com.android.internal.R.bool.config_hasUsbHostSupport)) { com.android.internal.R.bool.config_hasUsbHostSupport)) { // start monitoring for connected USB devices // start monitoring for connected USB devices Loading @@ -375,21 +409,27 @@ class UsbService extends IUsbManager.Stub { } } } } /* * Sends a message to update the USB connected and configured state (device mode). * If delayed is true, then we add a small delay in sending the message to debounce * the USB connection when enabling USB tethering. */ private final void update(boolean delayed) { private final void update(boolean delayed) { mHandler.removeMessages(MSG_UPDATE); mHandler.removeMessages(MSG_UPDATE_STATE); mHandler.sendEmptyMessageDelayed(MSG_UPDATE, delayed ? UPDATE_DELAY : 0); mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATE, delayed ? UPDATE_DELAY : 0); } } /* Returns a list of all currently attached USB devices */ /* Returns a list of all currently attached USB devices (host mdoe) */ public void getDeviceList(Bundle devices) { public void getDeviceList(Bundle devices) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); synchronized (mDevices) { synchronized (mLock) { for (String name : mDevices.keySet()) { for (String name : mDevices.keySet()) { devices.putParcelable(name, mDevices.get(name)); devices.putParcelable(name, mDevices.get(name)); } } } } } } /* Opens the specified USB device (host mode) */ public ParcelFileDescriptor openDevice(String deviceName) { public ParcelFileDescriptor openDevice(String deviceName) { if (isBlackListed(deviceName)) { if (isBlackListed(deviceName)) { throw new SecurityException("USB device is on a restricted bus"); throw new SecurityException("USB device is on a restricted bus"); Loading @@ -403,19 +443,23 @@ class UsbService extends IUsbManager.Stub { return nativeOpenDevice(deviceName); return nativeOpenDevice(deviceName); } } /* returns the currently attached USB accessory (device mode) */ public UsbAccessory getCurrentAccessory() { public UsbAccessory getCurrentAccessory() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); return mCurrentAccessory; return mCurrentAccessory; } } /* opens the currently attached USB accessory (device mode) */ public ParcelFileDescriptor openAccessory() { public ParcelFileDescriptor openAccessory() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); return nativeOpenAccessory(); return nativeOpenAccessory(); } } /* * This handler is for deferred handling of events related to device mode and accessories. */ private final Handler mHandler = new Handler() { private final Handler mHandler = new Handler() { private void addEnabledFunctions(Intent intent) { private void addEnabledFunctionsLocked(Intent intent) { synchronized (mEnabledFunctions) { // include state of all USB functions in our extras // include state of all USB functions in our extras for (int i = 0; i < mEnabledFunctions.size(); i++) { for (int i = 0; i < mEnabledFunctions.size(); i++) { intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED); intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED); Loading @@ -424,13 +468,12 @@ class UsbService extends IUsbManager.Stub { intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED); intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED); } } } } } @Override @Override public void handleMessage(Message msg) { public void handleMessage(Message msg) { synchronized (mLock) { switch (msg.what) { switch (msg.what) { case MSG_UPDATE: case MSG_UPDATE_STATE: synchronized (this) { if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) { if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) { if (mConnected == 0 && mCurrentAccessory != null) { if (mConnected == 0 && mCurrentAccessory != null) { // turn off accessory mode when we are disconnected // turn off accessory mode when we are disconnected Loading @@ -438,6 +481,14 @@ class UsbService extends IUsbManager.Stub { UsbManager.USB_FUNCTION_ACCESSORY, false)) { UsbManager.USB_FUNCTION_ACCESSORY, false)) { Log.d(TAG, "exited USB accessory mode"); Log.d(TAG, "exited USB accessory mode"); // restore previously enabled functions for (String function : mAccessoryRestoreFunctions) { if (UsbManager.setFunctionEnabled(function, true)) { Log.e(TAG, "could not reenable function " + function); } } mAccessoryRestoreFunctions.clear(); Intent intent = new Intent( Intent intent = new Intent( UsbManager.ACTION_USB_ACCESSORY_DETACHED); UsbManager.ACTION_USB_ACCESSORY_DETACHED); intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory); intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory); Loading Loading @@ -468,17 +519,23 @@ class UsbService extends IUsbManager.Stub { intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0); intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0); intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration); intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration); addEnabledFunctions(intent); addEnabledFunctionsLocked(intent); mContext.sendStickyBroadcast(intent); mContext.sendStickyBroadcast(intent); } } } break; break; case MSG_FUNCTION_ENABLED: case MSG_FUNCTION_DISABLED: functionEnabledLocked((String)msg.obj, msg.what == MSG_FUNCTION_ENABLED); break; } } } } } }; }; // host support private native void monitorUsbHostBus(); private native void monitorUsbHostBus(); private native ParcelFileDescriptor nativeOpenDevice(String deviceName); private native ParcelFileDescriptor nativeOpenDevice(String deviceName); // accessory support private native String[] nativeGetAccessoryStrings(); private native String[] nativeGetAccessoryStrings(); private native ParcelFileDescriptor nativeOpenAccessory(); private native ParcelFileDescriptor nativeOpenAccessory(); } } Loading
services/java/com/android/server/UsbService.java +113 −56 Original line number Original line Diff line number Diff line Loading @@ -44,7 +44,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashMap; /** /** * <p>UsbService monitors for changes to USB state. * UsbService monitors for changes to USB state. * This includes code for both USB host support (where the android device is the host) * as well as USB device support (android device is connected to a USB host). * Accessory mode is a special case of USB device mode, where the android device is * connected to a USB host that supports the android accessory protocol. */ */ class UsbService extends IUsbManager.Stub { class UsbService extends IUsbManager.Stub { private static final String TAG = UsbService.class.getSimpleName(); private static final String TAG = UsbService.class.getSimpleName(); Loading @@ -63,7 +67,9 @@ class UsbService extends IUsbManager.Stub { private static final String USB_COMPOSITE_CLASS_PATH = private static final String USB_COMPOSITE_CLASS_PATH = "/sys/class/usb_composite"; "/sys/class/usb_composite"; private static final int MSG_UPDATE = 0; private static final int MSG_UPDATE_STATE = 0; private static final int MSG_FUNCTION_ENABLED = 1; private static final int MSG_FUNCTION_DISABLED = 2; // Delay for debouncing USB disconnects. // Delay for debouncing USB disconnects. // We often get rapid connect/disconnect events when enabling USB functions, // We often get rapid connect/disconnect events when enabling USB functions, Loading @@ -79,7 +85,6 @@ class UsbService extends IUsbManager.Stub { private int mLastConfiguration = -1; private int mLastConfiguration = -1; // lists of enabled and disabled USB functions (for USB device mode) // lists of enabled and disabled USB functions (for USB device mode) // synchronize on mEnabledFunctions when using either of these lists private final ArrayList<String> mEnabledFunctions = new ArrayList<String>(); private final ArrayList<String> mEnabledFunctions = new ArrayList<String>(); private final ArrayList<String> mDisabledFunctions = new ArrayList<String>(); private final ArrayList<String> mDisabledFunctions = new ArrayList<String>(); Loading @@ -90,12 +95,35 @@ class UsbService extends IUsbManager.Stub { private final String[] mHostBlacklist; private final String[] mHostBlacklist; private boolean mSystemReady; private boolean mSystemReady; private UsbAccessory mCurrentAccessory; private UsbAccessory mCurrentAccessory; // functions to restore after exiting accessory mode private final ArrayList<String> mAccessoryRestoreFunctions = new ArrayList<String>(); private final Context mContext; private final Context mContext; private final Object mLock = new Object(); private final void functionEnabled(String function, boolean enabled) { /* synchronized (mEnabledFunctions) { * Handles USB function enable/disable events (device mode) */ private final void functionEnabledLocked(String function, boolean enabled) { boolean enteringAccessoryMode = (enabled && UsbManager.USB_FUNCTION_ACCESSORY.equals(function)); if (enteringAccessoryMode) { // keep a list of functions to reenable after exiting accessory mode mAccessoryRestoreFunctions.clear(); int count = mEnabledFunctions.size(); for (int i = 0; i < count; i++) { String f = mEnabledFunctions.get(i); // RNDIS should not be restored and adb is handled automatically if (!UsbManager.USB_FUNCTION_RNDIS.equals(f) && !UsbManager.USB_FUNCTION_ADB.equals(f) && !UsbManager.USB_FUNCTION_ACCESSORY.equals(f)) { mAccessoryRestoreFunctions.add(f); } } } if (enabled) { if (enabled) { if (!mEnabledFunctions.contains(function)) { if (!mEnabledFunctions.contains(function)) { mEnabledFunctions.add(function); mEnabledFunctions.add(function); Loading @@ -107,9 +135,8 @@ class UsbService extends IUsbManager.Stub { } } mEnabledFunctions.remove(function); mEnabledFunctions.remove(function); } } } if (enabled && UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) { if (enteringAccessoryMode) { String[] strings = nativeGetAccessoryStrings(); String[] strings = nativeGetAccessoryStrings(); if (strings != null) { if (strings != null) { Log.d(TAG, "entering USB accessory mode"); Log.d(TAG, "entering USB accessory mode"); Loading @@ -136,6 +163,9 @@ class UsbService extends IUsbManager.Stub { } } } } /* * Listens for uevent messages from the kernel to monitor the USB state (device mode) */ private final UEventObserver mUEventObserver = new UEventObserver() { private final UEventObserver mUEventObserver = new UEventObserver() { @Override @Override public void onUEvent(UEventObserver.UEvent event) { public void onUEvent(UEventObserver.UEvent event) { Loading @@ -143,7 +173,7 @@ class UsbService extends IUsbManager.Stub { Slog.v(TAG, "USB UEVENT: " + event.toString()); Slog.v(TAG, "USB UEVENT: " + event.toString()); } } synchronized (this) { synchronized (mLock) { String name = event.get("SWITCH_NAME"); String name = event.get("SWITCH_NAME"); String state = event.get("SWITCH_STATE"); String state = event.get("SWITCH_STATE"); if (name != null && state != null) { if (name != null && state != null) { Loading Loading @@ -172,8 +202,11 @@ class UsbService extends IUsbManager.Stub { if (function != null && enabledStr != null) { if (function != null && enabledStr != null) { // Note: we do not broadcast a change when a function is enabled or disabled. // Note: we do not broadcast a change when a function is enabled or disabled. // We just record the state change for the next broadcast. // We just record the state change for the next broadcast. boolean enabled = "1".equals(enabledStr); int what = ("1".equals(enabledStr) ? functionEnabled(function, enabled); MSG_FUNCTION_ENABLED : MSG_FUNCTION_DISABLED); Message msg = Message.obtain(mHandler, what); msg.obj = function; mHandler.sendMessage(msg); } } } } } } Loading @@ -197,6 +230,7 @@ class UsbService extends IUsbManager.Stub { private final void init() { private final void init() { char[] buffer = new char[1024]; char[] buffer = new char[1024]; // Read initial USB state (device mode) mConfiguration = -1; mConfiguration = -1; try { try { FileReader file = new FileReader(USB_CONNECTED_PATH); FileReader file = new FileReader(USB_CONNECTED_PATH); Loading @@ -217,8 +251,8 @@ class UsbService extends IUsbManager.Stub { if (mConfiguration < 0) if (mConfiguration < 0) return; return; // Read initial list of enabled and disabled functions (device mode) try { try { synchronized (mEnabledFunctions) { File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles(); File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles(); for (int i = 0; i < files.length; i++) { for (int i = 0; i < files.length; i++) { File file = new File(files[i], "enable"); File file = new File(files[i], "enable"); Loading @@ -233,7 +267,6 @@ class UsbService extends IUsbManager.Stub { mDisabledFunctions.add(functionName); mDisabledFunctions.add(functionName); } } } } } } catch (FileNotFoundException e) { } catch (FileNotFoundException e) { Slog.w(TAG, "This kernel does not have USB composite class support"); Slog.w(TAG, "This kernel does not have USB composite class support"); } catch (Exception e) { } catch (Exception e) { Loading @@ -251,6 +284,7 @@ class UsbService extends IUsbManager.Stub { return false; return false; } } /* returns true if the USB device should not be accessible by applications (host mode) */ private boolean isBlackListed(int clazz, int subClass, int protocol) { private boolean isBlackListed(int clazz, int subClass, int protocol) { // blacklist hubs // blacklist hubs if (clazz == UsbConstants.USB_CLASS_HUB) return true; if (clazz == UsbConstants.USB_CLASS_HUB) return true; Loading @@ -264,7 +298,7 @@ class UsbService extends IUsbManager.Stub { return false; return false; } } // called from JNI in monitorUsbHostBus() /* Called from JNI in monitorUsbHostBus() to report new USB devices (host mode) */ private void usbDeviceAdded(String deviceName, int vendorID, int productID, private void usbDeviceAdded(String deviceName, int vendorID, int productID, int deviceClass, int deviceSubclass, int deviceProtocol, int deviceClass, int deviceSubclass, int deviceProtocol, /* array of quintuples containing id, class, subclass, protocol /* array of quintuples containing id, class, subclass, protocol Loading @@ -279,7 +313,7 @@ class UsbService extends IUsbManager.Stub { return; return; } } synchronized (mDevices) { synchronized (mLock) { if (mDevices.get(deviceName) != null) { if (mDevices.get(deviceName) != null) { Log.w(TAG, "device already on mDevices list: " + deviceName); Log.w(TAG, "device already on mDevices list: " + deviceName); return; return; Loading Loading @@ -338,9 +372,9 @@ class UsbService extends IUsbManager.Stub { } } } } // called from JNI in monitorUsbHostBus() /* Called from JNI in monitorUsbHostBus to report USB device removal (host mode) */ private void usbDeviceRemoved(String deviceName) { private void usbDeviceRemoved(String deviceName) { synchronized (mDevices) { synchronized (mLock) { UsbDevice device = mDevices.remove(deviceName); UsbDevice device = mDevices.remove(deviceName); if (device != null) { if (device != null) { Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED); Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED); Loading @@ -363,7 +397,7 @@ class UsbService extends IUsbManager.Stub { } } void systemReady() { void systemReady() { synchronized (this) { synchronized (mLock) { if (mContext.getResources().getBoolean( if (mContext.getResources().getBoolean( com.android.internal.R.bool.config_hasUsbHostSupport)) { com.android.internal.R.bool.config_hasUsbHostSupport)) { // start monitoring for connected USB devices // start monitoring for connected USB devices Loading @@ -375,21 +409,27 @@ class UsbService extends IUsbManager.Stub { } } } } /* * Sends a message to update the USB connected and configured state (device mode). * If delayed is true, then we add a small delay in sending the message to debounce * the USB connection when enabling USB tethering. */ private final void update(boolean delayed) { private final void update(boolean delayed) { mHandler.removeMessages(MSG_UPDATE); mHandler.removeMessages(MSG_UPDATE_STATE); mHandler.sendEmptyMessageDelayed(MSG_UPDATE, delayed ? UPDATE_DELAY : 0); mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATE, delayed ? UPDATE_DELAY : 0); } } /* Returns a list of all currently attached USB devices */ /* Returns a list of all currently attached USB devices (host mdoe) */ public void getDeviceList(Bundle devices) { public void getDeviceList(Bundle devices) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); synchronized (mDevices) { synchronized (mLock) { for (String name : mDevices.keySet()) { for (String name : mDevices.keySet()) { devices.putParcelable(name, mDevices.get(name)); devices.putParcelable(name, mDevices.get(name)); } } } } } } /* Opens the specified USB device (host mode) */ public ParcelFileDescriptor openDevice(String deviceName) { public ParcelFileDescriptor openDevice(String deviceName) { if (isBlackListed(deviceName)) { if (isBlackListed(deviceName)) { throw new SecurityException("USB device is on a restricted bus"); throw new SecurityException("USB device is on a restricted bus"); Loading @@ -403,19 +443,23 @@ class UsbService extends IUsbManager.Stub { return nativeOpenDevice(deviceName); return nativeOpenDevice(deviceName); } } /* returns the currently attached USB accessory (device mode) */ public UsbAccessory getCurrentAccessory() { public UsbAccessory getCurrentAccessory() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); return mCurrentAccessory; return mCurrentAccessory; } } /* opens the currently attached USB accessory (device mode) */ public ParcelFileDescriptor openAccessory() { public ParcelFileDescriptor openAccessory() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_USB, null); return nativeOpenAccessory(); return nativeOpenAccessory(); } } /* * This handler is for deferred handling of events related to device mode and accessories. */ private final Handler mHandler = new Handler() { private final Handler mHandler = new Handler() { private void addEnabledFunctions(Intent intent) { private void addEnabledFunctionsLocked(Intent intent) { synchronized (mEnabledFunctions) { // include state of all USB functions in our extras // include state of all USB functions in our extras for (int i = 0; i < mEnabledFunctions.size(); i++) { for (int i = 0; i < mEnabledFunctions.size(); i++) { intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED); intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED); Loading @@ -424,13 +468,12 @@ class UsbService extends IUsbManager.Stub { intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED); intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED); } } } } } @Override @Override public void handleMessage(Message msg) { public void handleMessage(Message msg) { synchronized (mLock) { switch (msg.what) { switch (msg.what) { case MSG_UPDATE: case MSG_UPDATE_STATE: synchronized (this) { if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) { if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) { if (mConnected == 0 && mCurrentAccessory != null) { if (mConnected == 0 && mCurrentAccessory != null) { // turn off accessory mode when we are disconnected // turn off accessory mode when we are disconnected Loading @@ -438,6 +481,14 @@ class UsbService extends IUsbManager.Stub { UsbManager.USB_FUNCTION_ACCESSORY, false)) { UsbManager.USB_FUNCTION_ACCESSORY, false)) { Log.d(TAG, "exited USB accessory mode"); Log.d(TAG, "exited USB accessory mode"); // restore previously enabled functions for (String function : mAccessoryRestoreFunctions) { if (UsbManager.setFunctionEnabled(function, true)) { Log.e(TAG, "could not reenable function " + function); } } mAccessoryRestoreFunctions.clear(); Intent intent = new Intent( Intent intent = new Intent( UsbManager.ACTION_USB_ACCESSORY_DETACHED); UsbManager.ACTION_USB_ACCESSORY_DETACHED); intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory); intent.putExtra(UsbManager.EXTRA_ACCESSORY, mCurrentAccessory); Loading Loading @@ -468,17 +519,23 @@ class UsbService extends IUsbManager.Stub { intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0); intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0); intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration); intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration); addEnabledFunctions(intent); addEnabledFunctionsLocked(intent); mContext.sendStickyBroadcast(intent); mContext.sendStickyBroadcast(intent); } } } break; break; case MSG_FUNCTION_ENABLED: case MSG_FUNCTION_DISABLED: functionEnabledLocked((String)msg.obj, msg.what == MSG_FUNCTION_ENABLED); break; } } } } } }; }; // host support private native void monitorUsbHostBus(); private native void monitorUsbHostBus(); private native ParcelFileDescriptor nativeOpenDevice(String deviceName); private native ParcelFileDescriptor nativeOpenDevice(String deviceName); // accessory support private native String[] nativeGetAccessoryStrings(); private native String[] nativeGetAccessoryStrings(); private native ParcelFileDescriptor nativeOpenAccessory(); private native ParcelFileDescriptor nativeOpenAccessory(); } }