From: Dennis Cheng Date: Fri, 7 Aug 2015 23:58:13 +0000 (-0700) Subject: test_vnd_lib: Discover devices X-Git-Tag: android-x86-7.1-r1~394^2~216^2~30 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=f1548336;p=android-x86%2Fsystem-bt.git test_vnd_lib: Discover devices This upload allows the user to send fake inquiry responses to the controller at run-time via the test channel. Bug: 21586676 Change-Id: Ieae24d496115f19716fcaaffa627a9c22ffade21 --- diff --git a/vendor_libs/test_vendor_lib/include/dual_mode_controller.h b/vendor_libs/test_vendor_lib/include/dual_mode_controller.h index 75bcd1def..e7fdba869 100644 --- a/vendor_libs/test_vendor_lib/include/dual_mode_controller.h +++ b/vendor_libs/test_vendor_lib/include/dual_mode_controller.h @@ -324,7 +324,19 @@ class DualModeController { // is halted. void HciInquiry(const std::vector& args); - void UciTimeoutAll(const std::vector& args); + // Test Channel commands: + + // Clears all test channel modifications. + void UciClear(const std::vector& args); + + // Discovers a fake device. + void UciDiscover(const std::vector& args); + + // Discovers a fake device on the specified interval (in ms). + void UciDiscoverInterval(const std::vector& args); + + // Causes all future HCI commands to timeout. + void UciTimeoutAll(const std::vector& args); private: enum State { @@ -335,6 +347,11 @@ class DualModeController { kConnection, // In a connection. }; + enum TestChannelState { + kNone, // The controller is running normally. + kTimeoutAll, // All commands should time out, i.e. send no response. + }; + // Creates a command complete event and sends it back to the HCI. void SendCommandComplete(uint16_t command_opcode, const std::vector& return_parameters) const; @@ -353,7 +370,8 @@ class DualModeController { void SendInquiryResult() const; // Sends an extended inquiry response for a fake device. - void SendExtendedInquiryResult() const; + void SendExtendedInquiryResult(const std::string& name, + const std::string& address) const; // Callback provided to send events from the controller back to the HCI. std::function)> send_event_; @@ -366,7 +384,7 @@ class DualModeController { active_commands_; std::unordered_map&)>> + std::function&)>> test_channel_active_commands_; // Specifies the format of Inquiry Result events to be returned during the @@ -380,6 +398,8 @@ class DualModeController { // Current link layer state of the controller. State state_; + TestChannelState test_channel_state_; + DISALLOW_COPY_AND_ASSIGN(DualModeController); }; diff --git a/vendor_libs/test_vendor_lib/include/test_channel_handler.h b/vendor_libs/test_vendor_lib/include/test_channel_handler.h index 408e47dfc..01331530b 100644 --- a/vendor_libs/test_vendor_lib/include/test_channel_handler.h +++ b/vendor_libs/test_vendor_lib/include/test_channel_handler.h @@ -37,14 +37,14 @@ class TestChannelHandler { // Callback to be fired when a command is received from the test channel. void HandleTestCommand(std::string command_name, - std::vector args); + std::vector args); // Creates the mapping from the |command_name| to the method |callback|, // which is provided by the controller and will be fired when its command is // received from the test channel. void RegisterControllerCommand( std::string command_name, - std::function args)> callback); + std::function args)> callback); void RegisterHandlersWithTransport(TestChannelTransport& transport); @@ -52,7 +52,7 @@ class TestChannelHandler { // Controller callbacks to be executed in handlers and registered in // RegisterControllerCommand(). std::unordered_map args)> > + std::function args)> > commands_; DISALLOW_COPY_AND_ASSIGN(TestChannelHandler); diff --git a/vendor_libs/test_vendor_lib/include/test_channel_transport.h b/vendor_libs/test_vendor_lib/include/test_channel_transport.h index b0cd2aa7f..c065cedc9 100644 --- a/vendor_libs/test_vendor_lib/include/test_channel_transport.h +++ b/vendor_libs/test_vendor_lib/include/test_channel_transport.h @@ -52,7 +52,7 @@ class TestChannelTransport : public base::MessageLoopForIO::Watcher { // Sets the callback that fires when data is read in // |OnFileCanReadWithoutBlocking|. void RegisterCommandHandler( - std::function)> callback); + std::function)> callback); private: // base::MessageLoopForIO::Watcher overrides: @@ -60,7 +60,7 @@ class TestChannelTransport : public base::MessageLoopForIO::Watcher { void OnFileCanWriteWithoutBlocking(int fd) override; - std::function)> + std::function)> command_handler_; // File descriptor to watch for test hook data. diff --git a/vendor_libs/test_vendor_lib/scripts/test_channel.py b/vendor_libs/test_vendor_lib/scripts/test_channel.py index c2abd8fa1..f505bd37b 100644 --- a/vendor_libs/test_vendor_lib/scripts/test_channel.py +++ b/vendor_libs/test_vendor_lib/scripts/test_channel.py @@ -35,7 +35,7 @@ Usage: the port, also from step 1, as arguments. """ -#!/ usr / bin / env python +#!/usr/bin/env python import cmd import random @@ -44,6 +44,18 @@ import string import struct import sys +DEVICE_NAME_LENGTH = 6 +DEVICE_ADDRESS_LENGTH = 6 + +# Used to generate fake device names and addresses during discovery. +def generate_random_name(): + return ''.join(random.SystemRandom().choice(string.ascii_uppercase + \ + string.digits) for _ in range(DEVICE_NAME_LENGTH)) + +def generate_random_address(): + return ''.join(random.SystemRandom().choice(string.digits) for _ in \ + range(DEVICE_ADDRESS_LENGTH)) + class Connection(object): """Simple wrapper class for a socket object. @@ -71,6 +83,12 @@ class TestChannel(object): def __init__(self, address, port): self._connection = Connection(address, port) + self._discovered_devices = DeviceManager() + + def discover_new_device(self, name=None, address=None): + device = Device(name, address) + self._discovered_devices.add_device(device) + return device def close(self): self._connection.close() @@ -99,6 +117,40 @@ class TestChannel(object): if len(arg) > 255: raise ValueError # Size must be encodable in one octet. +class DeviceManager(object): + """Maintains the active fake devices that have been "discovered". + + Attributes: + device_list: Maps device addresses (keys) to devices (values). + """ + + def __init__(self): + self.device_list = {} + + def add_device(self, device): + self.device_list[device.get_address()] = device + +class Device(object): + """A fake device to be returned in inquiry and scan results. Note that if an + explicit name or address is not provided, a random string of characters + is used. + + Attributes: + name: The device name for use in extended results. + address: The BD address of the device. + """ + + def __init__(self, name=None, address=None): + # TODO(dennischeng): Generate device properties more robustly. + self.name = generate_random_name() if name is None else name + self.address = generate_random_address() if address is None else address + + def get_name(self): + return self.name + + def get_address(self): + return self.address + class TestChannelShell(cmd.Cmd): """Shell for sending test channel data to controller. @@ -139,10 +191,14 @@ class TestChannelShell(cmd.Cmd): random name is used instead. """ if len(args) == 0: - # TODO(dennischeng): Generate device properties more robustly. - args = ''.join(random.SystemRandom().choice(string.ascii_uppercase + \ - string.digits) for _ in range(6)) - self._test_channel.send_command('DISCOVER', args.split()) + args = generate_random_name() + device_list = [self.test_channel.discover_new_device(arg) for arg in \ + args.split()] + device_names_and_addresses = [] + for device in device_list: + device_names_and_addresses.append(device.get_name()) + device_names_and_addresses.append(device.get_address()) + self._test_channel.send_command('DISCOVER', device_names_and_addresses) def do_discover_interval(self, args): """ @@ -150,6 +206,8 @@ class TestChannelShell(cmd.Cmd): Sends an inquiry result for a device with a random name on the interval specified by |interval_in_ms|. """ + args.append(generate_random_name()) + args.append(generate_random_address()) self._test_channel.send_command('DISCOVER_INTERVAL', args.split()) def do_clear(self, args): diff --git a/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc b/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc index f5d5f4ff1..bb5e03fb3 100644 --- a/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc +++ b/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc @@ -156,22 +156,26 @@ void DualModeController::SendInquiryResult() const { send_event_(std::move(inquiry_result)); } -void DualModeController::SendExtendedInquiryResult() const { +void DualModeController::SendExtendedInquiryResult( + const std::string& name, const std::string& address) const { std::vector rssi = {0}; - std::vector extended_inquiry_data = {7, 0x09, - 'F', 'o', 'o', 'B', 'a', 'r'}; + std::vector extended_inquiry_data = {name.length() + 1, 0x09}; + std::copy(name.begin(), name.end(), + std::back_inserter(extended_inquiry_data)); + std::vector bd_address(address.begin(), address.end()); // TODO(dennischeng): Use constants for parameter sizes, here and elsewhere. while (extended_inquiry_data.size() < 240) { extended_inquiry_data.push_back(0); } std::unique_ptr extended_inquiry_result = EventPacket::CreateExtendedInquiryResultEvent( - kOtherDeviceBdAddress, kPageScanRepetitionMode, kPageScanPeriodMode, - kClassOfDevice, kClockOffset, rssi, extended_inquiry_data); + bd_address, kPageScanRepetitionMode, kPageScanPeriodMode, kClassOfDevice, + kClockOffset, rssi, extended_inquiry_data); send_event_(std::move(extended_inquiry_result)); } -DualModeController::DualModeController() : state_(kStandby) { +DualModeController::DualModeController() + : state_(kStandby), test_channel_state_(kNone) { #define SET_HANDLER(opcode, method) \ active_commands_[opcode] = \ std::bind(&DualModeController::method, this, std::placeholders::_1); @@ -205,7 +209,10 @@ DualModeController::DualModeController() : state_(kStandby) { #define SET_TEST_HANDLER(command_name, method) \ test_channel_active_commands_[command_name] = \ std::bind(&DualModeController::method, this, std::placeholders::_1); - SET_TEST_HANDLER("TimeoutAll", UciTimeoutAll); + SET_TEST_HANDLER("CLEAR", UciTimeoutAll); + SET_TEST_HANDLER("DISCOVER", UciDiscover); + SET_TEST_HANDLER("DISCOVER_INTERVAL", UciTimeoutAll); + SET_TEST_HANDLER("TIMEOUT_ALL", UciTimeoutAll); #undef SET_TEST_HANDLER } @@ -228,8 +235,26 @@ void DualModeController::RegisterEventChannel( send_event_ = callback; } -void DualModeController::UciTimeoutAll(const std::vector& args) { +void DualModeController::UciClear(const std::vector& args) { + LogCommand("Uci Clear"); + test_channel_state_ = kNone; +} + +void DualModeController::UciDiscover(const std::vector& args) { + LogCommand("Uci Discover"); + for (size_t i = 0; i < args.size()-1; i+=2) { + SendExtendedInquiryResult(args[i], args[i+1]); + } +} + +void DualModeController::UciDiscoverInterval( + const std::vector& args) { + LogCommand("Uci Timeout All"); +} + +void DualModeController::UciTimeoutAll(const std::vector& args) { LogCommand("Uci Timeout All"); + test_channel_state_ = kTimeoutAll; } // TODO(dennischeng): Store relevant arguments from commands as attributes of @@ -405,7 +430,7 @@ void DualModeController::HciInquiry(const std::vector& /* args */) { break; case (kExtendedOrRssiInquiry): - SendExtendedInquiryResult(); + SendExtendedInquiryResult("FooBar", "123456"); break; } } diff --git a/vendor_libs/test_vendor_lib/src/test_channel_handler.cc b/vendor_libs/test_vendor_lib/src/test_channel_handler.cc index a30138fcf..8d6d3cca2 100644 --- a/vendor_libs/test_vendor_lib/src/test_channel_handler.cc +++ b/vendor_libs/test_vendor_lib/src/test_channel_handler.cc @@ -32,7 +32,7 @@ void TestChannelHandler::RegisterHandlersWithTransport( } void TestChannelHandler::HandleTestCommand(std::string command_name, - std::vector args) { + std::vector args) { LOG_INFO(LOG_TAG, "Test Channel command: %s", command_name.c_str()); // The command hasn't been registered with the handler yet. There is nothing @@ -40,14 +40,14 @@ void TestChannelHandler::HandleTestCommand(std::string command_name, if (commands_.count(command_name) == 0) { return; } - std::function args)> command = + std::function args)> command = commands_[command_name]; command(args); } void TestChannelHandler::RegisterControllerCommand( std::string command_name, - std::function args)> callback) { + std::function args)> callback) { commands_[command_name] = callback; } diff --git a/vendor_libs/test_vendor_lib/src/test_channel_transport.cc b/vendor_libs/test_vendor_lib/src/test_channel_transport.cc index 4955359a8..f5a96986e 100644 --- a/vendor_libs/test_vendor_lib/src/test_channel_transport.cc +++ b/vendor_libs/test_vendor_lib/src/test_channel_transport.cc @@ -92,15 +92,14 @@ void TestChannelTransport::OnFileCanReadWithoutBlocking(int fd) { LOG_INFO(LOG_TAG, "Event ready in TestChannelTransport on fd: %d", fd); uint8_t command_name_size = 0; read(fd, &command_name_size, 1); - LOG_INFO(LOG_TAG, "command_name_size: %d", command_name_size); - std::vector command_name; - command_name.resize(command_name_size); - read(fd, &command_name[0], command_name_size); - std::string command_name_str(command_name.begin(), command_name.end()); + std::vector command_name_raw; + command_name_raw.resize(command_name_size); + read(fd, &command_name_raw[0], command_name_size); + std::string command_name(command_name_raw.begin(), command_name_raw.end()); LOG_INFO(LOG_TAG, "Received command from test channel: %s", - command_name_str.c_str()); + command_name.c_str()); - if (command_name_str == "CLOSE_TEST_CHANNEL") { + if (command_name == "CLOSE_TEST_CHANNEL") { fd_.reset(nullptr); return; } @@ -122,12 +121,13 @@ void TestChannelTransport::OnFileCanReadWithoutBlocking(int fd) { LOG_INFO(LOG_TAG, "Command argument %d: %s", i, args[i].c_str()); } + command_handler_(command_name, args); } void TestChannelTransport::OnFileCanWriteWithoutBlocking(int fd) {} void TestChannelTransport::RegisterCommandHandler( - std::function)> callback) { + std::function)> callback) { command_handler_ = callback; }