adb: get libusb compiling on Windows.

This still doesn't work yet because libusb doesn't support hotplug on
Windows yet, but it's in the milestones for the next libusb release,
and this is enough to start poking around with the WinUSB device-side
stuff, so leave it broken for now.

Bug: http://b/68993980
Test: set ADB_LIBUSB=1; adb.exe server nodaemon aborts in the expected place
Change-Id: Icef7d46e31c847d6a8e724c6f58ae5db43673c16
This commit is contained in:
Josh Gao 2017-12-08 13:05:40 -08:00
parent cce381e307
commit 9425996b45
5 changed files with 75 additions and 97 deletions

View File

@ -101,6 +101,8 @@ LIBADB_windows_SRC_FILES := \
sysdeps_win32.cpp \
sysdeps/win32/errno.cpp \
sysdeps/win32/stat.cpp \
client/usb_dispatch.cpp \
client/usb_libusb.cpp \
client/usb_windows.cpp \
LIBADB_TEST_windows_SRCS := \
@ -159,9 +161,7 @@ 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 libmdnssd
LOCAL_STATIC_LIBRARIES_linux := libusb
LOCAL_STATIC_LIBRARIES_darwin := libusb
LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase libmdnssd libusb
LOCAL_C_INCLUDES_windows := development/host/windows/usb/api/
LOCAL_MULTILIB := first
@ -230,9 +230,7 @@ LOCAL_STATIC_LIBRARIES := \
libdiagnose_usb \
libmdnssd \
libgmock_host \
LOCAL_STATIC_LIBRARIES_linux := libusb
LOCAL_STATIC_LIBRARIES_darwin := libusb
libusb \
# Set entrypoint to wmain from sysdeps_win32.cpp instead of main
LOCAL_LDFLAGS_windows := -municode
@ -298,14 +296,12 @@ LOCAL_STATIC_LIBRARIES := \
libdiagnose_usb \
liblog \
libmdnssd \
libusb \
# Don't use libcutils on Windows.
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

View File

@ -41,8 +41,6 @@
#include "transport.h"
#include "usb.h"
using namespace std::literals;
using android::base::StringPrintf;
// RAII wrappers for libusb.
@ -222,7 +220,7 @@ static void process_device(libusb_device* device) {
// Use size_t for interface_num so <iostream>s don't mangle it.
size_t interface_num;
uint16_t zero_mask;
uint16_t zero_mask = 0;
uint8_t bulk_in = 0, bulk_out = 0;
size_t packet_size = 0;
bool found_adb = false;
@ -372,9 +370,9 @@ static void process_device(libusb_device* device) {
#endif
}
auto result =
std::make_unique<usb_handle>(device_address, device_serial, std::move(handle),
interface_num, bulk_in, bulk_out, zero_mask, packet_size);
std::unique_ptr<usb_handle> result(new usb_handle(device_address, device_serial,
std::move(handle), interface_num, bulk_in,
bulk_out, zero_mask, packet_size));
usb_handle* usb_handle_raw = result.get();
{
@ -397,7 +395,7 @@ static void device_connected(libusb_device* device) {
// hack around this by inserting a sleep.
auto thread = std::thread([device]() {
std::string device_path = get_device_dev_path(device);
std::this_thread::sleep_for(1s);
std::this_thread::sleep_for(std::chrono::seconds(1));
process_device(device);
if (--connecting_devices == 0) {
@ -448,8 +446,8 @@ static void hotplug_thread() {
}
}
static int hotplug_callback(libusb_context*, libusb_device* device, libusb_hotplug_event event,
void*) {
static LIBUSB_CALL int hotplug_callback(libusb_context*, libusb_device* device,
libusb_hotplug_event event, void*) {
// We're called with the libusb lock taken. Call these on a separate thread outside of this
// function so that the usb_handle mutex is always taken before the libusb mutex.
static std::once_flag once;
@ -493,59 +491,60 @@ void usb_cleanup() {
libusb_hotplug_deregister_callback(nullptr, hotplug_handle);
}
static LIBUSB_CALL void transfer_callback(libusb_transfer* transfer) {
transfer_info* info = static_cast<transfer_info*>(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<std::mutex> 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;
}
// usb_read() can return when receiving some data.
if (info->is_bulk_out && 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();
}
// 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<std::mutex> device_lock) {
libusb_transfer* transfer = info->transfer;
transfer->user_data = info;
transfer->callback = [](libusb_transfer* transfer) {
transfer_info* info = static_cast<transfer_info*>(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<std::mutex> 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;
}
// usb_read() can return when receiving some data.
if (info->is_bulk_out && 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();
};
transfer->callback = transfer_callback;
LOG(DEBUG) << "locking " << info->name << " transfer_info mutex";
std::unique_lock<std::mutex> lock(info->mutex);

View File

@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <mutex>
#include <thread>
@ -40,6 +41,8 @@
#include "sysdeps/chrono.h"
#include "transport.h"
namespace native {
/** Structure usb_handle describes our connection to the usb device via
AdbWinApi.dll. This structure is returned from usb_open() routine and
is expected in each subsequent call that is accessing the device.
@ -48,13 +51,7 @@
rely on AdbWinApi.dll's handle validation and AdbCloseHandle(endpoint)'s
ability to break a thread out of pipe IO.
*/
struct usb_handle {
/// Previous entry in the list of opened usb handles
usb_handle* prev;
/// Next entry in the list of opened usb handles
usb_handle* next;
struct usb_handle : public ::usb_handle {
/// Handle to USB interface
ADBAPIHANDLE adb_interface;
@ -78,9 +75,7 @@ struct usb_handle {
static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
/// List of opened usb handles
static usb_handle handle_list = {
.prev = &handle_list, .next = &handle_list,
};
static std::vector<usb_handle*> handle_list;
/// Locker for the list of opened usb handles
static std::mutex& usb_lock = *new std::mutex();
@ -131,11 +126,9 @@ void usb_kick(usb_handle* handle);
int usb_close(usb_handle* handle);
int known_device_locked(const wchar_t* dev_name) {
usb_handle* usb;
if (NULL != dev_name) {
// Iterate through the list looking for the name match.
for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
for (usb_handle* usb : handle_list) {
// In Windows names are not case sensetive!
if ((NULL != usb->interface_name) && (0 == wcsicmp(usb->interface_name, dev_name))) {
return 1;
@ -168,10 +161,7 @@ int register_new_device(usb_handle* handle) {
}
// Not in the list. Add this handle to the list.
handle->next = &handle_list;
handle->prev = handle_list.prev;
handle->prev->next = handle;
handle->next->prev = handle;
handle_list.push_back(handle);
return 1;
}
@ -274,10 +264,6 @@ usb_handle* do_usb_open(const wchar_t* interface_name) {
goto fail;
}
// Set linkers back to the handle
ret->next = ret;
ret->prev = ret;
// Create interface.
ret->adb_interface = AdbCreateInterfaceByName(interface_name);
if (NULL == ret->adb_interface) {
@ -484,13 +470,8 @@ int usb_close(usb_handle* handle) {
// Remove handle from the list
{
std::lock_guard<std::mutex> lock(usb_lock);
if ((handle->next != handle) && (handle->prev != handle)) {
handle->next->prev = handle->prev;
handle->prev->next = handle->next;
handle->prev = handle;
handle->next = handle;
}
handle_list.erase(std::remove(handle_list.begin(), handle_list.end(), handle),
handle_list.end());
}
// Cleanup handle
@ -623,7 +604,9 @@ static void kick_devices() {
// Need to acquire lock to safely walk the list which might be modified
// by another thread.
std::lock_guard<std::mutex> lock(usb_lock);
for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
for (usb_handle* usb : handle_list) {
usb_kick_locked(usb);
}
}
} // namespace native

View File

@ -181,7 +181,7 @@ int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol)
}
bool should_use_libusb() {
#if defined(_WIN32) || !ADB_HOST
#if !ADB_HOST
return false;
#else
static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0;

View File

@ -29,8 +29,8 @@
void usb_kick(handle_ref_type h); \
size_t usb_get_max_packet_size(handle_ref_type)
#if defined(_WIN32) || !ADB_HOST
// Windows and the daemon have a single implementation.
#if !ADB_HOST
// The daemon has a single implementation.
struct usb_handle;
ADB_USB_INTERFACE(usb_handle*);