OSDN Git Service

test_vnd_lib: Discover devices
authorDennis Cheng <dennischeng@google.com>
Fri, 7 Aug 2015 23:58:13 +0000 (16:58 -0700)
committerDennis Cheng <dennischeng@google.com>
Sat, 15 Aug 2015 00:32:03 +0000 (17:32 -0700)
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

vendor_libs/test_vendor_lib/include/dual_mode_controller.h
vendor_libs/test_vendor_lib/include/test_channel_handler.h
vendor_libs/test_vendor_lib/include/test_channel_transport.h
vendor_libs/test_vendor_lib/scripts/test_channel.py
vendor_libs/test_vendor_lib/src/dual_mode_controller.cc
vendor_libs/test_vendor_lib/src/test_channel_handler.cc
vendor_libs/test_vendor_lib/src/test_channel_transport.cc

index 75bcd1d..e7fdba8 100644 (file)
@@ -324,7 +324,19 @@ class DualModeController {
   //           is halted.
   void HciInquiry(const std::vector<std::uint8_t>& args);
 
-  void UciTimeoutAll(const std::vector<std::uint8_t>& args);
+  // Test Channel commands:
+
+  // Clears all test channel modifications.
+  void UciClear(const std::vector<std::string>& args);
+
+  // Discovers a fake device.
+  void UciDiscover(const std::vector<std::string>& args);
+
+  // Discovers a fake device on the specified interval (in ms).
+  void UciDiscoverInterval(const std::vector<std::string>& args);
+
+  // Causes all future HCI commands to timeout.
+  void UciTimeoutAll(const std::vector<std::string>& 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<uint8_t>& 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<void(std::unique_ptr<EventPacket>)> send_event_;
@@ -366,7 +384,7 @@ class DualModeController {
       active_commands_;
 
   std::unordered_map<std::string,
-                     std::function<void(const std::vector<std::uint8_t>&)>>
+                     std::function<void(const std::vector<std::string>&)>>
       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);
 };
 
index 408e47d..0133153 100644 (file)
@@ -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<std::uint8_t> args);
+                         std::vector<std::string> 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<void(const std::vector<std::uint8_t> args)> callback);
+      std::function<void(const std::vector<std::string> 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<std::string,
-                     std::function<void(const std::vector<std::uint8_t> args)> >
+                     std::function<void(const std::vector<std::string> args)> >
       commands_;
 
   DISALLOW_COPY_AND_ASSIGN(TestChannelHandler);
index b0cd2aa..c065ced 100644 (file)
@@ -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<void(std::string, std::vector<std::uint8_t>)> callback);
+      std::function<void(std::string, std::vector<std::string>)> callback);
 
  private:
   // base::MessageLoopForIO::Watcher overrides:
@@ -60,7 +60,7 @@ class TestChannelTransport : public base::MessageLoopForIO::Watcher {
 
   void OnFileCanWriteWithoutBlocking(int fd) override;
 
-  std::function<void(std::string, std::vector<std::uint8_t>)>
+  std::function<void(std::string, std::vector<std::string>)>
       command_handler_;
 
   // File descriptor to watch for test hook data.
index c2abd8f..f505bd3 100644 (file)
@@ -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):
index f5d5f4f..bb5e03f 100644 (file)
@@ -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<uint8_t> rssi = {0};
-  std::vector<uint8_t> extended_inquiry_data = {7, 0x09,
-                                                'F', 'o', 'o', 'B', 'a', 'r'};
+  std::vector<uint8_t> extended_inquiry_data = {name.length() + 1, 0x09};
+  std::copy(name.begin(), name.end(),
+            std::back_inserter(extended_inquiry_data));
+  std::vector<uint8_t> 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<EventPacket> 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<std::uint8_t>& args) {
+void DualModeController::UciClear(const std::vector<std::string>& args) {
+  LogCommand("Uci Clear");
+  test_channel_state_ = kNone;
+}
+
+void DualModeController::UciDiscover(const std::vector<std::string>& 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<std::string>& args) {
+  LogCommand("Uci Timeout All");
+}
+
+void DualModeController::UciTimeoutAll(const std::vector<std::string>& 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<uint8_t>& /* args */) {
       break;
 
     case (kExtendedOrRssiInquiry):
-      SendExtendedInquiryResult();
+      SendExtendedInquiryResult("FooBar", "123456");
       break;
   }
 }
index a30138f..8d6d3cc 100644 (file)
@@ -32,7 +32,7 @@ void TestChannelHandler::RegisterHandlersWithTransport(
 }
 
 void TestChannelHandler::HandleTestCommand(std::string command_name,
-                                           std::vector<uint8_t> args) {
+                                           std::vector<std::string> 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<void(const std::vector<uint8_t> args)> command =
+  std::function<void(const std::vector<std::string> args)> command =
       commands_[command_name];
   command(args);
 }
 
 void TestChannelHandler::RegisterControllerCommand(
     std::string command_name,
-    std::function<void(const std::vector<uint8_t> args)> callback) {
+    std::function<void(const std::vector<std::string> args)> callback) {
   commands_[command_name] = callback;
 }
 
index 4955359..f5a9698 100644 (file)
@@ -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<uint8_t> 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<uint8_t> 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<void(std::string, std::vector<uint8_t>)> callback) {
+    std::function<void(std::string, std::vector<std::string>)> callback) {
   command_handler_ = callback;
 }