summaryrefslogtreecommitdiffstats
path: root/host/windows/usb/adb_winapi_test/adb_winapi_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/windows/usb/adb_winapi_test/adb_winapi_test.cpp')
-rwxr-xr-xhost/windows/usb/adb_winapi_test/adb_winapi_test.cpp575
1 files changed, 483 insertions, 92 deletions
diff --git a/host/windows/usb/adb_winapi_test/adb_winapi_test.cpp b/host/windows/usb/adb_winapi_test/adb_winapi_test.cpp
index 11fcadf01..75bf76a82 100755
--- a/host/windows/usb/adb_winapi_test/adb_winapi_test.cpp
+++ b/host/windows/usb/adb_winapi_test/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);
- return true;
+ 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());
- return 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);
- };
+ 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);
+ }
- AdbCloseHandle(enum_handle);
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ printf("\n--- AdbNextInterface failure %u", GetLastError());
+ ret = false;
+ }
- // 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;
+ if (!AdbCloseHandle(enum_handle)) {
+ printf("\n--- AdbCloseHandle failure %u", GetLastError());
+ ret = false;
+ }
}
- // Test it
- TestInterfaceHandle(interface_handle);
- AdbCloseHandle(interface_handle);
- return true;
+ 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);
- AdbCloseHandle(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.
- 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 {
- printf("\n--- AdbGetInterfaceName failure %u", GetLastError());
+ 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 bNumConfigurations = %u", dev_desc.bDescriptorType);
+ 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 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);
- printf("\n setting_index = %u", pipe_info.setting_index);
+ DumpEndpointInformation(&pipe_info);
} else {
- printf("\n--- AdbGetEndpointInformation(%u) failure %u", pipe, GetLastError());
+ 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 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);
- printf("\n setting_index = %u", pipe_info.setting_index);
+ DumpEndpointInformation(&pipe_info);
} else {
- printf("\n--- AdbGetDefaultBulkReadEndpointInformation failure %u", GetLastError());
+ 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 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);
- printf("\n setting_index = %u", pipe_info.setting_index);
+ DumpEndpointInformation(&pipe_info);
} else {
- printf("\n--- AdbGetDefaultBulkWriteEndpointInformation failure %u", GetLastError());
+ 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.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;
+ 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);
+
+ free(buf);
+ }
+
+ 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_;
+};
- printf("\n %s", buf);
+volatile ADBAPIHANDLE g_read_handle;
+volatile ADBAPIHANDLE g_interface_handle;
+volatile bool g_stop_close_race_thread;
- delete buf;
+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;
+}
- AdbCloseHandle(adb_write);
- AdbCloseHandle(adb_read);
+#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);
+ }
+}
- return true;
+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;
}