am 944f23ec: Merge "AdbWinUsbApi.dll: fix race condition crash in WinUsb.dll"
* commit '944f23ec76229a474182cfdb7f6cea2330a8a5a9': AdbWinUsbApi.dll: fix race condition crash in WinUsb.dll
This commit is contained in:
5
host/windows/.gitignore
vendored
5
host/windows/.gitignore
vendored
@@ -6,7 +6,10 @@ usb/Debug
|
||||
usb/Release
|
||||
usb/api/obj*
|
||||
usb/api/*.log
|
||||
usb/api/*.wrn
|
||||
usb/adb_winapi_test/obj*
|
||||
usb/adb_winapi_test/*.log
|
||||
usb/adb_winapi_test/*.wrn
|
||||
usb/winusb/obj*
|
||||
usb/winusb/*.log
|
||||
usb/winusb/*.log
|
||||
usb/winusb/*.wrn
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
LIBRARY AdbWinApi.dll
|
||||
EXPORTS
|
||||
AdbEnumInterfaces
|
||||
AdbNextInterface
|
||||
AdbCreateInterfaceByName
|
||||
AdbOpenDefaultBulkReadEndpoint
|
||||
AdbOpenDefaultBulkWriteEndpoint
|
||||
AdbCloseHandle
|
||||
AdbGetInterfaceName
|
||||
AdbWriteEndpointSync
|
||||
AdbReadEndpointSync
|
||||
AdbGetSerialNumber
|
||||
AdbGetUsbInterfaceDescriptor
|
||||
AdbGetUsbDeviceDescriptor
|
||||
AdbGetEndpointInformation
|
||||
Binary file not shown.
BIN
host/windows/prebuilt/usb/AdbWinApi.pdb
Executable file
BIN
host/windows/prebuilt/usb/AdbWinApi.pdb
Executable file
Binary file not shown.
Binary file not shown.
BIN
host/windows/prebuilt/usb/AdbWinUsbApi.pdb
Executable file
BIN
host/windows/prebuilt/usb/AdbWinUsbApi.pdb
Executable file
Binary file not shown.
@@ -12,8 +12,31 @@ 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.
|
||||
|
||||
In order to build adb_winapi_test.dll you will need to install Windows Driver
|
||||
Kit, which can be obtained from Microsoft. Assuming that WDK is installed, you
|
||||
need to set one of the WDK's build environments, "cd" back into this directory,
|
||||
and execute "build -cbeEIFZ" to clean and rebuild this project, or you can
|
||||
execute "build -befEIF" to do a minimal build.
|
||||
In order to build a directory with a SOURCES file you will need to install
|
||||
the Windows Driver Kit, which can be obtained from Microsoft:
|
||||
|
||||
Windows Driver Kit Version 7.1.0
|
||||
https://www.microsoft.com/en-us/download/details.aspx?id=11800
|
||||
md5: 8fe981a1706d43ad34bda496e6558f94
|
||||
sha1: de6abdb8eb4e08942add4aa270c763ed4e3d8242
|
||||
|
||||
This old version is used because it can build for Windows Vista (WDK 8.1
|
||||
cannot), it includes compilers (so it doesn't require Visual Studio), and it is
|
||||
probably not too far from the WDK that this code was originally built with, so
|
||||
it should be less risky.
|
||||
|
||||
When installing the WDK, uncheck `Device Simulation Framework' because it is
|
||||
unnecessary and it installs a kernel-mode driver that we don't need.
|
||||
|
||||
Assuming that WDK is installed, you need to set one of the WDK's build
|
||||
environments (Start Menu -> Windows Driver Kits -> x86 Free Build Environment;
|
||||
choose the one for the oldest version of Windows you want to support),
|
||||
"cd" back into this directory, and execute "build -cbeEIFZ" to clean and rebuild
|
||||
this project, or you can execute "build -befEIF" to do a minimal build.
|
||||
|
||||
Note that you need to build AdbWinApi.dll (..\api) before you build
|
||||
this directory, as this depends on the AdbWinApi.lib import library.
|
||||
|
||||
When you're done with the WDK build environment, don't forget to right-click the
|
||||
OACR icon (in the lower-right notification area of the taskbar) and choose
|
||||
`Close'.
|
||||
|
||||
@@ -18,12 +18,17 @@ TARGETNAME = adb_winapi_test
|
||||
TARGETPATH = obj
|
||||
TARGETTYPE = PROGRAM
|
||||
|
||||
_NT_TARGET_VERSION = $(_NT_TARGET_VERSION_VISTA)
|
||||
|
||||
UMTYPE = console
|
||||
UMENTRY = main
|
||||
|
||||
# Use statically linked atl libraries:
|
||||
USE_STATIC_ATL = 1
|
||||
|
||||
# Use STL, default version
|
||||
USE_STL = 1
|
||||
|
||||
# Use multithreaded libraries
|
||||
USE_LIBCMT = 1
|
||||
|
||||
@@ -34,13 +39,19 @@ TARGETLIBS=$(SDK_LIB_PATH)\ole32.lib \
|
||||
INCLUDES=$(DDK_INC_PATH)\;$(SDK_INC_PATH)\;$(CRT_INC_PATH)\;$(ATL_INC_PATH)\api
|
||||
|
||||
# Common C defines
|
||||
USER_C_FLAGS = $(USER_C_FLAGS) /FD /wd4100 /nologo
|
||||
USER_C_FLAGS = $(USER_C_FLAGS) /FD /wd4100 /nologo
|
||||
|
||||
# The STL uses C++ exception handling.
|
||||
USE_NATIVE_EH=1
|
||||
|
||||
# Turn on all warnings, and treat warnings as errors
|
||||
MSC_WARNING_LEVEL = /W4 /Wp64 /WX
|
||||
MSC_WARNING_LEVEL = /W4 /WX
|
||||
|
||||
PRECOMPILED_CXX = 1
|
||||
PRECOMPILED_INCLUDE = stdafx.h
|
||||
PRECOMPILED_SOURCEFILE = stdafx.cpp
|
||||
# Disable precompiled header to work-around compiler issue with interaction with
|
||||
# ASLR on Windows 7 and newer.
|
||||
# http://blogs.msdn.com/b/vcblog/archive/2009/11/12/visual-c-precompiled-header-errors-on-windows-7.aspx
|
||||
#PRECOMPILED_CXX = 1
|
||||
#PRECOMPILED_INCLUDE = stdafx.h
|
||||
#PRECOMPILED_SOURCEFILE = stdafx.cpp
|
||||
|
||||
SOURCES = adb_winapi_test.cpp
|
||||
|
||||
@@ -33,24 +33,35 @@ const GUID kAdbInterfaceId = ANDROID_USB_CLASS_ID;
|
||||
int interface_count = 0;
|
||||
|
||||
// Constants used to initialize a "handshake" message
|
||||
#define MAX_PAYLOAD 4096
|
||||
#define A_SYNC 0x434e5953
|
||||
#define A_CNXN 0x4e584e43
|
||||
#define A_OPEN 0x4e45504f
|
||||
#define A_OKAY 0x59414b4f
|
||||
#define A_CLSE 0x45534c43
|
||||
#define A_WRTE 0x45545257
|
||||
#define A_VERSION 0x01000000
|
||||
#define MAX_PAYLOAD 4096
|
||||
#define A_SYNC 0x434e5953
|
||||
#define A_CNXN 0x4e584e43
|
||||
#define A_OPEN 0x4e45504f
|
||||
#define A_OKAY 0x59414b4f
|
||||
#define A_CLSE 0x45534c43
|
||||
#define A_WRTE 0x45545257
|
||||
#define A_AUTH 0x48545541
|
||||
#define A_VERSION 0x01000000
|
||||
|
||||
// AUTH packets first argument
|
||||
#define ADB_AUTH_TOKEN 1
|
||||
#define ADB_AUTH_SIGNATURE 2
|
||||
#define ADB_AUTH_RSAPUBLICKEY 3
|
||||
|
||||
// Interface descriptor constants for ADB interface
|
||||
#define ADB_CLASS 0xff
|
||||
#define ADB_SUBCLASS 0x42
|
||||
#define ADB_PROTOCOL 0x1
|
||||
|
||||
// Formats message sent to USB device
|
||||
struct message {
|
||||
unsigned int command; /* command identifier constant */
|
||||
unsigned int arg0; /* first argument */
|
||||
unsigned int arg1; /* second argument */
|
||||
unsigned int data_length; /* length of payload (0 is allowed) */
|
||||
unsigned int data_crc32; /* crc32 of data payload */
|
||||
unsigned int magic; /* command ^ 0xffffffff */
|
||||
};
|
||||
struct message {
|
||||
unsigned int command; /* command identifier constant */
|
||||
unsigned int arg0; /* first argument */
|
||||
unsigned int arg1; /* second argument */
|
||||
unsigned int data_length; /* length of payload (0 is allowed) */
|
||||
unsigned int data_crc32; /* crc32 of data payload */
|
||||
unsigned int magic; /* command ^ 0xffffffff */
|
||||
};
|
||||
|
||||
//
|
||||
// Test routines declarations.
|
||||
@@ -69,7 +80,11 @@ bool TestInterface(const wchar_t* device_name);
|
||||
bool TestInterfaceHandle(ADBAPIHANDLE interface_handle);
|
||||
|
||||
// Sends a "handshake" message to the given interface.
|
||||
bool DeviceHandShake(ADBAPIHANDLE adb_interface);
|
||||
bool DeviceHandShake(ADBAPIHANDLE adb_interface);
|
||||
|
||||
// Test AdbCloseHandle race condition.
|
||||
bool TestCloseRaceCondition();
|
||||
|
||||
int __cdecl _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {
|
||||
// Test enum interfaces.
|
||||
if (!TestEnumInterfaces())
|
||||
@@ -85,6 +100,10 @@ int __cdecl _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {
|
||||
if (!TestInterfaces())
|
||||
return -2;
|
||||
|
||||
// Test for AdbCloseHandle race condition
|
||||
if (!TestCloseRaceCondition())
|
||||
return -3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -119,52 +138,60 @@ bool TestEnumInterfaces() {
|
||||
if (interface_info.flags & SPINT_REMOVED)
|
||||
printf(" REMOVED");
|
||||
|
||||
|
||||
buf_size = sizeof(buf);;
|
||||
buf_size = sizeof(buf);
|
||||
}
|
||||
|
||||
|
||||
AdbCloseHandle(enum_handle);
|
||||
bool ret = true;
|
||||
if (GetLastError() != ERROR_NO_MORE_ITEMS) {
|
||||
printf("\n--- AdbNextInterface failure %u", GetLastError());
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if (!AdbCloseHandle(enum_handle)) {
|
||||
printf("\n--- AdbCloseHandle failure %u", GetLastError());
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool TestInterfaces() {
|
||||
bool ret = true;
|
||||
|
||||
// Enumerate interfaces
|
||||
ADBAPIHANDLE enum_handle =
|
||||
AdbEnumInterfaces(kAdbInterfaceId, true, true, true);
|
||||
if (NULL == enum_handle) {
|
||||
printf("\nTest interfaces failure:");
|
||||
printf("\nUnable to enumerate ADB interfaces: %u", GetLastError());
|
||||
printf("\nUnable to enumerate ADB interfaces: %u", GetLastError());
|
||||
ret = false;
|
||||
} else {
|
||||
// Unite interface info structure and buffer big enough to contain the
|
||||
// largest structure.
|
||||
union {
|
||||
AdbInterfaceInfo interface_info;
|
||||
char buf[4096];
|
||||
};
|
||||
unsigned long buf_size = sizeof(buf);
|
||||
|
||||
// Test each found interface
|
||||
while (AdbNextInterface(enum_handle, &interface_info, &buf_size)) {
|
||||
TestInterface(interface_info.device_name);
|
||||
buf_size = sizeof(buf);
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_NO_MORE_ITEMS) {
|
||||
printf("\n--- AdbNextInterface failure %u", GetLastError());
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if (!AdbCloseHandle(enum_handle)) {
|
||||
printf("\n--- AdbCloseHandle failure %u", GetLastError());
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Unite interface info structure and buffer big enough to contain the
|
||||
// largest structure.
|
||||
union {
|
||||
AdbInterfaceInfo interface_info;
|
||||
char buf[4096];
|
||||
};
|
||||
unsigned long buf_size = sizeof(buf);
|
||||
|
||||
// Test each found interface
|
||||
while (AdbNextInterface(enum_handle, &interface_info, &buf_size)) {
|
||||
TestInterface(interface_info.device_name);
|
||||
buf_size = sizeof(buf);
|
||||
};
|
||||
|
||||
AdbCloseHandle(enum_handle);
|
||||
|
||||
// Create interface by VID/PID/MI
|
||||
ADBAPIHANDLE interface_handle =
|
||||
AdbCreateInterface(kAdbInterfaceId, DEVICE_VENDOR_ID,
|
||||
DEVICE_COMPOSITE_PRODUCT_ID, DEVICE_INTERFACE_ID);
|
||||
if (NULL == interface_handle) {
|
||||
printf("\nUnable to create interface by VID/PID: %u", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test it
|
||||
TestInterfaceHandle(interface_handle);
|
||||
AdbCloseHandle(interface_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool TestInterface(const wchar_t* device_name) {
|
||||
@@ -179,18 +206,98 @@ bool TestInterface(const wchar_t* device_name) {
|
||||
|
||||
// Test it
|
||||
TestInterfaceHandle(interface_handle);
|
||||
TestInterfaceHandle(interface_handle);
|
||||
if (!AdbCloseHandle(interface_handle)) {
|
||||
printf("\n--- AdbCloseHandle failure %u", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestInterfaceName(ADBAPIHANDLE interface_handle) {
|
||||
bool ret = true;
|
||||
unsigned long intr_name_size = 0;
|
||||
char* buf = NULL;
|
||||
|
||||
if (AdbGetInterfaceName(interface_handle, NULL, &intr_name_size, true)) {
|
||||
printf("\n--- AdbGetInterfaceName unexpectedly succeeded %u",
|
||||
GetLastError());
|
||||
ret = false;
|
||||
goto exit;
|
||||
}
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
printf("\n--- AdbGetInterfaceName failure %u", GetLastError());
|
||||
ret = false;
|
||||
goto exit;
|
||||
}
|
||||
if (intr_name_size == 0) {
|
||||
printf("\n--- AdbGetInterfaceName returned name size of zero");
|
||||
ret = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
const size_t buf_size = intr_name_size + 16; // extra in case of overwrite
|
||||
buf = reinterpret_cast<char*>(malloc(buf_size));
|
||||
if (buf == NULL) {
|
||||
printf("\n--- could not malloc %d bytes, errno %u", buf_size, errno);
|
||||
ret = false;
|
||||
goto exit;
|
||||
}
|
||||
const char buf_fill = (unsigned char)0xFF;
|
||||
memset(buf, buf_fill, buf_size);
|
||||
|
||||
if (!AdbGetInterfaceName(interface_handle, buf, &intr_name_size, true)) {
|
||||
printf("\n--- AdbGetInterfaceName failure %u", GetLastError());
|
||||
ret = false;
|
||||
goto exit;
|
||||
}
|
||||
if (buf[intr_name_size - 1] != '\0') {
|
||||
printf("\n--- AdbGetInterfaceName returned non-NULL terminated string");
|
||||
ret = false;
|
||||
goto exit;
|
||||
}
|
||||
for (size_t i = intr_name_size; i < buf_size; ++i) {
|
||||
if (buf[i] != buf_fill) {
|
||||
printf("\n--- AdbGetInterfaceName overwrote past the end of the buffer at"
|
||||
" index %u with 0x%02X", i, (unsigned char)buf[i]);
|
||||
ret = false;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n+++ Interface name %s", buf);
|
||||
|
||||
exit:
|
||||
free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DumpEndpointInformation(const AdbEndpointInformation* pipe_info) {
|
||||
printf("\n max_packet_size = %u", pipe_info->max_packet_size);
|
||||
printf("\n max_transfer_size = %u", pipe_info->max_transfer_size);
|
||||
printf("\n endpoint_type = %u", pipe_info->endpoint_type);
|
||||
const char* endpoint_type_desc = NULL;
|
||||
switch (pipe_info->endpoint_type) {
|
||||
#define CASE_TYPE(type) case type: endpoint_type_desc = #type; break
|
||||
CASE_TYPE(AdbEndpointTypeInvalid);
|
||||
CASE_TYPE(AdbEndpointTypeControl);
|
||||
CASE_TYPE(AdbEndpointTypeIsochronous);
|
||||
CASE_TYPE(AdbEndpointTypeBulk);
|
||||
CASE_TYPE(AdbEndpointTypeInterrupt);
|
||||
#undef CASE_TYPE
|
||||
}
|
||||
if (endpoint_type_desc != NULL) {
|
||||
printf(" (%s)", endpoint_type_desc);
|
||||
}
|
||||
printf("\n endpoint_address = %02X", pipe_info->endpoint_address);
|
||||
printf("\n polling_interval = %u", pipe_info->polling_interval);
|
||||
printf("\n setting_index = %u", pipe_info->setting_index);
|
||||
}
|
||||
|
||||
bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
|
||||
// Get interface name.
|
||||
// Get interface name.
|
||||
char intr_name[4096];
|
||||
unsigned long intr_name_size = sizeof(intr_name);
|
||||
if (AdbGetInterfaceName(interface_handle, intr_name, &intr_name_size, true)) {
|
||||
printf("\n+++ Interface name %s", intr_name);
|
||||
} else {
|
||||
if (!TestInterfaceName(interface_handle)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -211,7 +318,7 @@ bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
|
||||
printf("\n iManufacturer = %u", dev_desc.iManufacturer);
|
||||
printf("\n iProduct = %u", dev_desc.iProduct);
|
||||
printf("\n iSerialNumber = %u", dev_desc.iSerialNumber);
|
||||
printf("\n iSerialNumber = %u", dev_desc.iSerialNumber);
|
||||
printf("\n bNumConfigurations = %u", dev_desc.bNumConfigurations);
|
||||
} else {
|
||||
printf("\n--- AdbGetUsbDeviceDescriptor failure %u", GetLastError());
|
||||
return false;
|
||||
@@ -253,8 +360,17 @@ bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
|
||||
printf("\n bAlternateSetting = %u", intr_desc.bAlternateSetting);
|
||||
printf("\n bNumEndpoints = %u", intr_desc.bNumEndpoints);
|
||||
printf("\n bInterfaceClass = %u", intr_desc.bInterfaceClass);
|
||||
if (intr_desc.bInterfaceClass == ADB_CLASS) {
|
||||
printf(" (ADB_CLASS)");
|
||||
}
|
||||
printf("\n bInterfaceSubClass = %u", intr_desc.bInterfaceSubClass);
|
||||
if (intr_desc.bInterfaceSubClass == ADB_SUBCLASS) {
|
||||
printf(" (ADB_SUBCLASS)");
|
||||
}
|
||||
printf("\n bInterfaceProtocol = %u", intr_desc.bInterfaceProtocol);
|
||||
if (intr_desc.bInterfaceProtocol == ADB_PROTOCOL) {
|
||||
printf(" (ADB_PROTOCOL)");
|
||||
}
|
||||
printf("\n iInterface = %u", intr_desc.iInterface);
|
||||
} else {
|
||||
printf("\n--- AdbGetUsbInterfaceDescriptor failure %u", GetLastError());
|
||||
@@ -266,14 +382,10 @@ bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
|
||||
for (UCHAR pipe = 0; pipe < intr_desc.bNumEndpoints; pipe++) {
|
||||
if (AdbGetEndpointInformation(interface_handle, pipe, &pipe_info)) {
|
||||
printf("\n PIPE %u info:", pipe);
|
||||
printf("\n PIPE %u info:", pipe);
|
||||
printf("\n max_packet_size = %u", pipe_info.max_packet_size);
|
||||
printf("\n max_transfer_size = %u", pipe_info.max_transfer_size);
|
||||
printf("\n endpoint_type = %u", pipe_info.endpoint_type);
|
||||
printf("\n endpoint_address = %02X", pipe_info.endpoint_address);
|
||||
printf("\n polling_interval = %u", pipe_info.polling_interval);
|
||||
DumpEndpointInformation(&pipe_info);
|
||||
} else {
|
||||
} else {
|
||||
printf("\n--- AdbGetEndpointInformation(%u) failure %u", pipe,
|
||||
GetLastError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -281,28 +393,20 @@ bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
|
||||
// Get default bulk read endpoint info
|
||||
if (AdbGetDefaultBulkReadEndpointInformation(interface_handle, &pipe_info)) {
|
||||
printf("\n Default Bulk Read Pipe info:");
|
||||
printf("\n Default Bulk Read Pipe info:");
|
||||
printf("\n max_packet_size = %u", pipe_info.max_packet_size);
|
||||
printf("\n max_transfer_size = %u", pipe_info.max_transfer_size);
|
||||
printf("\n endpoint_type = %u", pipe_info.endpoint_type);
|
||||
printf("\n endpoint_address = %02X", pipe_info.endpoint_address);
|
||||
printf("\n polling_interval = %u", pipe_info.polling_interval);
|
||||
DumpEndpointInformation(&pipe_info);
|
||||
} else {
|
||||
} else {
|
||||
printf("\n--- AdbGetDefaultBulkReadEndpointInformation failure %u",
|
||||
GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get default bulk write endpoint info
|
||||
if (AdbGetDefaultBulkWriteEndpointInformation(interface_handle, &pipe_info)) {
|
||||
printf("\n Default Bulk Write Pipe info:");
|
||||
printf("\n Default Bulk Write Pipe info:");
|
||||
printf("\n max_packet_size = %u", pipe_info.max_packet_size);
|
||||
printf("\n max_transfer_size = %u", pipe_info.max_transfer_size);
|
||||
printf("\n endpoint_type = %u", pipe_info.endpoint_type);
|
||||
printf("\n endpoint_address = %02X", pipe_info.endpoint_address);
|
||||
printf("\n polling_interval = %u", pipe_info.polling_interval);
|
||||
DumpEndpointInformation(&pipe_info);
|
||||
} else {
|
||||
} else {
|
||||
printf("\n--- AdbGetDefaultBulkWriteEndpointInformation failure %u",
|
||||
GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -312,6 +416,48 @@ bool TestInterfaceHandle(ADBAPIHANDLE interface_handle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void HexDump(const void* data, const size_t read_bytes) {
|
||||
const unsigned char* buf = reinterpret_cast<const unsigned char*>(data);
|
||||
const size_t line_length = 16;
|
||||
for (size_t n = 0; n < read_bytes; n += line_length) {
|
||||
const unsigned char* line = &buf[n];
|
||||
const size_t max_line = min(line_length, read_bytes - n);
|
||||
|
||||
printf("\n ");
|
||||
for (size_t i = 0; i < line_length; ++i) {
|
||||
if (i >= max_line) {
|
||||
printf(" ");
|
||||
} else {
|
||||
printf("%02X ", line[i]);
|
||||
}
|
||||
}
|
||||
printf(" ");
|
||||
for (size_t i = 0; i < max_line; ++i) {
|
||||
if (isprint(line[i])) {
|
||||
printf("%c", line[i]);
|
||||
} else {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DumpMessageArg0(unsigned int command, unsigned int arg0) {
|
||||
if (command == A_AUTH) {
|
||||
const char* desc = NULL;
|
||||
switch (arg0) {
|
||||
#define CASE_ARG0(arg) case arg: desc = # arg; break
|
||||
CASE_ARG0(ADB_AUTH_TOKEN);
|
||||
CASE_ARG0(ADB_AUTH_SIGNATURE);
|
||||
CASE_ARG0(ADB_AUTH_RSAPUBLICKEY);
|
||||
#undef CASE_ARG0
|
||||
}
|
||||
if (desc != NULL) {
|
||||
printf(" (%s)", desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceHandShake(ADBAPIHANDLE adb_interface) {
|
||||
// Get interface name
|
||||
char interf_name[512];
|
||||
@@ -361,11 +507,11 @@ bool DeviceHandShake(ADBAPIHANDLE adb_interface) {
|
||||
// Send connect message
|
||||
message msg_send;
|
||||
msg_send.command = A_CNXN;
|
||||
msg_send.command = A_CNXN;
|
||||
msg_send.arg0 = A_VERSION;
|
||||
msg_send.arg1 = MAX_PAYLOAD;
|
||||
msg_send.data_length = 0;
|
||||
msg_send.data_crc32 = 0;
|
||||
msg_send.arg0 = A_VERSION;
|
||||
msg_send.arg1 = MAX_PAYLOAD;
|
||||
msg_send.data_length = 0;
|
||||
msg_send.data_crc32 = 0;
|
||||
msg_send.magic = msg_send.command ^ 0xffffffff;
|
||||
|
||||
ULONG written_bytes = 0;
|
||||
bool write_res = AdbWriteEndpointSync(adb_write, &msg_send, sizeof(msg_send), &written_bytes, 500);
|
||||
@@ -392,10 +538,13 @@ bool DeviceHandShake(ADBAPIHANDLE adb_interface) {
|
||||
printf("\n command = %08X (%c%c%c%c)", msg_rcv.command,
|
||||
cmd_ansi[0], cmd_ansi[1], cmd_ansi[2], cmd_ansi[3]);
|
||||
printf("\n arg0 = %08X", msg_rcv.arg0);
|
||||
DumpMessageArg0(msg_rcv.command, msg_rcv.arg0);
|
||||
printf("\n arg1 = %08X", msg_rcv.arg1);
|
||||
printf("\n data_length = %u", msg_rcv.data_length);
|
||||
printf("\n data_crc32 = %08X", msg_rcv.data_crc32);
|
||||
printf("\n magic = %08X", msg_rcv.magic);
|
||||
printf(" (%s)", (msg_rcv.magic == (msg_rcv.command ^ 0xffffffff)) ?
|
||||
"valid" : "invalid");
|
||||
|
||||
if (0 != msg_rcv.data_length) {
|
||||
char* buf = reinterpret_cast<char*>(malloc(msg_rcv.data_length));
|
||||
@@ -408,19 +557,261 @@ bool DeviceHandShake(ADBAPIHANDLE adb_interface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (ULONG n = 0; n < read_bytes; n++) {
|
||||
if (0 == (n % 16))
|
||||
printf("\n ");
|
||||
printf("%02X ", buf[n]);
|
||||
HexDump(buf, read_bytes);
|
||||
|
||||
|
||||
printf("\n %s", buf);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
|
||||
AdbCloseHandle(adb_write);
|
||||
if (!AdbCloseHandle(adb_write)) {
|
||||
printf("\n--- AdbCloseHandle failure %u", GetLastError());
|
||||
}
|
||||
if (!AdbCloseHandle(adb_read)) {
|
||||
printf("\n--- AdbCloseHandle failure %u", GetLastError());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Randomly delay the current thread.
|
||||
class RandomDelayer {
|
||||
public:
|
||||
// Prepare for a call to Delay() by getting random data. This call might grab
|
||||
// locks, causing serialization, so this should be called before
|
||||
// time-sensitive code.
|
||||
void SeedRandom() {
|
||||
r_ = rand();
|
||||
}
|
||||
|
||||
// Randomly delay the current thread based on a previous call to SeedRandom().
|
||||
void Delay() {
|
||||
switch (r_ % 5) {
|
||||
case 0:
|
||||
Sleep(0); // Give up time slice to another read-to-run thread.
|
||||
break;
|
||||
case 1:
|
||||
// Try to sleep for 1 ms, but probably more based on OS scheduler
|
||||
// minimum granularity.
|
||||
Sleep(1);
|
||||
break;
|
||||
case 2:
|
||||
// Yield to another thread ready-to-run on the current processor.
|
||||
SwitchToThread();
|
||||
break;
|
||||
case 3:
|
||||
// Busy-wait for a random amount of time.
|
||||
for (int i = 0; i < r_; ++i) {
|
||||
GetLastError();
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
break; // Do nothing, no delay.
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int r_;
|
||||
};
|
||||
|
||||
volatile ADBAPIHANDLE g_read_handle;
|
||||
volatile ADBAPIHANDLE g_interface_handle;
|
||||
volatile bool g_stop_close_race_thread;
|
||||
|
||||
unsigned __stdcall CloseRaceThread(void*) {
|
||||
RandomDelayer r;
|
||||
|
||||
while (!g_stop_close_race_thread) {
|
||||
r.SeedRandom();
|
||||
|
||||
// Do volatile reads of both globals
|
||||
ADBAPIHANDLE read_handle = g_read_handle;
|
||||
ADBAPIHANDLE interface_handle = g_interface_handle;
|
||||
|
||||
// If we got both handles, close them and clear the globals
|
||||
if (read_handle != NULL && interface_handle != NULL) {
|
||||
// Delay random amount before calling the API that conflicts with
|
||||
// Adb{Read,Write}EndpointSync().
|
||||
r.Delay();
|
||||
|
||||
if (!AdbCloseHandle(read_handle)) {
|
||||
printf("\nAdbCloseHandle(read) failure: %u", GetLastError());
|
||||
}
|
||||
if (!AdbCloseHandle(interface_handle)) {
|
||||
printf("\nAdbCloseHandle(interface) failure: %u", GetLastError());
|
||||
}
|
||||
|
||||
// Clear globals so that read thread is free to set them.
|
||||
g_read_handle = NULL;
|
||||
g_interface_handle = NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define EXPECTED_ERROR_LIST(FOR_EACH) \
|
||||
FOR_EACH(ERROR_INVALID_HANDLE) \
|
||||
FOR_EACH(ERROR_HANDLES_CLOSED) \
|
||||
FOR_EACH(ERROR_OPERATION_ABORTED)
|
||||
|
||||
#define MAKE_ARRAY_ITEM(x) x,
|
||||
const DWORD g_expected_errors[] = {
|
||||
EXPECTED_ERROR_LIST(MAKE_ARRAY_ITEM)
|
||||
};
|
||||
#undef MAKE_ARRAY_ITEM
|
||||
|
||||
#define MAKE_STRING_ITEM(x) #x,
|
||||
const char* g_expected_error_strings[] = {
|
||||
EXPECTED_ERROR_LIST(MAKE_STRING_ITEM)
|
||||
};
|
||||
#undef MAKE_STRING_ITEM
|
||||
|
||||
std::string get_error_description(const DWORD err) {
|
||||
const DWORD* end = g_expected_errors + ARRAYSIZE(g_expected_errors);
|
||||
const DWORD* found = std::find(g_expected_errors, end, err);
|
||||
if (found != end) {
|
||||
return g_expected_error_strings[found - g_expected_errors];
|
||||
} else {
|
||||
char buf[64];
|
||||
_snprintf(buf, sizeof(buf), "%u", err);
|
||||
return std::string(buf);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_expected_error(const DWORD err) {
|
||||
const DWORD* end = g_expected_errors + ARRAYSIZE(g_expected_errors);
|
||||
return std::find(g_expected_errors, end, err) != end;
|
||||
}
|
||||
|
||||
// Test to reproduce https://code.google.com/p/android/issues/detail?id=161890
|
||||
bool TestCloseRaceCondition() {
|
||||
const DWORD test_duration_sec = 10;
|
||||
printf("\nTesting close race condition for %u seconds... ",
|
||||
test_duration_sec);
|
||||
|
||||
ADBAPIHANDLE enum_handle =
|
||||
AdbEnumInterfaces(kAdbInterfaceId, true, true, true);
|
||||
if (NULL == enum_handle) {
|
||||
printf("\nUnable to enumerate ADB interfaces: %u", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
union {
|
||||
AdbInterfaceInfo interface_info;
|
||||
char buf[4096];
|
||||
};
|
||||
unsigned long buf_size = sizeof(buf);
|
||||
|
||||
// Get the first interface
|
||||
if (!AdbNextInterface(enum_handle, &interface_info, &buf_size)) {
|
||||
printf("\n--- AdbNextInterface failure %u", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AdbCloseHandle(enum_handle)) {
|
||||
printf("\nAdbCloseHandle(enum_handle) failure: %u", GetLastError());
|
||||
}
|
||||
|
||||
HANDLE thread_handle = reinterpret_cast<HANDLE>(
|
||||
_beginthreadex(NULL, 0, CloseRaceThread, NULL, 0, NULL));
|
||||
if (thread_handle == NULL) {
|
||||
printf("\n--- _beginthreadex failure %u", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run the test for 10 seconds. It usually reproduces the crash in 1 second.
|
||||
const DWORD tick_start = GetTickCount();
|
||||
const DWORD test_duration_ticks = test_duration_sec * 1000;
|
||||
RandomDelayer r;
|
||||
|
||||
std::map<DWORD, size_t> read_errors;
|
||||
|
||||
while (GetTickCount() < tick_start + test_duration_ticks) {
|
||||
// Busy-wait until close thread has cleared the handles, so that we don't
|
||||
// leak handles during the test.
|
||||
while (g_read_handle != NULL) {}
|
||||
while (g_interface_handle != NULL) {}
|
||||
|
||||
ADBAPIHANDLE interface_handle = AdbCreateInterfaceByName(
|
||||
interface_info.device_name);
|
||||
if (interface_handle == NULL) {
|
||||
// Not really expected to encounter an error here.
|
||||
printf("\n--- AdbCreateInterfaceByName failure %u", GetLastError());
|
||||
continue; // try again
|
||||
}
|
||||
ADBAPIHANDLE read_handle = AdbOpenDefaultBulkReadEndpoint(
|
||||
interface_handle, AdbOpenAccessTypeReadWrite,
|
||||
AdbOpenSharingModeReadWrite);
|
||||
if (read_handle == NULL) {
|
||||
// Not really expected to encounter an error here, so report, cleanup,
|
||||
// and retry.
|
||||
printf("\n--- AdbOpenDefaultBulkReadEndpoint failure %u", GetLastError());
|
||||
AdbCloseHandle(interface_handle);
|
||||
continue;
|
||||
}
|
||||
|
||||
r.SeedRandom();
|
||||
|
||||
// Set handles to allow other thread to close them.
|
||||
g_read_handle = read_handle;
|
||||
g_interface_handle = interface_handle;
|
||||
|
||||
// Delay random amount before calling the API that conflicts with
|
||||
// AdbCloseHandle().
|
||||
r.Delay();
|
||||
|
||||
message msg_rcv;
|
||||
ULONG read_bytes = 0;
|
||||
|
||||
while (AdbReadEndpointSync(read_handle, &msg_rcv, sizeof(msg_rcv),
|
||||
&read_bytes, 0 /* infinite timeout */)) {
|
||||
// Keep reading until a crash or we're broken out of the read
|
||||
// (with an error) by the CloseRaceThread.
|
||||
}
|
||||
read_errors[GetLastError()]++;
|
||||
}
|
||||
|
||||
g_stop_close_race_thread = true;
|
||||
if (WaitForSingleObject(thread_handle, INFINITE) != WAIT_OBJECT_0) {
|
||||
printf("\n--- WaitForSingleObject failure %u", GetLastError());
|
||||
}
|
||||
if (!CloseHandle(thread_handle)) {
|
||||
printf("\n--- CloseHandle failure %u", GetLastError());
|
||||
}
|
||||
|
||||
// The expected errors are the errors that would be encountered if the code
|
||||
// had all the major concurrent interleavings. So the test only passes if
|
||||
// we encountered all the expected errors, and thus stress tested all the
|
||||
// possible major concurrent interleavings.
|
||||
bool pass = true;
|
||||
for (size_t i = 0; i < ARRAYSIZE(g_expected_errors); ++i) {
|
||||
// If we didn't encounter the expected error code, then the test failed.
|
||||
if (read_errors.count(g_expected_errors[i]) == 0) {
|
||||
pass = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pass) {
|
||||
printf("passed");
|
||||
} else {
|
||||
printf("failed.");
|
||||
printf("\nPerhaps you just need to run the test longer or again.");
|
||||
}
|
||||
|
||||
printf("\nRead Error Code\t\tCount");
|
||||
printf("\n=============================");
|
||||
|
||||
for (std::map<DWORD, size_t>::iterator it = read_errors.begin();
|
||||
it != read_errors.end(); ++it) {
|
||||
printf("\n%s\t%u%s", get_error_description(it->first).c_str(), it->second,
|
||||
is_expected_error(it->first) ? " (expected)" : "");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE(g_expected_errors); ++i) {
|
||||
if (read_errors.count(g_expected_errors[i]) == 0) {
|
||||
printf("\n%s\t%u (was not encountered, but was expected)",
|
||||
get_error_description(g_expected_errors[i]).c_str(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include <atlbase.h>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <initguid.h>
|
||||
|
||||
|
||||
@@ -12,8 +12,28 @@ 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.
|
||||
|
||||
In order to build AdbWinApi.dll you will need to install Windows Driver Kit,
|
||||
which can be obtained from Microsoft. Assuming that WDK is installed, you
|
||||
need to set one of the WDK's build environments, "cd" back into this directory,
|
||||
and execute "build -cbeEIFZ" to clean and rebuild this project, or you can
|
||||
execute "build -befEIF" to do a minimal build.
|
||||
In order to build a directory with a SOURCES file you will need to install
|
||||
the Windows Driver Kit, which can be obtained from Microsoft:
|
||||
|
||||
Windows Driver Kit Version 7.1.0
|
||||
https://www.microsoft.com/en-us/download/details.aspx?id=11800
|
||||
md5: 8fe981a1706d43ad34bda496e6558f94
|
||||
sha1: de6abdb8eb4e08942add4aa270c763ed4e3d8242
|
||||
|
||||
This old version is used because it can build for Windows Vista (WDK 8.1
|
||||
cannot), it includes compilers (so it doesn't require Visual Studio), and it is
|
||||
probably not too far from the WDK that this code was originally built with, so
|
||||
it should be less risky.
|
||||
|
||||
When installing the WDK, uncheck `Device Simulation Framework' because it is
|
||||
unnecessary and it installs a kernel-mode driver that we don't need.
|
||||
|
||||
Assuming that WDK is installed, you need to set one of the WDK's build
|
||||
environments (Start Menu -> Windows Driver Kits -> x86 Free Build Environment;
|
||||
choose the one for the oldest version of Windows you want to support),
|
||||
"cd" back into this directory, and execute "build -cbeEIFZ" to clean and rebuild
|
||||
this project, or you can execute "build -befEIF" to do a minimal build.
|
||||
|
||||
When you're done with the WDK build environment, don't forget to right-click the
|
||||
OACR icon (in the lower-right notification area of the taskbar) and choose
|
||||
`Close'.
|
||||
|
||||
@@ -18,8 +18,13 @@ TARGETNAME = AdbWinApi
|
||||
TARGETPATH = obj
|
||||
TARGETTYPE = DYNLINK
|
||||
|
||||
_NT_TARGET_VERSION = $(_NT_TARGET_VERSION_VISTA)
|
||||
|
||||
UMTYPE = windows
|
||||
DLLDEF = AdbWinApi.def
|
||||
# Use the same load address as previous versions just to be conservative. This
|
||||
# really doesn't matter on newer OSes that use ASLR.
|
||||
DLLBASE = 0x400000
|
||||
|
||||
# Use statically linked atl libraries:
|
||||
# - atls.lib for free build
|
||||
@@ -33,6 +38,12 @@ STL_VER = 60
|
||||
# Use multithreaded libraries
|
||||
USE_LIBCMT = 1
|
||||
|
||||
!IF !$(FREEBUILD)
|
||||
# In checked build, ATL headers call APIs that are only in atlsd.lib. To use
|
||||
# atlsd.lib in checked build, set DEBUG_CRTS.
|
||||
DEBUG_CRTS=1
|
||||
!ENDIF
|
||||
|
||||
# Include directories
|
||||
INCLUDES = $(DDK_INC_PATH); \
|
||||
$(SDK_INC_PATH); \
|
||||
@@ -52,33 +63,28 @@ TARGETLIBS = $(SDK_LIB_PATH)\ole32.lib \
|
||||
$(SDK_LIB_PATH)\setupapi.lib \
|
||||
$(SDK_LIB_PATH)\usbd.lib
|
||||
|
||||
!IF "$(DDKBUILDENV)" == "fre"
|
||||
# Libraries for release (free) builds
|
||||
TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atls.lib
|
||||
!ELSE
|
||||
# Libraries for debug (checked) builds
|
||||
TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atlsd.lib
|
||||
!ENDIF
|
||||
|
||||
# Common C defines
|
||||
C_DEFINES= $(C_DEFINES) -DADBWIN_EXPORTS -D_UNICODE \
|
||||
-DUNICODE -DWIN32 -D_WINDOWS -D_USRDLL -D_WINDLL
|
||||
|
||||
!IF "$(DDKBUILDENV)" == "fre"
|
||||
# C defines for release (free) builds
|
||||
!IF "$(DDKBUILDENV)" == "fre"
|
||||
# C defines for release (free) builds
|
||||
C_DEFINES = $(C_DEFINES) -DNDEBUG
|
||||
!ELSE
|
||||
# C defines for debug (checked) builds
|
||||
# C defines for debug (checked) builds
|
||||
C_DEFINES = $(C_DEFINES) -D_DEBUG
|
||||
!ENDIF
|
||||
|
||||
# Turn on all warnings, and treat warnings as errors
|
||||
MSC_WARNING_LEVEL = /W4 /Wp64 /WX
|
||||
|
||||
MSC_WARNING_LEVEL = /W4 /WX
|
||||
|
||||
# operator new throws C++ exceptions
|
||||
USE_NATIVE_EH=1
|
||||
|
||||
# Common C defines
|
||||
USER_C_FLAGS = $(USER_C_FLAGS) /FD /EHsc /wd4100 /wd4200 /wd4702 /nologo
|
||||
|
||||
# Set precompiled header information
|
||||
USER_C_FLAGS = $(USER_C_FLAGS) /FD /wd4100 /wd4200 /wd4702 /nologo
|
||||
|
||||
# Set precompiled header information
|
||||
PRECOMPILED_CXX = 1
|
||||
PRECOMPILED_INCLUDE = stdafx.h
|
||||
PRECOMPILED_SOURCEFILE = stdafx.cpp
|
||||
|
||||
22
host/windows/usb/api/adb_api.h
Normal file → Executable file
22
host/windows/usb/api/adb_api.h
Normal file → Executable file
@@ -91,28 +91,6 @@ typedef struct _AdbEndpointInformation {
|
||||
#define ANDROID_USB_CLASS_ID \
|
||||
{0xf72fe0d4, 0xcbcb, 0x407d, {0x88, 0x14, 0x9e, 0xd6, 0x73, 0xd0, 0xdd, 0x6b}};
|
||||
|
||||
/// Defines vendor ID for HCT devices.
|
||||
#define DEVICE_VENDOR_ID 0x0BB4
|
||||
|
||||
/// Defines product ID for the device with single interface.
|
||||
#define DEVICE_SINGLE_PRODUCT_ID 0x0C01
|
||||
|
||||
/// Defines product ID for the Dream composite device.
|
||||
#define DEVICE_COMPOSITE_PRODUCT_ID 0x0C02
|
||||
|
||||
/// Defines product ID for the Magic composite device.
|
||||
#define DEVICE_MAGIC_COMPOSITE_PRODUCT_ID 0x0C03
|
||||
|
||||
/// Defines interface ID for the device.
|
||||
#define DEVICE_INTERFACE_ID 0x01
|
||||
|
||||
/// Defines vendor ID for the device
|
||||
#define DEVICE_EMULATOR_VENDOR_ID 0x18D1
|
||||
|
||||
/// Defines product ID for a SoftUSB device simulator that is used to test
|
||||
/// the driver in isolation from hardware.
|
||||
#define DEVICE_EMULATOR_PROD_ID 0xDDDD
|
||||
|
||||
// The following ifdef block is the standard way of creating macros which make
|
||||
// exporting from a DLL simpler. All files within this DLL are compiled with
|
||||
// the ADBWIN_EXPORTS symbol defined on the command line. this symbol should
|
||||
|
||||
@@ -57,8 +57,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,0,0,0
|
||||
PRODUCTVERSION 2,0,0,0
|
||||
FILEVERSION 2,0,0,1
|
||||
PRODUCTVERSION 2,0,0,1
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -75,12 +75,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Google, inc"
|
||||
VALUE "FileDescription", "Android ADB API (WinUsb)"
|
||||
VALUE "FileVersion", "2.0.0.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2006 The Android Open Source Project"
|
||||
VALUE "FileVersion", "2.0.0.1"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2006-2015 The Android Open Source Project"
|
||||
VALUE "InternalName", "AdbWinUsbApi.dll"
|
||||
VALUE "OriginalFilename", "AdbWinUsbApi.dll"
|
||||
VALUE "ProductName", "Android SDK"
|
||||
VALUE "ProductVersion", "2.0.0.0"
|
||||
VALUE "ProductVersion", "2.0.0.1"
|
||||
VALUE "OLESelfRegister", ""
|
||||
END
|
||||
END
|
||||
|
||||
@@ -1,7 +1,42 @@
|
||||
In order to build AdbWinUsbApi.dll you will need to install Windows Driver Kit,
|
||||
which can be obtained from Microsoft. Assuming that WDK is installed, you
|
||||
need to set one of the WDK's build environments, "cd" back into this directory,
|
||||
and execute "build -cbeEIFZ" to clean and rebuild this project, or you can
|
||||
execute "build -befEIF" to do a minimal build.
|
||||
Copyright (C) 2006 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.
|
||||
|
||||
In order to build a directory with a SOURCES file you will need to install
|
||||
the Windows Driver Kit, which can be obtained from Microsoft:
|
||||
|
||||
Windows Driver Kit Version 7.1.0
|
||||
https://www.microsoft.com/en-us/download/details.aspx?id=11800
|
||||
md5: 8fe981a1706d43ad34bda496e6558f94
|
||||
sha1: de6abdb8eb4e08942add4aa270c763ed4e3d8242
|
||||
|
||||
This old version is used because it can build for Windows Vista (WDK 8.1
|
||||
cannot), it includes compilers (so it doesn't require Visual Studio), and it is
|
||||
probably not too far from the WDK that this code was originally built with, so
|
||||
it should be less risky.
|
||||
|
||||
When installing the WDK, uncheck `Device Simulation Framework' because it is
|
||||
unnecessary and it installs a kernel-mode driver that we don't need.
|
||||
|
||||
Assuming that WDK is installed, you need to set one of the WDK's build
|
||||
environments (Start Menu -> Windows Driver Kits -> x86 Free Build Environment;
|
||||
choose the one for the oldest version of Windows you want to support),
|
||||
"cd" back into this directory, and execute "build -cbeEIFZ" to clean and rebuild
|
||||
this project, or you can execute "build -befEIF" to do a minimal build.
|
||||
|
||||
Note that you need to build AdbWinApi.dll (..\api) before you build
|
||||
AdbWinUsbApi.dll, as it depends on AdbWinApi.lib library.
|
||||
this directory, as this depends on the AdbWinApi.lib import library.
|
||||
|
||||
When you're done with the WDK build environment, don't forget to right-click the
|
||||
OACR icon (in the lower-right notification area of the taskbar) and choose
|
||||
`Close'.
|
||||
|
||||
@@ -18,8 +18,13 @@ TARGETNAME = AdbWinUsbApi
|
||||
TARGETPATH = obj
|
||||
TARGETTYPE = DYNLINK
|
||||
|
||||
_NT_TARGET_VERSION = $(_NT_TARGET_VERSION_VISTA)
|
||||
|
||||
UMTYPE = windows
|
||||
DLLDEF = AdbWinUsbApi.def
|
||||
# Use the same load address as previous versions just to be conservative. This
|
||||
# really doesn't matter on newer OSes that use ASLR.
|
||||
DLLBASE = 0x400000
|
||||
|
||||
# Use statically linked atl libraries:
|
||||
# - atls.lib for free build
|
||||
@@ -33,6 +38,12 @@ STL_VER = 60
|
||||
# Use multithreaded libraries
|
||||
USE_LIBCMT = 1
|
||||
|
||||
!IF !$(FREEBUILD)
|
||||
# In checked build, ATL headers call APIs that are only in atlsd.lib. To use
|
||||
# atlsd.lib in checked build, set DEBUG_CRTS.
|
||||
DEBUG_CRTS=1
|
||||
!ENDIF
|
||||
|
||||
# Include directories
|
||||
INCLUDES = $(DDK_INC_PATH); \
|
||||
$(SDK_INC_PATH); \
|
||||
@@ -54,33 +65,28 @@ TARGETLIBS = $(SDK_LIB_PATH)\ole32.lib \
|
||||
$(SDK_LIB_PATH)\winusb.lib \
|
||||
..\api\obj$(BUILD_ALT_DIR)\i386\AdbWinApi.lib
|
||||
|
||||
!IF "$(DDKBUILDENV)" == "fre"
|
||||
# Libraries for release (free) builds
|
||||
TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atls.lib
|
||||
!ELSE
|
||||
# Libraries for debug (checked) builds
|
||||
TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atlsd.lib
|
||||
!ENDIF
|
||||
|
||||
# Common C defines
|
||||
C_DEFINES= $(C_DEFINES) -DADBWINUSB_EXPORTS -D_UNICODE \
|
||||
-DUNICODE -DWIN32 -D_WINDOWS -D_USRDLL -D_WINDLL
|
||||
|
||||
!IF "$(DDKBUILDENV)" == "fre"
|
||||
# C defines for release (free) builds
|
||||
!IF "$(DDKBUILDENV)" == "fre"
|
||||
# C defines for release (free) builds
|
||||
C_DEFINES = $(C_DEFINES) -DNDEBUG
|
||||
!ELSE
|
||||
# C defines for debug (checked) builds
|
||||
# C defines for debug (checked) builds
|
||||
C_DEFINES = $(C_DEFINES) -D_DEBUG
|
||||
!ENDIF
|
||||
|
||||
# Turn on all warnings, and treat warnings as errors
|
||||
MSC_WARNING_LEVEL = /W4 /Wp64 /WX
|
||||
|
||||
MSC_WARNING_LEVEL = /W4 /WX
|
||||
|
||||
# operator new throws C++ exceptions
|
||||
USE_NATIVE_EH=1
|
||||
|
||||
# Common C defines
|
||||
USER_C_FLAGS = $(USER_C_FLAGS) /FD /EHsc /wd4100 /wd4200 /wd4702 /nologo
|
||||
|
||||
# Set precompiled header information
|
||||
USER_C_FLAGS = $(USER_C_FLAGS) /FD /wd4100 /wd4200 /wd4702 /nologo
|
||||
|
||||
# Set precompiled header information
|
||||
PRECOMPILED_CXX = 1
|
||||
PRECOMPILED_INCLUDE = stdafx.h
|
||||
PRECOMPILED_SOURCEFILE = stdafx.cpp
|
||||
|
||||
@@ -27,7 +27,8 @@ AdbWinUsbEndpointObject::AdbWinUsbEndpointObject(
|
||||
AdbWinUsbInterfaceObject* parent_interf,
|
||||
UCHAR endpoint_id,
|
||||
UCHAR endpoint_index)
|
||||
: AdbEndpointObject(parent_interf, endpoint_id, endpoint_index) {
|
||||
: AdbEndpointObject(parent_interf, endpoint_id, endpoint_index),
|
||||
lock_(), is_closing_(false), pending_io_count_(0) {
|
||||
}
|
||||
|
||||
AdbWinUsbEndpointObject::~AdbWinUsbEndpointObject() {
|
||||
@@ -44,6 +45,54 @@ LONG AdbWinUsbEndpointObject::Release() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AdbWinUsbEndpointObject::CloseHandle() {
|
||||
// This method only returns once all pending IOs are aborted and after
|
||||
// preventing future pending IOs. This means that once CloseHandle()
|
||||
// returns, threads using this object won't be using
|
||||
// parent_winusb_interface()->winusb_handle(), so it can then be safely
|
||||
// released.
|
||||
lock_.Lock();
|
||||
if (!is_closing_) {
|
||||
// Set flag to prevent new I/Os from starting up.
|
||||
is_closing_ = true;
|
||||
}
|
||||
|
||||
// While there are pending IOs, keep aborting the pipe. We have to do this
|
||||
// repeatedly because pending_ios_ is incremented before the IO has actually
|
||||
// started, and abort (probably) only works if the IO has been started.
|
||||
while (pending_io_count_ > 0) {
|
||||
lock_.Unlock();
|
||||
|
||||
// It has been noticed that on Windows 7, if you only call
|
||||
// WinUsb_AbortPipe(), without first calling WinUsb_ResetPipe(), the call
|
||||
// to WinUsb_AbortPipe() hangs.
|
||||
if (!WinUsb_ResetPipe(parent_winusb_interface()->winusb_handle(),
|
||||
endpoint_id()) ||
|
||||
!WinUsb_AbortPipe(parent_winusb_interface()->winusb_handle(),
|
||||
endpoint_id())) {
|
||||
// Reset or Abort failed for unexpected reason. We might not be able to
|
||||
// abort pending IOs, so we shouldn't keep polling pending_io_count_ or
|
||||
// else we might hang forever waiting for the IOs to abort. In this
|
||||
// situation it is preferable to risk a race condition (which may or may
|
||||
// not crash) and just break now.
|
||||
lock_.Lock();
|
||||
break;
|
||||
}
|
||||
|
||||
// Give the IO threads time to break out of I/O calls and decrement
|
||||
// pending_io_count_. They should finish up pretty quick. The amount of time
|
||||
// "wasted" here (as opposed to if we did synchronization with an event)
|
||||
// doesn't really matter since this is an uncommon corner-case.
|
||||
Sleep(16); // 16 ms, old default OS scheduler granularity
|
||||
|
||||
lock_.Lock();
|
||||
}
|
||||
|
||||
lock_.Unlock();
|
||||
|
||||
return AdbEndpointObject::CloseHandle();
|
||||
}
|
||||
|
||||
ADBAPIHANDLE AdbWinUsbEndpointObject::CommonAsyncReadWrite(
|
||||
bool is_read,
|
||||
void* buffer,
|
||||
@@ -51,6 +100,9 @@ ADBAPIHANDLE AdbWinUsbEndpointObject::CommonAsyncReadWrite(
|
||||
ULONG* bytes_transferred,
|
||||
HANDLE event_handle,
|
||||
ULONG time_out) {
|
||||
// TODO: Do synchronization with is_closing_ and pending_io_count_ like
|
||||
// CommonSyncReadWrite(). This is not yet implemented because there are no
|
||||
// callers to Adb{Read,Write}EndpointAsync() in AOSP, and hence no testing.
|
||||
if (!SetTimeout(time_out))
|
||||
return false;
|
||||
|
||||
@@ -110,6 +162,24 @@ bool AdbWinUsbEndpointObject::CommonSyncReadWrite(bool is_read,
|
||||
ULONG bytes_to_transfer,
|
||||
ULONG* bytes_transferred,
|
||||
ULONG time_out) {
|
||||
lock_.Lock();
|
||||
if (is_closing_) {
|
||||
lock_.Unlock();
|
||||
// AdbCloseHandle() is in progress, so don't start up any new IOs.
|
||||
SetLastError(ERROR_HANDLES_CLOSED);
|
||||
return false;
|
||||
} else {
|
||||
// Not closing down, so record the fact that we're doing IO. This will
|
||||
// prevent CloseHandle() from returning until our IO completes or it aborts
|
||||
// our IO.
|
||||
++pending_io_count_;
|
||||
lock_.Unlock();
|
||||
}
|
||||
|
||||
// Because we've incremented pending_ios_, do the matching decrement when this
|
||||
// object goes out of scope.
|
||||
DecrementPendingIO dec(this);
|
||||
|
||||
if (!SetTimeout(time_out))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -72,6 +72,17 @@ class AdbWinUsbEndpointObject : public AdbEndpointObject {
|
||||
*/
|
||||
virtual LONG Release();
|
||||
|
||||
/** \brief This method is called when handle to this object gets closed.
|
||||
|
||||
In this call object is deleted from the AdbObjectHandleMap. We override
|
||||
this method in order to abort pending IOs and to prevent new IOs from
|
||||
starting up.
|
||||
@return true on success or false if object is already closed. If
|
||||
false is returned GetLastError() provides extended error
|
||||
information.
|
||||
*/
|
||||
virtual bool CloseHandle();
|
||||
|
||||
//
|
||||
// Abstract overrides
|
||||
//
|
||||
@@ -150,6 +161,32 @@ class AdbWinUsbEndpointObject : public AdbEndpointObject {
|
||||
WINUSB_INTERFACE_HANDLE winusb_handle() const {
|
||||
return parent_winusb_interface()->winusb_handle();
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Helper class whose destructor decrements pending_io_count_.
|
||||
class DecrementPendingIO {
|
||||
public:
|
||||
DecrementPendingIO(AdbWinUsbEndpointObject* endpoint)
|
||||
: endpoint_(endpoint) {}
|
||||
~DecrementPendingIO() {
|
||||
endpoint_->lock_.Lock();
|
||||
ATLASSERT(endpoint_->pending_io_count_ > 0);
|
||||
--(endpoint_->pending_io_count_);
|
||||
endpoint_->lock_.Unlock();
|
||||
}
|
||||
private:
|
||||
AdbWinUsbEndpointObject* endpoint_;
|
||||
};
|
||||
|
||||
protected:
|
||||
/// Protects is_closing_ and pending_io_count_.
|
||||
CComAutoCriticalSection lock_;
|
||||
|
||||
/// Once set, prevents new IOs from starting up.
|
||||
bool is_closing_;
|
||||
|
||||
/// Count of pending IOs potentially blocked in WinUsb APIs.
|
||||
ULONG pending_io_count_;
|
||||
};
|
||||
|
||||
#endif // ANDROID_USB_API_ADB_WINUSB_ENDPOINT_OBJECT_H__
|
||||
|
||||
Reference in New Issue
Block a user