blob: 75bf76a8210f614fd53439f02aa7cb985320f7b8 [file] [log] [blame]
/*
* Copyright (C) 2009 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.
*/
// This file contains implementation of a test application that tests
// functionality of AdbWinApi interface. In this test we will use AdbWinApi
// interface in order to enumerate USB interfaces for Android ADB class, and
// for each interface found we will test USB I/O on that interface by sending
// a simple "hand shake" message to the device connected via this interface.
#include "stdafx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// Android ADB interface identifier
const GUID kAdbInterfaceId = ANDROID_USB_CLASS_ID;
// Number of interfaces detected in TestEnumInterfaces.
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_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 */
};
//
// Test routines declarations.
//
// Tests interface enumeration.
bool TestEnumInterfaces();
// Tests all interfaces detected for our device class.
bool TestInterfaces();
// Tests interface addressed by the given device name.
bool TestInterface(const wchar_t* device_name);
// Tests interface opened with ADB API.
bool TestInterfaceHandle(ADBAPIHANDLE interface_handle);
// Sends a "handshake" message to the given 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())
return -1;
if (0 == interface_count) {
printf("\nNo ADB interfaces found. Make sure that device is "
"connected to USB port and is powered on.");
return 1;
}
// Test each interface found in the system
if (!TestInterfaces())
return -2;
// Test for AdbCloseHandle race condition
if (!TestCloseRaceCondition())
return -3;
return 0;
}
bool TestEnumInterfaces() {
// Enumerate interfaces
ADBAPIHANDLE enum_handle =
AdbEnumInterfaces(kAdbInterfaceId, true, true, true);
if (NULL == enum_handle) {
printf("\nEnum 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);
// Enumerate (and count) interfaces, printing information for each found
// interface.
interface_count = 0;
while (AdbNextInterface(enum_handle, &interface_info, &buf_size)) {
interface_count++;
printf("\nFound interface %ws:", interface_info.device_name);
if (interface_info.flags & SPINT_ACTIVE)
printf(" ACTIVE");
if (interface_info.flags & SPINT_DEFAULT)
printf(" DEFAULT");
if (interface_info.flags & SPINT_REMOVED)
printf(" REMOVED");
buf_size = sizeof(buf);
}
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());
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;
}
}
return ret;
}
bool TestInterface(const wchar_t* device_name) {
printf("\n*** Test interface( %ws )", device_name);
// Get ADB handle to the interface by its name
ADBAPIHANDLE interface_handle = AdbCreateInterfaceByName(device_name);
if (NULL == interface_handle) {
printf(" FAILED:\nUnable to create interface by name: %u", GetLastError());
return false;
}
// Test it
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.
if (!TestInterfaceName(interface_handle)) {
return false;
}
// Get device descriptor for the interface
USB_DEVICE_DESCRIPTOR dev_desc;
if (AdbGetUsbDeviceDescriptor(interface_handle, &dev_desc)) {
printf("\n+++ Device descriptor:");
printf("\n bLength = %u", dev_desc.bLength);
printf("\n bDescriptorType = %u", dev_desc.bDescriptorType);
printf("\n bcdUSB = %u", dev_desc.bcdUSB);
printf("\n bDeviceClass = %u", dev_desc.bDeviceClass);
printf("\n bDeviceSubClass = %u", dev_desc.bDeviceSubClass);
printf("\n bDeviceProtocol = %u", dev_desc.bDeviceProtocol);
printf("\n bMaxPacketSize0 = %u", dev_desc.bMaxPacketSize0);
printf("\n idVendor = %X", dev_desc.idVendor);
printf("\n idProduct = %X", dev_desc.idProduct);
printf("\n bcdDevice = %u", dev_desc.bcdDevice);
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.bNumConfigurations);
} else {
printf("\n--- AdbGetUsbDeviceDescriptor failure %u", GetLastError());
return false;
}
// Get configuration descriptor for the interface
USB_CONFIGURATION_DESCRIPTOR config_desc;
if (AdbGetUsbConfigurationDescriptor(interface_handle, &config_desc)) {
printf("\n+++ Configuration descriptor:");
printf("\n bLength = %u", config_desc.bLength);
printf("\n bDescriptorType = %u", config_desc.bDescriptorType);
printf("\n wTotalLength = %u", config_desc.wTotalLength);
printf("\n bNumInterfaces = %u", config_desc.bNumInterfaces);
printf("\n bConfigurationValue = %u", config_desc.bConfigurationValue);
printf("\n iConfiguration = %u", config_desc.iConfiguration);
printf("\n bmAttributes = %u", config_desc.bmAttributes);
printf("\n MaxPower = %u", config_desc.MaxPower);
} else {
printf("\n--- AdbGetUsbConfigurationDescriptor failure %u", GetLastError());
return false;
}
// Get device serial number
char ser_num[1024];
unsigned long ser_num_size = sizeof(ser_num);
if (AdbGetSerialNumber(interface_handle, ser_num, &ser_num_size, true)) {
printf("\n+++ Serial number: %s", ser_num);
} else {
printf("\n--- AdbGetSerialNumber failure %u", GetLastError());
return false;
}
// Get interface descriptor
USB_INTERFACE_DESCRIPTOR intr_desc;
if (AdbGetUsbInterfaceDescriptor(interface_handle, &intr_desc)) {
printf("\n+++ Interface descriptor:");
printf("\n bDescriptorType = %u", intr_desc.bDescriptorType);
printf("\n bInterfaceNumber = %u", intr_desc.bInterfaceNumber);
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());
return false;
}
// Enumerate interface's endpoints
AdbEndpointInformation pipe_info;
for (UCHAR pipe = 0; pipe < intr_desc.bNumEndpoints; pipe++) {
if (AdbGetEndpointInformation(interface_handle, pipe, &pipe_info)) {
printf("\n PIPE %u info:", pipe);
DumpEndpointInformation(&pipe_info);
} else {
printf("\n--- AdbGetEndpointInformation(%u) failure %u", pipe,
GetLastError());
return false;
}
}
// Get default bulk read endpoint info
if (AdbGetDefaultBulkReadEndpointInformation(interface_handle, &pipe_info)) {
printf("\n Default Bulk Read Pipe info:");
DumpEndpointInformation(&pipe_info);
} 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:");
DumpEndpointInformation(&pipe_info);
} else {
printf("\n--- AdbGetDefaultBulkWriteEndpointInformation failure %u",
GetLastError());
return false;
}
// Test a handshake on that interface
DeviceHandShake(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];
unsigned long name_size = sizeof(interf_name);
if (!AdbGetInterfaceName(adb_interface, interf_name, &name_size, true)) {
printf("\nDeviceHandShake: AdbGetInterfaceName returned error %u",
GetLastError());
return false;
}
printf("\n\nDeviceHandShake on %s", interf_name);
char* ser_num = NULL;
name_size = 0;
if (!AdbGetSerialNumber(adb_interface, ser_num, &name_size, true)) {
ser_num = reinterpret_cast<char*>(malloc(name_size));
if (NULL != ser_num) {
if (!AdbGetSerialNumber(adb_interface, ser_num, &name_size, true)) {
printf("\n AdbGetSerialNumber returned error %u", GetLastError());
AdbCloseHandle(adb_interface);
return false;
}
printf("\nInterface serial number is %s", ser_num);
free(ser_num);
}
}
// Get default read endpoint
ADBAPIHANDLE adb_read = AdbOpenDefaultBulkReadEndpoint(adb_interface,
AdbOpenAccessTypeReadWrite,
AdbOpenSharingModeReadWrite);
if (NULL == adb_read) {
printf("\n AdbOpenDefaultBulkReadEndpoint returned error %u", GetLastError());
return false;
}
// Get default write endpoint
ADBAPIHANDLE adb_write = AdbOpenDefaultBulkWriteEndpoint(adb_interface,
AdbOpenAccessTypeReadWrite,
AdbOpenSharingModeReadWrite);
if (NULL == adb_write) {
printf("\n AdbOpenDefaultBulkWriteEndpoint returned error %u", GetLastError());
AdbCloseHandle(adb_read);
return false;
}
// 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;
ULONG written_bytes = 0;
bool write_res = AdbWriteEndpointSync(adb_write, &msg_send, sizeof(msg_send), &written_bytes, 500);
if (!write_res) {
printf("\n AdbWriteEndpointSync returned error %u", GetLastError());
AdbCloseHandle(adb_write);
AdbCloseHandle(adb_read);
return false;
}
// Receive handshake
message msg_rcv;
ULONG read_bytes = 0;
bool read_res = AdbReadEndpointSync(adb_read, &msg_rcv, sizeof(msg_rcv), &read_bytes, 512);
if (!read_res) {
printf("\n AdbReadEndpointSync returned error %u", GetLastError());
AdbCloseHandle(adb_write);
AdbCloseHandle(adb_read);
return false;
}
printf("\n Read handshake: %u bytes received", read_bytes);
char* cmd_ansi = reinterpret_cast<char*>(&msg_rcv.command);
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));
read_res = AdbReadEndpointSync(adb_read, buf, msg_rcv.data_length, &read_bytes, 512);
if (!read_res) {
printf("\n AdbReadEndpointSync (data) returned error %u", GetLastError());
free(buf);
AdbCloseHandle(adb_write);
AdbCloseHandle(adb_read);
return false;
}
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_;
};
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;
}