UsbService.java revision 1c0e543638fa940651b675645146fd71c2ebd9b9
1/* 2 * Copyright (C) 2010 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 and 14 * limitations under the License. 15 */ 16 17package com.android.server.usb; 18 19import android.app.PendingIntent; 20import android.content.BroadcastReceiver; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.content.pm.PackageManager; 26import android.hardware.usb.IUsbManager; 27import android.hardware.usb.UsbAccessory; 28import android.hardware.usb.UsbConstants; 29import android.hardware.usb.UsbDevice; 30import android.hardware.usb.UsbEndpoint; 31import android.hardware.usb.UsbInterface; 32import android.hardware.usb.UsbManager; 33import android.net.Uri; 34import android.os.Binder; 35import android.os.Bundle; 36import android.os.Handler; 37import android.os.Message; 38import android.os.Parcelable; 39import android.os.ParcelFileDescriptor; 40import android.os.UEventObserver; 41import android.provider.Settings; 42import android.util.Log; 43import android.util.Slog; 44 45import java.io.File; 46import java.io.FileDescriptor; 47import java.io.FileNotFoundException; 48import java.io.FileReader; 49import java.io.PrintWriter; 50import java.util.ArrayList; 51import java.util.HashMap; 52import java.util.List; 53 54/** 55 * UsbService monitors for changes to USB state. 56 * This includes code for both USB host support (where the android device is the host) 57 * as well as USB device support (android device is connected to a USB host). 58 * Accessory mode is a special case of USB device mode, where the android device is 59 * connected to a USB host that supports the android accessory protocol. 60 */ 61public class UsbService extends IUsbManager.Stub { 62 private static final String TAG = UsbService.class.getSimpleName(); 63 private static final boolean LOG = false; 64 65 private static final String USB_CONNECTED_MATCH = 66 "DEVPATH=/devices/virtual/switch/usb_connected"; 67 private static final String USB_CONFIGURATION_MATCH = 68 "DEVPATH=/devices/virtual/switch/usb_configuration"; 69 private static final String USB_FUNCTIONS_MATCH = 70 "DEVPATH=/devices/virtual/usb_composite/"; 71 private static final String USB_CONNECTED_PATH = 72 "/sys/class/switch/usb_connected/state"; 73 private static final String USB_CONFIGURATION_PATH = 74 "/sys/class/switch/usb_configuration/state"; 75 private static final String USB_COMPOSITE_CLASS_PATH = 76 "/sys/class/usb_composite"; 77 78 private static final int MSG_UPDATE_STATE = 0; 79 private static final int MSG_FUNCTION_ENABLED = 1; 80 private static final int MSG_FUNCTION_DISABLED = 2; 81 82 // Delay for debouncing USB disconnects. 83 // We often get rapid connect/disconnect events when enabling USB functions, 84 // which need debouncing. 85 private static final int UPDATE_DELAY = 1000; 86 87 // current connected and configuration state 88 private int mConnected; 89 private int mConfiguration; 90 91 // last broadcasted connected and configuration state 92 private int mLastConnected = -1; 93 private int mLastConfiguration = -1; 94 95 // lists of enabled and disabled USB functions (for USB device mode) 96 private final ArrayList<String> mEnabledFunctions = new ArrayList<String>(); 97 private final ArrayList<String> mDisabledFunctions = new ArrayList<String>(); 98 99 // contains all connected USB devices (for USB host mode) 100 private final HashMap<String,UsbDevice> mDevices = new HashMap<String,UsbDevice>(); 101 102 // USB busses to exclude from USB host support 103 private final String[] mHostBlacklist; 104 105 private boolean mSystemReady; 106 107 private UsbAccessory mCurrentAccessory; 108 // USB functions that are enabled by default, to restore after exiting accessory mode 109 private final ArrayList<String> mDefaultFunctions = new ArrayList<String>(); 110 111 private final Context mContext; 112 private final Object mLock = new Object(); 113 private final UsbDeviceSettingsManager mDeviceManager; 114 private final boolean mHasUsbHost; 115 private final boolean mHasUsbAccessory; 116 117 private final void readCurrentAccessoryLocked() { 118 if (mHasUsbAccessory) { 119 String[] strings = nativeGetAccessoryStrings(); 120 if (strings != null) { 121 mCurrentAccessory = new UsbAccessory(strings); 122 Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); 123 if (mSystemReady) { 124 mDeviceManager.accessoryAttached(mCurrentAccessory); 125 } 126 } else { 127 Log.e(TAG, "nativeGetAccessoryStrings failed"); 128 } 129 } 130 } 131 132 /* 133 * Handles USB function enable/disable events (device mode) 134 */ 135 private final void functionEnabledLocked(String function, boolean enabled) { 136 if (enabled) { 137 if (!mEnabledFunctions.contains(function)) { 138 mEnabledFunctions.add(function); 139 } 140 mDisabledFunctions.remove(function); 141 142 if (UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) { 143 readCurrentAccessoryLocked(); 144 } 145 } else { 146 if (!mDisabledFunctions.contains(function)) { 147 mDisabledFunctions.add(function); 148 } 149 mEnabledFunctions.remove(function); 150 } 151 } 152 153 /* 154 * Listens for uevent messages from the kernel to monitor the USB state (device mode) 155 */ 156 private final UEventObserver mUEventObserver = new UEventObserver() { 157 @Override 158 public void onUEvent(UEventObserver.UEvent event) { 159 if (Log.isLoggable(TAG, Log.VERBOSE)) { 160 Slog.v(TAG, "USB UEVENT: " + event.toString()); 161 } 162 163 synchronized (mLock) { 164 String name = event.get("SWITCH_NAME"); 165 String state = event.get("SWITCH_STATE"); 166 if (name != null && state != null) { 167 try { 168 int intState = Integer.parseInt(state); 169 if ("usb_connected".equals(name)) { 170 mConnected = intState; 171 // trigger an Intent broadcast 172 if (mSystemReady) { 173 // debounce disconnects to avoid problems bringing up USB tethering 174 update(mConnected == 0); 175 } 176 } else if ("usb_configuration".equals(name)) { 177 mConfiguration = intState; 178 // trigger an Intent broadcast 179 if (mSystemReady) { 180 update(mConnected == 0); 181 } 182 } 183 } catch (NumberFormatException e) { 184 Slog.e(TAG, "Could not parse switch state from event " + event); 185 } 186 } else { 187 String function = event.get("FUNCTION"); 188 String enabledStr = event.get("ENABLED"); 189 if (function != null && enabledStr != null) { 190 // Note: we do not broadcast a change when a function is enabled or disabled. 191 // We just record the state change for the next broadcast. 192 int what = ("1".equals(enabledStr) ? 193 MSG_FUNCTION_ENABLED : MSG_FUNCTION_DISABLED); 194 Message msg = Message.obtain(mHandler, what); 195 msg.obj = function; 196 mHandler.sendMessage(msg); 197 } 198 } 199 } 200 } 201 }; 202 203 private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { 204 public void onReceive(Context context, Intent intent) { 205 // handle accessories attached at boot time 206 synchronized (mLock) { 207 if (mCurrentAccessory != null) { 208 mDeviceManager.accessoryAttached(mCurrentAccessory); 209 } 210 } 211 } 212 }; 213 214 public UsbService(Context context) { 215 mContext = context; 216 mDeviceManager = new UsbDeviceSettingsManager(context); 217 PackageManager pm = mContext.getPackageManager(); 218 mHasUsbHost = pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST); 219 mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY); 220 221 mHostBlacklist = context.getResources().getStringArray( 222 com.android.internal.R.array.config_usbHostBlacklist); 223 224 synchronized (mLock) { 225 init(); // set initial status 226 227 // Watch for USB configuration changes 228 if (mConfiguration >= 0) { 229 mUEventObserver.startObserving(USB_CONNECTED_MATCH); 230 mUEventObserver.startObserving(USB_CONFIGURATION_MATCH); 231 mUEventObserver.startObserving(USB_FUNCTIONS_MATCH); 232 } 233 } 234 } 235 236 private final void init() { 237 char[] buffer = new char[1024]; 238 boolean inAccessoryMode = false; 239 240 // Read initial USB state (device mode) 241 mConfiguration = -1; 242 try { 243 FileReader file = new FileReader(USB_CONNECTED_PATH); 244 int len = file.read(buffer, 0, 1024); 245 file.close(); 246 mConnected = Integer.valueOf((new String(buffer, 0, len)).trim()); 247 248 file = new FileReader(USB_CONFIGURATION_PATH); 249 len = file.read(buffer, 0, 1024); 250 file.close(); 251 mConfiguration = Integer.valueOf((new String(buffer, 0, len)).trim()); 252 253 } catch (FileNotFoundException e) { 254 Slog.i(TAG, "This kernel does not have USB configuration switch support"); 255 } catch (Exception e) { 256 Slog.e(TAG, "" , e); 257 } 258 if (mConfiguration < 0) { 259 // This may happen in the emulator or devices without USB device mode support 260 return; 261 } 262 263 // Read initial list of enabled and disabled functions (device mode) 264 try { 265 File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles(); 266 for (int i = 0; i < files.length; i++) { 267 File file = new File(files[i], "enable"); 268 FileReader reader = new FileReader(file); 269 int len = reader.read(buffer, 0, 1024); 270 reader.close(); 271 int value = Integer.valueOf((new String(buffer, 0, len)).trim()); 272 String functionName = files[i].getName(); 273 if (value == 1) { 274 mEnabledFunctions.add(functionName); 275 if (UsbManager.USB_FUNCTION_ACCESSORY.equals(functionName)) { 276 // The USB accessory driver is on by default, but it might have been 277 // enabled before the USB service has initialized. 278 inAccessoryMode = true; 279 } else if (!UsbManager.USB_FUNCTION_ADB.equals(functionName)) { 280 // adb is enabled/disabled automatically by the adbd daemon, 281 // so don't treat it as a default function. 282 mDefaultFunctions.add(functionName); 283 } 284 } else { 285 mDisabledFunctions.add(functionName); 286 } 287 } 288 } catch (FileNotFoundException e) { 289 Slog.w(TAG, "This kernel does not have USB composite class support"); 290 } catch (Exception e) { 291 Slog.e(TAG, "" , e); 292 } 293 294 // handle the case where an accessory switched the driver to accessory mode 295 // before the framework finished booting 296 if (inAccessoryMode) { 297 readCurrentAccessoryLocked(); 298 299 // FIXME - if we booted in accessory mode, then we have no way to figure out 300 // which functions are enabled by default. 301 // For now, assume that MTP or mass storage are the only possibilities 302 if (mDisabledFunctions.contains(UsbManager.USB_FUNCTION_MTP)) { 303 mDefaultFunctions.add(UsbManager.USB_FUNCTION_MTP); 304 } else if (mDisabledFunctions.contains(UsbManager.USB_FUNCTION_MASS_STORAGE)) { 305 mDefaultFunctions.add(UsbManager.USB_FUNCTION_MASS_STORAGE); 306 } 307 } 308 } 309 310 private boolean isBlackListed(String deviceName) { 311 int count = mHostBlacklist.length; 312 for (int i = 0; i < count; i++) { 313 if (deviceName.startsWith(mHostBlacklist[i])) { 314 return true; 315 } 316 } 317 return false; 318 } 319 320 /* returns true if the USB device should not be accessible by applications (host mode) */ 321 private boolean isBlackListed(int clazz, int subClass, int protocol) { 322 // blacklist hubs 323 if (clazz == UsbConstants.USB_CLASS_HUB) return true; 324 325 // blacklist HID boot devices (mouse and keyboard) 326 if (clazz == UsbConstants.USB_CLASS_HID && 327 subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT) { 328 return true; 329 } 330 331 return false; 332 } 333 334 /* Called from JNI in monitorUsbHostBus() to report new USB devices (host mode) */ 335 private void usbDeviceAdded(String deviceName, int vendorID, int productID, 336 int deviceClass, int deviceSubclass, int deviceProtocol, 337 /* array of quintuples containing id, class, subclass, protocol 338 and number of endpoints for each interface */ 339 int[] interfaceValues, 340 /* array of quadruples containing address, attributes, max packet size 341 and interval for each endpoint */ 342 int[] endpointValues) { 343 344 if (isBlackListed(deviceName) || 345 isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) { 346 return; 347 } 348 349 synchronized (mLock) { 350 if (mDevices.get(deviceName) != null) { 351 Log.w(TAG, "device already on mDevices list: " + deviceName); 352 return; 353 } 354 355 int numInterfaces = interfaceValues.length / 5; 356 Parcelable[] interfaces = new UsbInterface[numInterfaces]; 357 try { 358 // repackage interfaceValues as an array of UsbInterface 359 int intf, endp, ival = 0, eval = 0; 360 for (intf = 0; intf < numInterfaces; intf++) { 361 int interfaceId = interfaceValues[ival++]; 362 int interfaceClass = interfaceValues[ival++]; 363 int interfaceSubclass = interfaceValues[ival++]; 364 int interfaceProtocol = interfaceValues[ival++]; 365 int numEndpoints = interfaceValues[ival++]; 366 367 Parcelable[] endpoints = new UsbEndpoint[numEndpoints]; 368 for (endp = 0; endp < numEndpoints; endp++) { 369 int address = endpointValues[eval++]; 370 int attributes = endpointValues[eval++]; 371 int maxPacketSize = endpointValues[eval++]; 372 int interval = endpointValues[eval++]; 373 endpoints[endp] = new UsbEndpoint(address, attributes, 374 maxPacketSize, interval); 375 } 376 377 // don't allow if any interfaces are blacklisted 378 if (isBlackListed(interfaceClass, interfaceSubclass, interfaceProtocol)) { 379 return; 380 } 381 interfaces[intf] = new UsbInterface(interfaceId, interfaceClass, 382 interfaceSubclass, interfaceProtocol, endpoints); 383 } 384 } catch (Exception e) { 385 // beware of index out of bound exceptions, which might happen if 386 // a device does not set bNumEndpoints correctly 387 Log.e(TAG, "error parsing USB descriptors", e); 388 return; 389 } 390 391 UsbDevice device = new UsbDevice(deviceName, vendorID, productID, 392 deviceClass, deviceSubclass, deviceProtocol, interfaces); 393 mDevices.put(deviceName, device); 394 mDeviceManager.deviceAttached(device); 395 } 396 } 397 398 /* Called from JNI in monitorUsbHostBus to report USB device removal (host mode) */ 399 private void usbDeviceRemoved(String deviceName) { 400 synchronized (mLock) { 401 UsbDevice device = mDevices.remove(deviceName); 402 if (device != null) { 403 mDeviceManager.deviceDetached(device); 404 } 405 } 406 } 407 408 private void initHostSupport() { 409 // Create a thread to call into native code to wait for USB host events. 410 // This thread will call us back on usbDeviceAdded and usbDeviceRemoved. 411 Runnable runnable = new Runnable() { 412 public void run() { 413 monitorUsbHostBus(); 414 } 415 }; 416 new Thread(null, runnable, "UsbService host thread").start(); 417 } 418 419 public void systemReady() { 420 synchronized (mLock) { 421 if (mHasUsbHost) { 422 // start monitoring for connected USB devices 423 initHostSupport(); 424 } 425 426 update(false); 427 if (mCurrentAccessory != null) { 428 Log.d(TAG, "accessoryAttached at systemReady"); 429 // its still too early to handle accessories, so add a BOOT_COMPLETED receiver 430 // to handle this later. 431 mContext.registerReceiver(mBootCompletedReceiver, 432 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 433 } 434 mSystemReady = true; 435 } 436 } 437 438 /* 439 * Sends a message to update the USB connected and configured state (device mode). 440 * If delayed is true, then we add a small delay in sending the message to debounce 441 * the USB connection when enabling USB tethering. 442 */ 443 private final void update(boolean delayed) { 444 mHandler.removeMessages(MSG_UPDATE_STATE); 445 mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATE, delayed ? UPDATE_DELAY : 0); 446 } 447 448 /* Returns a list of all currently attached USB devices (host mdoe) */ 449 public void getDeviceList(Bundle devices) { 450 synchronized (mLock) { 451 for (String name : mDevices.keySet()) { 452 devices.putParcelable(name, mDevices.get(name)); 453 } 454 } 455 } 456 457 /* Opens the specified USB device (host mode) */ 458 public ParcelFileDescriptor openDevice(String deviceName) { 459 synchronized (mLock) { 460 if (isBlackListed(deviceName)) { 461 throw new SecurityException("USB device is on a restricted bus"); 462 } 463 UsbDevice device = mDevices.get(deviceName); 464 if (device == null) { 465 // if it is not in mDevices, it either does not exist or is blacklisted 466 throw new IllegalArgumentException( 467 "device " + deviceName + " does not exist or is restricted"); 468 } 469 mDeviceManager.checkPermission(device); 470 return nativeOpenDevice(deviceName); 471 } 472 } 473 474 /* returns the currently attached USB accessory (device mode) */ 475 public UsbAccessory getCurrentAccessory() { 476 return mCurrentAccessory; 477 } 478 479 /* opens the currently attached USB accessory (device mode) */ 480 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { 481 synchronized (mLock) { 482 if (mCurrentAccessory == null) { 483 throw new IllegalArgumentException("no accessory attached"); 484 } 485 if (!mCurrentAccessory.equals(accessory)) { 486 Log.e(TAG, accessory.toString() + " does not match current accessory " 487 + mCurrentAccessory); 488 throw new IllegalArgumentException("accessory not attached"); 489 } 490 mDeviceManager.checkPermission(mCurrentAccessory); 491 return nativeOpenAccessory(); 492 } 493 } 494 495 public void setDevicePackage(UsbDevice device, String packageName) { 496 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 497 mDeviceManager.setDevicePackage(device, packageName); 498 } 499 500 public void setAccessoryPackage(UsbAccessory accessory, String packageName) { 501 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 502 mDeviceManager.setAccessoryPackage(accessory, packageName); 503 } 504 505 public boolean hasDevicePermission(UsbDevice device) { 506 return mDeviceManager.hasPermission(device); 507 } 508 509 public boolean hasAccessoryPermission(UsbAccessory accessory) { 510 return mDeviceManager.hasPermission(accessory); 511 } 512 513 public void requestDevicePermission(UsbDevice device, String packageName, 514 PendingIntent pi) { 515 mDeviceManager.requestPermission(device, packageName, pi); 516 } 517 518 public void requestAccessoryPermission(UsbAccessory accessory, String packageName, 519 PendingIntent pi) { 520 mDeviceManager.requestPermission(accessory, packageName, pi); 521 } 522 523 public void grantDevicePermission(UsbDevice device, int uid) { 524 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 525 mDeviceManager.grantDevicePermission(device, uid); 526 } 527 528 public void grantAccessoryPermission(UsbAccessory accessory, int uid) { 529 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 530 mDeviceManager.grantAccessoryPermission(accessory, uid); 531 } 532 533 public boolean hasDefaults(String packageName) { 534 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 535 return mDeviceManager.hasDefaults(packageName); 536 } 537 538 public void clearDefaults(String packageName) { 539 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 540 mDeviceManager.clearDefaults(packageName); 541 } 542 543 /* 544 * This handler is for deferred handling of events related to device mode and accessories. 545 */ 546 private final Handler mHandler = new Handler() { 547 private void addEnabledFunctionsLocked(Intent intent) { 548 // include state of all USB functions in our extras 549 for (int i = 0; i < mEnabledFunctions.size(); i++) { 550 intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED); 551 } 552 for (int i = 0; i < mDisabledFunctions.size(); i++) { 553 intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED); 554 } 555 } 556 557 @Override 558 public void handleMessage(Message msg) { 559 synchronized (mLock) { 560 switch (msg.what) { 561 case MSG_UPDATE_STATE: 562 if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) { 563 if (mConnected == 0) { 564 // make sure accessory mode is off, and restore default functions 565 if (mCurrentAccessory != null && UsbManager.setFunctionEnabled( 566 UsbManager.USB_FUNCTION_ACCESSORY, false)) { 567 Log.d(TAG, "exited USB accessory mode"); 568 569 int count = mDefaultFunctions.size(); 570 for (int i = 0; i < count; i++) { 571 String function = mDefaultFunctions.get(i); 572 if (!UsbManager.setFunctionEnabled(function, true)) { 573 Log.e(TAG, "could not reenable function " + function); 574 } 575 } 576 577 mDeviceManager.accessoryDetached(mCurrentAccessory); 578 mCurrentAccessory = null; 579 } 580 } 581 582 final ContentResolver cr = mContext.getContentResolver(); 583 if (Settings.Secure.getInt(cr, 584 Settings.Secure.DEVICE_PROVISIONED, 0) == 0) { 585 Slog.i(TAG, "Device not provisioned, skipping USB broadcast"); 586 return; 587 } 588 589 mLastConnected = mConnected; 590 mLastConfiguration = mConfiguration; 591 592 // send a sticky broadcast containing current USB state 593 Intent intent = new Intent(UsbManager.ACTION_USB_STATE); 594 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 595 intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0); 596 intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration); 597 addEnabledFunctionsLocked(intent); 598 mContext.sendStickyBroadcast(intent); 599 } 600 break; 601 case MSG_FUNCTION_ENABLED: 602 case MSG_FUNCTION_DISABLED: 603 functionEnabledLocked((String)msg.obj, msg.what == MSG_FUNCTION_ENABLED); 604 break; 605 } 606 } 607 } 608 }; 609 610 @Override 611 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 612 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 613 != PackageManager.PERMISSION_GRANTED) { 614 pw.println("Permission Denial: can't dump UsbManager from from pid=" 615 + Binder.getCallingPid() 616 + ", uid=" + Binder.getCallingUid()); 617 return; 618 } 619 620 synchronized (mLock) { 621 pw.println("USB Manager State:"); 622 623 pw.println(" USB Device State:"); 624 pw.print(" Enabled Functions: "); 625 for (int i = 0; i < mEnabledFunctions.size(); i++) { 626 pw.print(mEnabledFunctions.get(i) + " "); 627 } 628 pw.println(""); 629 pw.print(" Disabled Functions: "); 630 for (int i = 0; i < mDisabledFunctions.size(); i++) { 631 pw.print(mDisabledFunctions.get(i) + " "); 632 } 633 pw.println(""); 634 pw.print(" Default Functions: "); 635 for (int i = 0; i < mDefaultFunctions.size(); i++) { 636 pw.print(mDefaultFunctions.get(i) + " "); 637 } 638 pw.println(""); 639 pw.println(" mConnected: " + mConnected + ", mConfiguration: " + mConfiguration); 640 pw.println(" mCurrentAccessory: " + mCurrentAccessory); 641 642 pw.println(" USB Host State:"); 643 for (String name : mDevices.keySet()) { 644 pw.println(" " + name + ": " + mDevices.get(name)); 645 } 646 mDeviceManager.dump(fd, pw); 647 } 648 } 649 650 // host support 651 private native void monitorUsbHostBus(); 652 private native ParcelFileDescriptor nativeOpenDevice(String deviceName); 653 // accessory support 654 private native String[] nativeGetAccessoryStrings(); 655 private native ParcelFileDescriptor nativeOpenAccessory(); 656} 657