OSDN Git Service

RootCanal: Desktop simulation envrionment
authorMyles Watson <mylesgw@google.com>
Wed, 13 Feb 2019 20:36:32 +0000 (12:36 -0800)
committerHansong Zhang <hsz@google.com>
Thu, 28 Mar 2019 22:01:10 +0000 (15:01 -0700)
Test: nativetest64/root-canal/root-canal [TEST_PORT] [HCI_PORT] [LINK_PORT]
      python scripts/test_channel.py

Change-Id: I6e57981182c392366d7d97249d837694b49dfa4e

vendor_libs/test_vendor_lib/Android.bp
vendor_libs/test_vendor_lib/desktop/root_canal_main.cc [new file with mode: 0644]
vendor_libs/test_vendor_lib/desktop/test_environment.cc [new file with mode: 0644]
vendor_libs/test_vendor_lib/desktop/test_environment.h [new file with mode: 0644]

index f30795f..2620fb6 100644 (file)
@@ -107,3 +107,35 @@ cc_test_host {
         "-DLOG_NDEBUG=1",
     ],
 }
+
+// Linux RootCanal Executable
+// ========================================================
+cc_test_host {
+    name: "root-canal",
+    defaults: [
+        "libchrome_support_defaults",
+    ],
+    srcs: [
+        "desktop/root_canal_main.cc",
+        "desktop/test_environment.cc",
+    ],
+    header_libs: [
+        "libbluetooth_headers",
+    ],
+    local_include_dirs: [
+        "include",
+    ],
+    include_dirs: [
+        "system/bt",
+        "system/bt/utils/include",
+        "system/bt/hci/include",
+        "system/bt/stack/include",
+    ],
+    shared_libs: [
+        "liblog",
+    ],
+    static_libs: [
+        "libbt-rootcanal-types",
+        "libbt-rootcanal",
+    ],
+}
diff --git a/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc b/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc
new file mode 100644 (file)
index 0000000..5432292
--- /dev/null
@@ -0,0 +1,69 @@
+//
+// Copyright 2017 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.
+//
+
+#define LOG_TAG "root_canal"
+
+#include "test_environment.h"
+
+#include <base/logging.h>
+#include <utils/Log.h>
+#include <future>
+
+#include "hci_internals.h"
+
+using ::android::bluetooth::root_canal::TestEnvironment;
+
+constexpr uint16_t kTestPort = 6401;
+constexpr uint16_t kHciServerPort = 6402;
+constexpr uint16_t kLinkServerPort = 6403;
+
+int main(int argc, char** argv) {
+  ALOGI("main");
+  uint16_t test_port = kTestPort;
+  uint16_t hci_server_port = kHciServerPort;
+  uint16_t link_server_port = kLinkServerPort;
+
+  for (int arg = 0; arg < argc; arg++) {
+    int port = atoi(argv[arg]);
+    ALOGI("%d: %s (%d)", arg, argv[arg], port);
+    if (port < 0 || port > 0xffff) {
+      ALOGW("%s out of range", argv[arg]);
+    } else {
+      switch (arg) {
+        case 0:  // executable name
+          break;
+        case 1:
+          test_port = port;
+          break;
+        case 2:
+          hci_server_port = port;
+          break;
+        case 3:
+          link_server_port = port;
+          break;
+        default:
+          ALOGW("Ignored option %s", argv[arg]);
+      }
+    }
+  }
+
+  TestEnvironment root_canal(test_port, hci_server_port, link_server_port);
+  std::promise<void> barrier;
+  std::future<void> barrier_future = barrier.get_future();
+  root_canal.initialize(std::move(barrier));
+  barrier_future.wait();
+  root_canal.close();
+}
diff --git a/vendor_libs/test_vendor_lib/desktop/test_environment.cc b/vendor_libs/test_vendor_lib/desktop/test_environment.cc
new file mode 100644 (file)
index 0000000..542738d
--- /dev/null
@@ -0,0 +1,178 @@
+//
+// Copyright 2017 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.
+//
+
+#define LOG_TAG "root_canal"
+
+#include "test_environment.h"
+
+#include <base/logging.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <utils/Log.h>
+
+#include "hci_internals.h"
+
+namespace android {
+namespace bluetooth {
+namespace root_canal {
+
+using test_vendor_lib::AsyncTaskId;
+using test_vendor_lib::DualModeController;
+using test_vendor_lib::TaskCallback;
+
+void TestEnvironment::initialize(std::promise<void> barrier) {
+  ALOGI("%s", __func__);
+
+  barrier_ = std::move(barrier);
+
+  test_channel_transport_.RegisterCommandHandler([this](const std::string& name, const std::vector<std::string>& args) {
+    async_manager_.ExecAsync(std::chrono::milliseconds(0),
+                             [this, name, args]() { test_channel_.HandleCommand(name, args); });
+  });
+
+  test_model_.Reset();
+
+  SetUpTestChannel();
+  SetUpHciServer([this](int fd) { test_model_.IncomingHciConnection(fd); });
+  SetUpLinkLayerServer([this](int fd) { test_model_.IncomingLinkLayerConnection(fd); });
+
+  ALOGI("%s: Finished", __func__);
+}
+
+void TestEnvironment::close() {
+  ALOGI("%s", __func__);
+}
+
+void TestEnvironment::SetUpHciServer(const std::function<void(int)>& connection_callback) {
+  int socket_fd = remote_hci_transport_.SetUp(hci_server_port_);
+
+  test_channel_.RegisterSendResponse(
+      [](const std::string& response) { ALOGI("No HCI Response channel: %s", response.c_str()); });
+
+  if (socket_fd == -1) {
+    ALOGE("Remote HCI channel SetUp(%d) failed.", hci_server_port_);
+    return;
+  }
+
+  async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
+    int conn_fd = remote_hci_transport_.Accept(socket_fd);
+    if (conn_fd < 0) {
+      ALOGE("Error watching remote HCI channel fd.");
+      return;
+    }
+    int flags = fcntl(conn_fd, F_GETFL, NULL);
+    int ret;
+    ret = fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
+    CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+
+    connection_callback(conn_fd);
+  });
+}
+
+void TestEnvironment::SetUpLinkLayerServer(const std::function<void(int)>& connection_callback) {
+  int socket_fd = remote_link_layer_transport_.SetUp(link_server_port_);
+
+  test_channel_.RegisterSendResponse(
+      [](const std::string& response) { ALOGI("No LinkLayer Response channel: %s", response.c_str()); });
+
+  if (socket_fd == -1) {
+    ALOGE("Remote LinkLayer channel SetUp(%d) failed.", link_server_port_);
+    return;
+  }
+
+  async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
+    int conn_fd = remote_link_layer_transport_.Accept(socket_fd);
+    if (conn_fd < 0) {
+      ALOGE("Error watching remote LinkLayer channel fd.");
+      return;
+    }
+    int flags = fcntl(conn_fd, F_GETFL, NULL);
+    int ret = fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
+    CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+
+    connection_callback(conn_fd);
+  });
+}
+
+int TestEnvironment::ConnectToRemoteServer(const std::string& server, int port) {
+  int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+  if (socket_fd < 1) {
+    ALOGI("socket() call failed: %s", strerror(errno));
+    return -1;
+  }
+
+  struct hostent* host;
+  host = gethostbyname(server.c_str());
+  if (host == NULL) {
+    ALOGI("gethostbyname() failed for %s: %s", server.c_str(), strerror(errno));
+    return -1;
+  }
+
+  struct sockaddr_in serv_addr;
+  memset((void*)&serv_addr, 0, sizeof(serv_addr));
+  serv_addr.sin_family = AF_INET;
+  serv_addr.sin_addr.s_addr = INADDR_ANY;
+  serv_addr.sin_port = htons(port);
+
+  int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+  if (result < 0) {
+    ALOGI("connect() failed for %s@%d: %s", server.c_str(), port, strerror(errno));
+    return -1;
+  }
+
+  int flags = fcntl(socket_fd, F_GETFL, NULL);
+  int ret = fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
+  CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+
+  return socket_fd;
+}
+
+void TestEnvironment::SetUpTestChannel() {
+  int socket_fd = test_channel_transport_.SetUp(test_port_);
+
+  test_channel_.RegisterSendResponse(
+      [](const std::string& response) { ALOGI("No test channel: %s", response.c_str()); });
+
+  if (socket_fd == -1) {
+    ALOGE("Test channel SetUp(%d) failed.", test_port_);
+    return;
+  }
+
+  ALOGI("Test channel SetUp() successful");
+  async_manager_.WatchFdForNonBlockingReads(socket_fd, [this](int socket_fd) {
+    int conn_fd = test_channel_transport_.Accept(socket_fd);
+    if (conn_fd < 0) {
+      ALOGE("Error watching test channel fd.");
+      barrier_.set_value();
+      return;
+    }
+    ALOGI("Test channel connection accepted.");
+    test_channel_.RegisterSendResponse(
+        [this, conn_fd](const std::string& response) { test_channel_transport_.SendResponse(conn_fd, response); });
+
+    async_manager_.WatchFdForNonBlockingReads(conn_fd, [this](int conn_fd) {
+      test_channel_transport_.OnCommandReady(conn_fd, [this, conn_fd]() {
+        async_manager_.StopWatchingFileDescriptor(conn_fd);
+        barrier_.set_value();
+      });
+    });
+  });
+}
+
+}  // namespace root_canal
+}  // namespace bluetooth
+}  // namespace android
diff --git a/vendor_libs/test_vendor_lib/desktop/test_environment.h b/vendor_libs/test_vendor_lib/desktop/test_environment.h
new file mode 100644 (file)
index 0000000..f48789b
--- /dev/null
@@ -0,0 +1,78 @@
+//
+// Copyright 2017 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.
+//
+
+#pragma once
+
+#include <future>
+
+#include "model/controller/dual_mode_controller.h"
+#include "model/setup/async_manager.h"
+#include "model/setup/test_channel_transport.h"
+#include "model/setup/test_command_handler.h"
+#include "model/setup/test_model.h"
+
+namespace android {
+namespace bluetooth {
+namespace root_canal {
+
+class TestEnvironment {
+ public:
+  TestEnvironment(uint16_t test_port, uint16_t hci_server_port, uint16_t link_server_port)
+      : test_port_(test_port), hci_server_port_(hci_server_port), link_server_port_(link_server_port) {}
+
+  void initialize(std::promise<void> barrier);
+
+  void close();
+
+ private:
+  uint16_t test_port_;
+  uint16_t hci_server_port_;
+  uint16_t link_server_port_;
+  std::promise<void> barrier_;
+
+  test_vendor_lib::AsyncManager async_manager_;
+
+  void SetUpTestChannel();
+  void SetUpHciServer(const std::function<void(int)>& on_connect);
+  void SetUpLinkLayerServer(const std::function<void(int)>& on_connect);
+  int ConnectToRemoteServer(const std::string& server, int port);
+
+  std::shared_ptr<test_vendor_lib::DualModeController> controller_;
+
+  test_vendor_lib::TestChannelTransport test_channel_transport_;
+  test_vendor_lib::TestChannelTransport remote_hci_transport_;
+  test_vendor_lib::TestChannelTransport remote_link_layer_transport_;
+
+  test_vendor_lib::TestModel test_model_{
+      [this](std::chrono::milliseconds delay, const test_vendor_lib::TaskCallback& task) {
+        return async_manager_.ExecAsync(delay, task);
+      },
+
+      [this](std::chrono::milliseconds delay, std::chrono::milliseconds period,
+             const test_vendor_lib::TaskCallback& task) {
+        return async_manager_.ExecAsyncPeriodically(delay, period, task);
+      },
+
+      [this](test_vendor_lib::AsyncTaskId task) { async_manager_.CancelAsyncTask(task); },
+
+      [this](const std::string& server, int port) { return ConnectToRemoteServer(server, port); }};
+
+  test_vendor_lib::TestCommandHandler test_channel_{test_model_};
+};
+
+}  // namespace root_canal
+}  // namespace bluetooth
+}  // namespace android