From 1c70e1bcbcced190b351d4fb418f32b4e428f496 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Wed, 28 Sep 2016 12:32:45 -0700 Subject: [PATCH] adb: add libusb implementation for Linux/Darwin. Add a libusb-based implementation alongside the existing native implementations, controlled by the ADB_LIBUSB environment variable. Windows will need more work for the usb driver. Bug: http://b/31321337 Test: python test_device.py on linux/darwin, with ADB_LIBUSB=0 and 1 Change-Id: Ib68fb2c6c05475eae3ff4cc19f55802a6f489bb7 --- adb/Android.mk | 18 +- adb/adb.cpp | 3 +- adb/adb.h | 14 +- adb/client/main.cpp | 7 +- adb/client/usb_dispatch.cpp | 55 ++++ adb/client/usb_libusb.cpp | 519 ++++++++++++++++++++++++++++++++++++ adb/client/usb_linux.cpp | 5 +- adb/transport_usb.cpp | 2 - adb/usb.h | 57 ++++ 9 files changed, 659 insertions(+), 21 deletions(-) create mode 100644 adb/client/usb_dispatch.cpp create mode 100644 adb/client/usb_libusb.cpp create mode 100644 adb/usb.h diff --git a/adb/Android.mk b/adb/Android.mk index 41cb7359c..b444afad1 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -81,10 +81,14 @@ LIBADB_windows_CFLAGS := \ LIBADB_darwin_SRC_FILES := \ sysdeps_unix.cpp \ + client/usb_dispatch.cpp \ + client/usb_libusb.cpp \ client/usb_osx.cpp \ LIBADB_linux_SRC_FILES := \ sysdeps_unix.cpp \ + client/usb_dispatch.cpp \ + client/usb_libusb.cpp \ client/usb_linux.cpp \ LIBADB_windows_SRC_FILES := \ @@ -150,6 +154,8 @@ LOCAL_SANITIZE := $(adb_host_sanitize) # Even though we're building a static library (and thus there's no link step for # this to take effect), this adds the includes to our path. LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase +LOCAL_STATIC_LIBRARIES_linux := libusb +LOCAL_STATIC_LIBRARIES_darwin := libusb LOCAL_C_INCLUDES_windows := development/host/windows/usb/api/ LOCAL_MULTILIB := first @@ -169,7 +175,7 @@ LOCAL_SRC_FILES := \ shell_service_test.cpp \ LOCAL_SANITIZE := $(adb_target_sanitize) -LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils libcrypto +LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils libcrypto libusb LOCAL_SHARED_LIBRARIES := liblog libbase libcutils include $(BUILD_NATIVE_TEST) @@ -219,10 +225,13 @@ LOCAL_STATIC_LIBRARIES := \ libdiagnose_usb \ libgmock_host \ +LOCAL_STATIC_LIBRARIES_linux := libusb +LOCAL_STATIC_LIBRARIES_darwin := libusb + # Set entrypoint to wmain from sysdeps_win32.cpp instead of main LOCAL_LDFLAGS_windows := -municode LOCAL_LDLIBS_linux := -lrt -ldl -lpthread -LOCAL_LDLIBS_darwin := -framework CoreFoundation -framework IOKit +LOCAL_LDLIBS_darwin := -framework CoreFoundation -framework IOKit -lobjc LOCAL_LDLIBS_windows := -lws2_32 -luserenv LOCAL_STATIC_LIBRARIES_windows := AdbWinApi @@ -236,7 +245,7 @@ include $(CLEAR_VARS) LOCAL_LDLIBS_linux := -lrt -ldl -lpthread -LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon +LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon -lobjc # Use wmain instead of main LOCAL_LDFLAGS_windows := -municode @@ -287,6 +296,9 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_STATIC_LIBRARIES_darwin := libcutils LOCAL_STATIC_LIBRARIES_linux := libcutils +LOCAL_STATIC_LIBRARIES_darwin += libusb +LOCAL_STATIC_LIBRARIES_linux += libusb + LOCAL_CXX_STL := libc++_static # Don't add anything here, we don't want additional shared dependencies diff --git a/adb/adb.cpp b/adb/adb.cpp index 3cd50bad4..ece143c63 100644 --- a/adb/adb.cpp +++ b/adb/adb.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -1047,7 +1048,7 @@ int handle_host_request(const char* service, TransportType type, // may not read the OKAY sent above. adb_shutdown(reply_fd); - exit(0); + android::base::quick_exit(0); } #if ADB_HOST diff --git a/adb/adb.h b/adb/adb.h index 7db3b1569..6a38f18e0 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -28,6 +28,7 @@ #include "adb_trace.h" #include "fdevent.h" #include "socket.h" +#include "usb.h" constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024; constexpr size_t MAX_PAYLOAD_V2 = 256 * 1024; @@ -54,7 +55,6 @@ std::string adb_version(); #define ADB_SERVER_VERSION 38 class atransport; -struct usb_handle; struct amessage { uint32_t command; /* command identifier constant */ @@ -195,18 +195,6 @@ void local_init(int port); bool local_connect(int port); int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error); -// USB host/client interface. -void usb_init(); -int usb_write(usb_handle *h, const void *data, int len); -int usb_read(usb_handle *h, void *data, int len); -int usb_close(usb_handle *h); -void usb_kick(usb_handle *h); - -// USB device detection. -#if ADB_HOST -int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol); -#endif - ConnectionState connection_state(atransport *t); extern const char* adb_device_banner; diff --git a/adb/client/main.cpp b/adb/client/main.cpp index d58351659..97a54fd6c 100644 --- a/adb/client/main.cpp +++ b/adb/client/main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "adb.h" @@ -86,7 +87,7 @@ static void setup_daemon_logging(void) { static BOOL WINAPI ctrlc_handler(DWORD type) { // TODO: Consider trying to kill a starting up adb server (if we're in // launch_server) by calling GenerateConsoleCtrlEvent(). - exit(STATUS_CONTROL_C_EXIT); + android::base::quick_exit(STATUS_CONTROL_C_EXIT); return TRUE; } #endif @@ -108,6 +109,10 @@ int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply } SetConsoleCtrlHandler(ctrlc_handler, TRUE); +#else + signal(SIGINT, [](int) { + android::base::quick_exit(0); + }); #endif init_transport_registration(); diff --git a/adb/client/usb_dispatch.cpp b/adb/client/usb_dispatch.cpp new file mode 100644 index 000000000..597e66e8e --- /dev/null +++ b/adb/client/usb_dispatch.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "usb.h" + +static bool should_use_libusb() { + static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0; + return enable; +} + +void usb_init() { + if (should_use_libusb()) { + LOG(INFO) << "using libusb backend"; + libusb::usb_init(); + } else { + LOG(INFO) << "using native backend"; + native::usb_init(); + } +} + +int usb_write(usb_handle* h, const void* data, int len) { + return should_use_libusb() + ? libusb::usb_write(reinterpret_cast(h), data, len) + : native::usb_write(reinterpret_cast(h), data, len); +} + +int usb_read(usb_handle* h, void* data, int len) { + return should_use_libusb() + ? libusb::usb_read(reinterpret_cast(h), data, len) + : native::usb_read(reinterpret_cast(h), data, len); +} + +int usb_close(usb_handle* h) { + return should_use_libusb() ? libusb::usb_close(reinterpret_cast(h)) + : native::usb_close(reinterpret_cast(h)); +} + +void usb_kick(usb_handle* h) { + should_use_libusb() ? libusb::usb_kick(reinterpret_cast(h)) + : native::usb_kick(reinterpret_cast(h)); +} diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp new file mode 100644 index 000000000..7adb26213 --- /dev/null +++ b/adb/client/usb_libusb.cpp @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "usb.h" + +#include "sysdeps.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "adb.h" +#include "transport.h" +#include "usb.h" + +using namespace std::literals; + +using android::base::StringPrintf; + +// RAII wrappers for libusb. +struct ConfigDescriptorDeleter { + void operator()(libusb_config_descriptor* desc) { + libusb_free_config_descriptor(desc); + } +}; + +using unique_config_descriptor = std::unique_ptr; + +struct DeviceHandleDeleter { + void operator()(libusb_device_handle* h) { + libusb_close(h); + } +}; + +using unique_device_handle = std::unique_ptr; + +struct transfer_info { + transfer_info(const char* name, uint16_t zero_mask) : + name(name), + transfer(libusb_alloc_transfer(0)), + zero_mask(zero_mask) + { + } + + ~transfer_info() { + libusb_free_transfer(transfer); + } + + const char* name; + libusb_transfer* transfer; + bool transfer_complete; + std::condition_variable cv; + std::mutex mutex; + uint16_t zero_mask; + + void Notify() { + LOG(DEBUG) << "notifying " << name << " transfer complete"; + transfer_complete = true; + cv.notify_one(); + } +}; + +namespace libusb { +struct usb_handle : public ::usb_handle { + usb_handle(const std::string& device_address, const std::string& serial, + unique_device_handle&& device_handle, uint8_t interface, uint8_t bulk_in, + uint8_t bulk_out, size_t zero_mask) + : device_address(device_address), + serial(serial), + closing(false), + device_handle(device_handle.release()), + read("read", zero_mask), + write("write", zero_mask), + interface(interface), + bulk_in(bulk_in), + bulk_out(bulk_out) { + } + + ~usb_handle() { + Close(); + } + + void Close() { + std::unique_lock lock(device_handle_mutex); + // Cancelling transfers will trigger more Closes, so make sure this only happens once. + if (closing) { + return; + } + closing = true; + + // Make sure that no new transfers come in. + libusb_device_handle* handle = device_handle; + if (!handle) { + return; + } + + device_handle = nullptr; + + // Cancel already dispatched transfers. + libusb_cancel_transfer(read.transfer); + libusb_cancel_transfer(write.transfer); + + libusb_release_interface(handle, interface); + libusb_close(handle); + } + + std::string device_address; + std::string serial; + + std::atomic closing; + std::mutex device_handle_mutex; + libusb_device_handle* device_handle; + + transfer_info read; + transfer_info write; + + uint8_t interface; + uint8_t bulk_in; + uint8_t bulk_out; +}; + +static auto& usb_handles = *new std::unordered_map>(); +static auto& usb_handles_mutex = *new std::mutex(); + +static std::thread* device_poll_thread = nullptr; +static std::atomic terminate_device_poll_thread(false); + +static std::string get_device_address(libusb_device* device) { + return StringPrintf("usb:%d:%d", libusb_get_bus_number(device), + libusb_get_device_address(device)); +} + +static bool endpoint_is_output(uint8_t endpoint) { + return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT; +} + +static bool should_perform_zero_transfer(uint8_t endpoint, size_t write_length, uint16_t zero_mask) { + return endpoint_is_output(endpoint) && write_length != 0 && zero_mask != 0 && + (write_length & zero_mask) == 0; +} + +static void poll_for_devices() { + libusb_device** list; + adb_thread_setname("device poll"); + while (!terminate_device_poll_thread) { + const ssize_t device_count = libusb_get_device_list(nullptr, &list); + + LOG(VERBOSE) << "found " << device_count << " attached devices"; + + for (ssize_t i = 0; i < device_count; ++i) { + libusb_device* device = list[i]; + std::string device_address = get_device_address(device); + std::string device_serial; + + // Figure out if we want to open the device. + libusb_device_descriptor device_desc; + int rc = libusb_get_device_descriptor(device, &device_desc); + if (rc != 0) { + LOG(WARNING) << "failed to get device descriptor for device at " << device_address + << ": " << libusb_error_name(rc); + } + + if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) { + // Assume that all Android devices have the device class set to per interface. + // TODO: Is this assumption valid? + LOG(VERBOSE) << "skipping device with incorrect class at " << device_address; + continue; + } + + libusb_config_descriptor* config_raw; + rc = libusb_get_active_config_descriptor(device, &config_raw); + if (rc != 0) { + LOG(WARNING) << "failed to get active config descriptor for device at " + << device_address << ": " << libusb_error_name(rc); + continue; + } + const unique_config_descriptor config(config_raw); + + // Use size_t for interface_num so s don't mangle it. + size_t interface_num; + uint16_t zero_mask; + uint8_t bulk_in = 0, bulk_out = 0; + bool found_adb = false; + + for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) { + const libusb_interface& interface = config->interface[interface_num]; + if (interface.num_altsetting != 1) { + // Assume that interfaces with alternate settings aren't adb interfaces. + // TODO: Is this assumption valid? + LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " + << device_address << " (interface " << interface_num << ")"; + continue; + } + + const libusb_interface_descriptor& interface_desc = interface.altsetting[0]; + if (!is_adb_interface(interface_desc.bInterfaceClass, + interface_desc.bInterfaceSubClass, + interface_desc.bInterfaceProtocol)) { + LOG(VERBOSE) << "skipping non-adb interface at " << device_address + << " (interface " << interface_num << ")"; + continue; + } + + LOG(VERBOSE) << "found potential adb interface at " << device_address + << " (interface " << interface_num << ")"; + + bool found_in = false; + bool found_out = false; + for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints; + ++endpoint_num) { + const auto& endpoint_desc = interface_desc.endpoint[endpoint_num]; + const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress; + const uint8_t endpoint_attr = endpoint_desc.bmAttributes; + + const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK; + + if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) { + continue; + } + + if (endpoint_is_output(endpoint_addr) && !found_out) { + found_out = true; + bulk_out = endpoint_addr; + zero_mask = endpoint_desc.wMaxPacketSize - 1; + } else if (!endpoint_is_output(endpoint_addr) && !found_in) { + found_in = true; + bulk_in = endpoint_addr; + } + } + + if (found_in && found_out) { + found_adb = true; + break; + } else { + LOG(VERBOSE) << "rejecting potential adb interface at " << device_address + << "(interface " << interface_num << "): missing bulk endpoints " + << "(found_in = " << found_in << ", found_out = " << found_out + << ")"; + } + } + + if (!found_adb) { + LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address; + continue; + } + + { + std::unique_lock lock(usb_handles_mutex); + if (usb_handles.find(device_address) != usb_handles.end()) { + LOG(VERBOSE) << "device at " << device_address + << " has already been registered, skipping"; + continue; + } + } + + libusb_device_handle* handle_raw; + rc = libusb_open(list[i], &handle_raw); + if (rc != 0) { + LOG(WARNING) << "failed to open usb device at " << device_address << ": " + << libusb_error_name(rc); + continue; + } + + unique_device_handle handle(handle_raw); + LOG(DEBUG) << "successfully opened adb device at " << device_address << ", " + << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out); + + device_serial.resize(255); + rc = libusb_get_string_descriptor_ascii( + handle_raw, device_desc.iSerialNumber, + reinterpret_cast(&device_serial[0]), device_serial.length()); + if (rc == 0) { + LOG(WARNING) << "received empty serial from device at " << device_address; + continue; + } else if (rc < 0) { + LOG(WARNING) << "failed to get serial from device at " << device_address + << libusb_error_name(rc); + continue; + } + device_serial.resize(rc); + + // Try to reset the device. + rc = libusb_reset_device(handle_raw); + if (rc != 0) { + LOG(WARNING) << "failed to reset opened device '" << device_serial + << "': " << libusb_error_name(rc); + continue; + } + + // WARNING: this isn't released via RAII. + rc = libusb_claim_interface(handle.get(), interface_num); + if (rc != 0) { + LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'" + << libusb_error_name(rc); + continue; + } + + for (uint8_t endpoint : {bulk_in, bulk_out}) { + rc = libusb_clear_halt(handle.get(), endpoint); + if (rc != 0) { + LOG(WARNING) << "failed to clear halt on device '" << device_serial + << "' endpoint 0x" << std::hex << endpoint << ": " + << libusb_error_name(rc); + libusb_release_interface(handle.get(), interface_num); + continue; + } + } + + auto result = + std::make_unique(device_address, device_serial, std::move(handle), + interface_num, bulk_in, bulk_out, zero_mask); + usb_handle* usb_handle_raw = result.get(); + + { + std::unique_lock lock(usb_handles_mutex); + usb_handles[device_address] = std::move(result); + } + + register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), 1); + + LOG(INFO) << "registered new usb device '" << device_serial << "'"; + } + libusb_free_device_list(list, 1); + + std::this_thread::sleep_for(500ms); + } +} + +void usb_init() { + LOG(DEBUG) << "initializing libusb..."; + int rc = libusb_init(nullptr); + if (rc != 0) { + LOG(FATAL) << "failed to initialize libusb: " << libusb_error_name(rc); + } + + // Spawn a thread for libusb_handle_events. + std::thread([]() { + adb_thread_setname("libusb"); + while (true) { + libusb_handle_events(nullptr); + } + }).detach(); + + // Spawn a thread to do device enumeration. + // TODO: Use libusb_hotplug_* instead? + device_poll_thread = new std::thread(poll_for_devices); + android::base::at_quick_exit([]() { + terminate_device_poll_thread = true; + std::unique_lock lock(usb_handles_mutex); + for (auto& it : usb_handles) { + it.second->Close(); + } + lock.unlock(); + device_poll_thread->join(); + }); +} + +// Dispatch a libusb transfer, unlock |device_lock|, and then wait for the result. +static int perform_usb_transfer(usb_handle* h, transfer_info* info, + std::unique_lock device_lock) { + libusb_transfer* transfer = info->transfer; + + transfer->user_data = info; + transfer->callback = [](libusb_transfer* transfer) { + transfer_info* info = static_cast(transfer->user_data); + + LOG(DEBUG) << info->name << " transfer callback entered"; + + // Make sure that the original submitter has made it to the condition_variable wait. + std::unique_lock lock(info->mutex); + + LOG(DEBUG) << info->name << " callback successfully acquired lock"; + + if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { + LOG(WARNING) << info->name + << " transfer failed: " << libusb_error_name(transfer->status); + info->Notify(); + return; + } + + if (transfer->actual_length != transfer->length) { + LOG(DEBUG) << info->name << " transfer incomplete, resubmitting"; + transfer->length -= transfer->actual_length; + transfer->buffer += transfer->actual_length; + int rc = libusb_submit_transfer(transfer); + if (rc != 0) { + LOG(WARNING) << "failed to submit " << info->name + << " transfer: " << libusb_error_name(rc); + transfer->status = LIBUSB_TRANSFER_ERROR; + info->Notify(); + } + return; + } + + if (should_perform_zero_transfer(transfer->endpoint, transfer->length, info->zero_mask)) { + LOG(DEBUG) << "submitting zero-length write"; + transfer->length = 0; + int rc = libusb_submit_transfer(transfer); + if (rc != 0) { + LOG(WARNING) << "failed to submit zero-length write: " << libusb_error_name(rc); + transfer->status = LIBUSB_TRANSFER_ERROR; + info->Notify(); + } + return; + } + + LOG(VERBOSE) << info->name << "transfer fully complete"; + info->Notify(); + }; + + LOG(DEBUG) << "locking " << info->name << " transfer_info mutex"; + std::unique_lock lock(info->mutex); + info->transfer_complete = false; + LOG(DEBUG) << "submitting " << info->name << " transfer"; + int rc = libusb_submit_transfer(transfer); + if (rc != 0) { + LOG(WARNING) << "failed to submit " << info->name << " transfer: " << libusb_error_name(rc); + errno = EIO; + return -1; + } + + LOG(DEBUG) << info->name << " transfer successfully submitted"; + device_lock.unlock(); + info->cv.wait(lock, [info]() { return info->transfer_complete; }); + if (transfer->status != 0) { + errno = EIO; + return -1; + } + + return 0; +} + +int usb_write(usb_handle* h, const void* d, int len) { + LOG(DEBUG) << "usb_write of length " << len; + + std::unique_lock lock(h->device_handle_mutex); + if (!h->device_handle) { + errno = EIO; + return -1; + } + + transfer_info* info = &h->write; + info->transfer->dev_handle = h->device_handle; + info->transfer->flags = 0; + info->transfer->endpoint = h->bulk_out; + info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; + info->transfer->length = len; + info->transfer->buffer = reinterpret_cast(const_cast(d)); + info->transfer->num_iso_packets = 0; + + int rc = perform_usb_transfer(h, info, std::move(lock)); + LOG(DEBUG) << "usb_write(" << len << ") = " << rc; + return rc; +} + +int usb_read(usb_handle* h, void* d, int len) { + LOG(DEBUG) << "usb_read of length " << len; + + std::unique_lock lock(h->device_handle_mutex); + if (!h->device_handle) { + errno = EIO; + return -1; + } + + transfer_info* info = &h->read; + info->transfer->dev_handle = h->device_handle; + info->transfer->flags = 0; + info->transfer->endpoint = h->bulk_in; + info->transfer->type = LIBUSB_TRANSFER_TYPE_BULK; + info->transfer->length = len; + info->transfer->buffer = reinterpret_cast(d); + info->transfer->num_iso_packets = 0; + + int rc = perform_usb_transfer(h, info, std::move(lock)); + LOG(DEBUG) << "usb_read(" << len << ") = " << rc; + return rc; +} + +int usb_close(usb_handle* h) { + std::unique_lock lock(usb_handles_mutex); + auto it = usb_handles.find(h->device_address); + if (it == usb_handles.end()) { + LOG(FATAL) << "attempted to close unregistered usb_handle for '" << h->serial << "'"; + } + usb_handles.erase(h->device_address); + return 0; +} + +void usb_kick(usb_handle* h) { + h->Close(); +} +} // namespace libusb diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp index e7f1338b3..13b7674fc 100644 --- a/adb/client/usb_linux.cpp +++ b/adb/client/usb_linux.cpp @@ -46,6 +46,7 @@ #include "adb.h" #include "transport.h" +#include "usb.h" using namespace std::chrono_literals; using namespace std::literals; @@ -53,7 +54,8 @@ using namespace std::literals; /* usb scan debugging is waaaay too verbose */ #define DBGX(x...) -struct usb_handle { +namespace native { +struct usb_handle : public ::usb_handle { ~usb_handle() { if (fd != -1) unix_close(fd); } @@ -595,3 +597,4 @@ void usb_init() { fatal_errno("cannot create device_poll thread"); } } +} // namespace native diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp index d054601ec..3d6cc9974 100644 --- a/adb/transport_usb.cpp +++ b/adb/transport_usb.cpp @@ -93,9 +93,7 @@ void init_usb_transport(atransport *t, usb_handle *h, ConnectionState state) t->usb = h; } -#if ADB_HOST int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol) { return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL); } -#endif diff --git a/adb/usb.h b/adb/usb.h new file mode 100644 index 000000000..879bacc88 --- /dev/null +++ b/adb/usb.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// USB host/client interface. + +#define ADB_USB_INTERFACE(handle_ref_type) \ + void usb_init(); \ + int usb_write(handle_ref_type h, const void* data, int len); \ + int usb_read(handle_ref_type h, void* data, int len); \ + int usb_close(handle_ref_type h); \ + void usb_kick(handle_ref_type h) + +#if defined(_WIN32) || !ADB_HOST +// Windows and the daemon have a single implementation. + +struct usb_handle; +ADB_USB_INTERFACE(usb_handle*); + +#else // linux host || darwin +// Linux and Darwin clients have native and libusb implementations. + +namespace libusb { + struct usb_handle; + ADB_USB_INTERFACE(libusb::usb_handle*); +} + +namespace native { + struct usb_handle; + ADB_USB_INTERFACE(native::usb_handle*); +} + +// Empty base that both implementations' opaque handles inherit from. +struct usb_handle { +}; + +ADB_USB_INTERFACE(::usb_handle*); + +#endif // linux host || darwin + + +// USB device detection. +int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol);