Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45253cbf authored by Hansong Zhang's avatar Hansong Zhang
Browse files

HCI HAL adapter: separate initialization and set_callback

Test: run bluetooth_test_gd

Change-Id: I1275be3020e34c56e0ef439e0f748db127d9f8e2
parent 36fd29e5
Loading
Loading
Loading
Loading
+27 −9
Original line number Diff line number Diff line
@@ -25,17 +25,16 @@ using HciPacket = std::vector<uint8_t>;

enum class Status : int32_t { SUCCESS, TRANSPORT_ERROR, INITIALIZATION_ERROR, UNKNOWN };

// Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHciCallbacks.hal in Android
// Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHciCallbacks.hal in Android, but moved initializationComplete
// callback to BluetoothInitializationCompleteCallback

// The interface from the Bluetooth Controller to the stack
class BluetoothHciHalCallbacks {
 public:
  virtual ~BluetoothHciHalCallbacks() = default;

  // Invoked when the Bluetooth controller initialization has been completed
  virtual void initializationComplete(Status status) = 0;

  // This function is invoked when an HCI event is received from the Bluetooth controller to be forwarded to the
  // Bluetooth stack
  // This function is invoked when an HCI event is received from the
  // Bluetooth controller to be forwarded to the Bluetooth stack
  // @param event is the HCI event to be sent to the Bluetooth stack
  virtual void hciEventReceived(HciPacket event) = 0;

@@ -48,6 +47,15 @@ class BluetoothHciHalCallbacks {
  virtual void scoDataReceived(HciPacket data) = 0;
};

// Callback for BluetoothHciHal::initialize()
class BluetoothInitializationCompleteCallback {
 public:
  virtual ~BluetoothInitializationCompleteCallback() = default;

  // Invoked when the Bluetooth controller initialization has been completed
  virtual void initializationComplete(Status status) = 0;
};

// Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHci.hal in Android
// The Host Controller Interface (HCI) is the layer defined by the Bluetooth
// specification between the software that runs on the host and the Bluetooth
@@ -65,15 +73,25 @@ class BluetoothHciHal {
  // required to communicate with the Bluetooth hardware in the
  // device.
  //
  // The |oninitializationComplete| callback must be invoked in response
  // The |InitializationCompleteCallback| callback must be invoked in response
  // to this function to indicate success before any other function
  // (sendHciCommand, sendAclData, * sendScoData) is invoked on this
  // interface.
  //
  // @param callback implements IBluetoothHciCallbacks which will
  // @param callback implements BluetoothInitializationCompleteCallback which will
  //    receive callbacks when incoming HCI initialization is complete
  virtual void initialize(BluetoothInitializationCompleteCallback* callback) = 0;

  // Register the callback for incoming packets. All incoming packets are dropped before
  // this callback is registered. Callback can only be registered once, but will be reset
  // after close().
  //
  // Call this function before initialize() to guarantee all incoming packets are received.
  //
  // @param callback implements BluetoothHciHalCallbacks which will
  //    receive callbacks when incoming HCI packets are received
  //    from the controller to be sent to the host.
  virtual void initialize(BluetoothHciHalCallbacks* callback) = 0;
  virtual void registerIncomingPacketCallback(BluetoothHciHalCallbacks* callback) = 0;

  // Send an HCI command (as specified in the Bluetooth Specification
  // V4.2, Vol 2, Part 5, Section 5.4.1) to the Bluetooth controller.
+32 −9
Original line number Diff line number Diff line
@@ -47,38 +47,55 @@ android::sp<BluetoothHciDeathRecipient> bluetooth_hci_death_recipient_ = new Blu

class HciHalBluetoothHciCallbacks : public IBluetoothHciCallbacks {
 public:
  HciHalBluetoothHciCallbacks(BluetoothHciHalCallbacks* callback) : callback_(callback) {}
  HciHalBluetoothHciCallbacks(BluetoothInitializationCompleteCallback* initialization_callback)
      : initialization_callback_(initialization_callback) {}

  void SetCallback(BluetoothHciHalCallbacks* callback) {
    ASSERT(callback_ == nullptr && callback != nullptr);
    callback_ = callback;
  }

  void ResetCallback() {
    callback_ = nullptr;
  }

  Return<void> initializationComplete(HidlStatus status) {
    ASSERT(status == HidlStatus::SUCCESS);
    callback_->initializationComplete(Status::SUCCESS);
    initialization_callback_->initializationComplete(Status::SUCCESS);
    return Void();
  }

  Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
    if (callback_ != nullptr) {
      callback_->hciEventReceived(std::vector<uint8_t>(event.begin(), event.end()));
    }
    return Void();
  }

  Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
    if (callback_ != nullptr) {
      callback_->aclDataReceived(std::vector<uint8_t>(data.begin(), data.end()));
    }
    return Void();
  }

  Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
    if (callback_ != nullptr) {
      callback_->scoDataReceived(std::vector<uint8_t>(data.begin(), data.end()));
    }
    return Void();
  }

 private:
  BluetoothHciHalCallbacks* callback_;
  BluetoothInitializationCompleteCallback* initialization_callback_ = nullptr;
  BluetoothHciHalCallbacks* callback_ = nullptr;
};

}  // namespace

class BluetoothHciHalHidl : public BluetoothHciHal {
 public:
  void initialize(BluetoothHciHalCallbacks* callback) override {
  void initialize(BluetoothInitializationCompleteCallback* callback) override {
    bt_hci_ = IBluetoothHci::getService();
    ASSERT(bt_hci_ != nullptr);
    auto death_link = bt_hci_->linkToDeath(bluetooth_hci_death_recipient_, 0);
@@ -86,11 +103,15 @@ class BluetoothHciHalHidl : public BluetoothHciHal {

    // Block allows allocation of a variable that might be bypassed by goto.
    {
      android::sp<IBluetoothHciCallbacks> callbacks = new HciHalBluetoothHciCallbacks(callback);
      bt_hci_->initialize(callbacks);
      callbacks_ = new HciHalBluetoothHciCallbacks(callback);
      bt_hci_->initialize(callbacks_);
    }
  }

  void registerIncomingPacketCallback(BluetoothHciHalCallbacks* callback) override {
    callbacks_->SetCallback(callback);
  }

  void sendHciCommand(HciPacket command) override {
    bt_hci_->sendHciCommand(command);
  }
@@ -110,10 +131,12 @@ class BluetoothHciHalHidl : public BluetoothHciHal {
      LOG_ERROR("Error unlinking death recipient from the Bluetooth HAL");
    }
    bt_hci_->close();
    callbacks_->ResetCallback();
    bt_hci_ = nullptr;
  }

 private:
  android::sp<HciHalBluetoothHciCallbacks> callbacks_;
  android::sp<IBluetoothHci> bt_hci_;
};

+19 −9
Original line number Diff line number Diff line
/*
 * Copyright 2019 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.
 */

#include "hal/hci_hal.h"

#include <chrono>
@@ -11,18 +27,12 @@ namespace {

std::promise<void>* g_promise;

class TestBluetoothHciHalCallbacks : public BluetoothHciHalCallbacks {
class TestBluetoothInitializationCompleteCallback : public BluetoothInitializationCompleteCallback {
 public:
  void initializationComplete(Status status) override {
    EXPECT_EQ(status, Status::SUCCESS);
    g_promise->set_value();
  }

  void hciEventReceived(HciPacket) override {}

  void aclDataReceived(HciPacket) override {}

  void scoDataReceived(HciPacket) override {}
};

class HciHalHidlTest : public ::testing::Test {
@@ -30,7 +40,7 @@ class HciHalHidlTest : public ::testing::Test {
  void SetUp() override {
    g_promise = new std::promise<void>;
    hal_ = GetBluetoothHciHal();
    hal_->initialize(&callbacks_);
    hal_->initialize(&init_callback_);
  }

  void TearDown() override {
@@ -40,7 +50,7 @@ class HciHalHidlTest : public ::testing::Test {
  }

  BluetoothHciHal* hal_ = nullptr;
  TestBluetoothHciHalCallbacks callbacks_;
  TestBluetoothInitializationCompleteCallback init_callback_;
};

TEST_F(HciHalHidlTest, init_and_close) {
+31 −23
Original line number Diff line number Diff line
@@ -19,20 +19,17 @@

#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <mutex>
#include <queue>
#include <string>

#include "os/log.h"
#include "os/reactor.h"
#include "os/thread.h"

namespace {
constexpr int INVALID_FD = -1;

constexpr uint8_t kH4Command = 0x01;
constexpr uint8_t kH4Acl = 0x02;
constexpr uint8_t kH4Sco = 0x03;
@@ -48,14 +45,14 @@ int ConnectToRootCanal(const std::string& server, int port) {
  int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (socket_fd < 1) {
    LOG_ERROR("can't create socket: %s", strerror(errno));
    return -1;
    return INVALID_FD;
  }

  struct hostent* host;
  host = gethostbyname(server.c_str());
  if (host == nullptr) {
    LOG_ERROR("can't get server name");
    return -1;
    return INVALID_FD;
  }

  struct sockaddr_in serv_addr;
@@ -67,14 +64,14 @@ int ConnectToRootCanal(const std::string& server, int port) {
  int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
  if (result < 0) {
    LOG_ERROR("can't connect: %s", strerror(errno));
    return -1;
    return INVALID_FD;
  }

  int flags = fcntl(socket_fd, F_GETFL, NULL);
  int ret = fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
  if (ret == -1) {
    LOG_ERROR("can't control socket fd: %s", strerror(errno));
    return -1;
    return INVALID_FD;
  }
  return socket_fd;
}
@@ -85,20 +82,26 @@ namespace hal {

class BluetoothHciHalHostRootcanal : public BluetoothHciHal {
 public:
  void initialize(BluetoothHciHalCallbacks* callback) override {
  void initialize(BluetoothInitializationCompleteCallback* callback) override {
    std::lock_guard<std::mutex> lock(mutex_);
    ASSERT(callback_ == nullptr && callback != nullptr);
    ASSERT(sock_fd_ == INVALID_FD && callback != nullptr);
    sock_fd_ = ConnectToRootCanal(config_->GetServerAddress(), config_->GetPort());
    ASSERT(sock_fd_ != INVALID_FD);
    reactable_ =
        hci_incoming_thread_.GetReactor()->Register(sock_fd_, [this]() { this->incoming_packet_received(); }, nullptr);
    callback_ = callback;
    callback->initializationComplete(Status::SUCCESS);
    LOG_INFO("Rootcanal HAL opened successfully");
  }

  void registerIncomingPacketCallback(BluetoothHciHalCallbacks* callback) override {
    std::lock_guard<std::mutex> lock(mutex_);
    ASSERT(incoming_packet_callback_ == nullptr && callback != nullptr);
    incoming_packet_callback_ = callback;
  }

  void sendHciCommand(HciPacket command) override {
    std::lock_guard<std::mutex> lock(mutex_);
    ASSERT(callback_ != nullptr);
    ASSERT(sock_fd_ != INVALID_FD);
    std::vector<uint8_t> packet = std::move(command);
    packet.insert(packet.cbegin(), kH4Command);
    write_to_rootcanal_fd(packet);
@@ -106,7 +109,7 @@ class BluetoothHciHalHostRootcanal : public BluetoothHciHal {

  void sendAclData(HciPacket data) override {
    std::lock_guard<std::mutex> lock(mutex_);
    ASSERT(callback_ != nullptr);
    ASSERT(sock_fd_ != INVALID_FD);
    std::vector<uint8_t> packet = std::move(data);
    packet.insert(packet.cbegin(), kH4Acl);
    write_to_rootcanal_fd(packet);
@@ -114,7 +117,7 @@ class BluetoothHciHalHostRootcanal : public BluetoothHciHal {

  void sendScoData(HciPacket data) override {
    std::lock_guard<std::mutex> lock(mutex_);
    ASSERT(callback_ != nullptr);
    ASSERT(sock_fd_ != INVALID_FD);
    std::vector<uint8_t> packet = std::move(data);
    packet.insert(packet.cbegin(), kH4Sco);
    write_to_rootcanal_fd(packet);
@@ -122,19 +125,22 @@ class BluetoothHciHalHostRootcanal : public BluetoothHciHal {

  void close() override {
    std::lock_guard<std::mutex> lock(mutex_);
    ASSERT(callback_ != nullptr);
    if (reactable_ != nullptr) {
      hci_incoming_thread_.GetReactor()->Unregister(reactable_);
      ASSERT(sock_fd_ != INVALID_FD);
    }
    reactable_ = nullptr;
    callback_ = nullptr;
    incoming_packet_callback_ = nullptr;
    ::close(sock_fd_);
    sock_fd_ = INVALID_FD;
    LOG_INFO("Rootcanal HAL is closed");
  }

 private:
  std::mutex mutex_;
  HciHalHostRootcanalConfig* config_ = HciHalHostRootcanalConfig::Get();
  BluetoothHciHalCallbacks* callback_ = nullptr;
  int sock_fd_ = 0;
  BluetoothHciHalCallbacks* incoming_packet_callback_ = nullptr;
  int sock_fd_ = INVALID_FD;
  bluetooth::os::Thread hci_incoming_thread_ =
      bluetooth::os::Thread("hci_incoming_thread", bluetooth::os::Thread::Priority::NORMAL);
  bluetooth::os::Reactor::Reactable* reactable_ = nullptr;
@@ -163,6 +169,8 @@ class BluetoothHciHalHostRootcanal : public BluetoothHciHal {
  }

  void incoming_packet_received() {
    ASSERT(incoming_packet_callback_ != nullptr);

    uint8_t buf[kBufSize] = {};

    ssize_t received_size;
@@ -188,7 +196,7 @@ class BluetoothHciHalHostRootcanal : public BluetoothHciHal {

      HciPacket receivedHciPacket;
      receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciEvtHeaderSize + payload_size);
      callback_->hciEventReceived(receivedHciPacket);
      incoming_packet_callback_->hciEventReceived(receivedHciPacket);
    }

    if (buf[0] == kH4Acl) {
@@ -204,7 +212,7 @@ class BluetoothHciHalHostRootcanal : public BluetoothHciHal {

      HciPacket receivedHciPacket;
      receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciAclHeaderSize + payload_size);
      callback_->aclDataReceived(receivedHciPacket);
      incoming_packet_callback_->aclDataReceived(receivedHciPacket);
    }

    if (buf[0] == kH4Sco) {
@@ -217,7 +225,7 @@ class BluetoothHciHalHostRootcanal : public BluetoothHciHal {

      HciPacket receivedHciPacket;
      receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciScoHeaderSize + payload_size);
      callback_->scoDataReceived(receivedHciPacket);
      incoming_packet_callback_->scoDataReceived(receivedHciPacket);
    }
    memset(buf, 0, kBufSize);
  }
+7 −2
Original line number Diff line number Diff line
@@ -50,12 +50,15 @@ using H4Packet = std::vector<uint8_t>;

std::queue<std::pair<uint8_t, HciPacket>> incoming_packets_queue_;

class TestBluetoothHciHalCallbacks : public BluetoothHciHalCallbacks {
class TestBluetoothInitializationCompleteCallback : public BluetoothInitializationCompleteCallback {
 public:
  void initializationComplete(Status status) override {
    EXPECT_EQ(status, Status::SUCCESS);
  }
};

class TestBluetoothHciHalCallbacks : public BluetoothHciHalCallbacks {
 public:
  void hciEventReceived(HciPacket packet) override {
    incoming_packets_queue_.emplace(kH4Event, packet);
  }
@@ -139,7 +142,8 @@ class HciHalRootcanalTest : public ::testing::Test {
    HciHalHostRootcanalConfig::Get()->SetPort(kTestPort);
    fake_server_ = new FakeRootcanalDesktopHciServer;
    hal_ = GetBluetoothHciHal();
    hal_->initialize(&callbacks_);
    hal_->initialize(&init_callback_);
    hal_->registerIncomingPacketCallback(&callbacks_);
    fake_server_socket_ = fake_server_->Accept();  // accept() after client is connected to avoid blocking
    std::queue<std::pair<uint8_t, HciPacket>> empty;
    std::swap(incoming_packets_queue_, empty);
@@ -159,6 +163,7 @@ class HciHalRootcanalTest : public ::testing::Test {

  FakeRootcanalDesktopHciServer* fake_server_ = nullptr;
  BluetoothHciHal* hal_ = nullptr;
  TestBluetoothInitializationCompleteCallback init_callback_;
  TestBluetoothHciHalCallbacks callbacks_;
  int fake_server_socket_ = -1;
};