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

Commit a7145655 authored by Hansong Zhang's avatar Hansong Zhang Committed by Automerger Merge Worker
Browse files

Add a way to connect to linux raw HCI HAL am: 75dcbe16 am: 75811200

Original change: https://android-review.googlesource.com/c/platform/system/bt/+/1617700

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I8053d69b08a1e3f2e47c3a45842199198c0c4f21
parents d544ccc7 75811200
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -126,7 +126,7 @@ cc_defaults {
        host: {
            srcs: [
                ":BluetoothBtaaSources_host",
                ":BluetoothHalSources_hci_rootcanal",
                ":BluetoothHalSources_hci_host",
                ":BluetoothOsSources_host",
            ],
        },
@@ -295,7 +295,7 @@ cc_test {
        },
        host: {
            srcs: [
                ":BluetoothHalTestSources_hci_rootcanal",
                ":BluetoothHalTestSources_hci_host",
                ":BluetoothOsTestSources_host",
            ],
        },
+4 −4
Original line number Diff line number Diff line
@@ -113,10 +113,10 @@ Root directory under Android tree:
    *   hci_hal_android_hidl.cc: implementation of hci_hal.h using Android HIDL
    *   hci_hal_android_hidl_test.cc: unit tests for the Android HIDL
        implementation
    *   hci_hal_host_rootcanal.cc: implementation of hci_hal.h using root-canal
        emulator
    *   hci_hal_host_rootcanal_test.cc: unit tests for the root-canal emulator
        implementation
    *   hci_hal_host.cc: implementation of hci_hal.h using root-canal
        emulator or linux Bluetooth HCI socket
    *   hci_hal_host_test.cc: unit tests for the socket based HAL (root-canal)
        emulator implementation
    *   facade.proto: gRPC automation interface definition for this layer
    *   facade.h/cc: an implementation of the above gRPC interface for the GD
        stack
+1 −1
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@

#include "common/init_flags.h"
#include "facade/grpc_root_server.h"
#include "hal/hci_hal_host_rootcanal.h"
#include "hal/hci_hal_host.h"
#include "hal/snoop_logger.h"
#include "os/log.h"
#include "os/parameter_provider.h"
+4 −4
Original line number Diff line number Diff line
@@ -22,9 +22,9 @@ filegroup {
}

filegroup {
    name: "BluetoothHalSources_hci_rootcanal",
    name: "BluetoothHalSources_hci_host",
    srcs: [
        "hci_hal_host_rootcanal.cc",
        "hci_hal_host.cc",
    ],
}

@@ -36,9 +36,9 @@ filegroup {
}

filegroup {
    name: "BluetoothHalTestSources_hci_rootcanal",
    name: "BluetoothHalTestSources_hci_host",
    srcs: [
        "hci_hal_host_rootcanal_test.cc",
        "hci_hal_host_test.cc",
    ],
}

+174 −22
Original line number Diff line number Diff line
@@ -14,9 +14,10 @@
 * limitations under the License.
 */

#include "hal/hci_hal_host_rootcanal.h"
#include "hal/hci_hal_host.h"

#include <netdb.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
@@ -48,7 +49,160 @@ constexpr uint8_t kHciEvtHeaderSize = 2;
constexpr uint8_t kHciIsoHeaderSize = 4;
constexpr int kBufSize = 1024 + 4 + 1;  // DeviceProperties::acl_data_packet_size_ + ACL header + H4 header

int ConnectToRootCanal(const std::string& server, int port) {
#ifdef USE_LINUX_HCI_SOCKET
constexpr uint8_t BTPROTO_HCI = 1;
constexpr uint16_t HCI_CHANNEL_USER = 1;
constexpr uint16_t HCI_CHANNEL_CONTROL = 3;
constexpr uint16_t HCI_DEV_NONE = 0xffff;

/* reference from <kernel>/include/net/bluetooth/mgmt.h */
#define MGMT_OP_INDEX_LIST 0x0003
#define MGMT_EV_INDEX_ADDED 0x0004
#define MGMT_EV_COMMAND_COMP 0x0001
#define MGMT_EV_SIZE_MAX 1024
#define WRITE_NO_INTR(fn) \
  do {                    \
  } while ((fn) == -1 && errno == EINTR)

struct sockaddr_hci {
  sa_family_t hci_family;
  unsigned short hci_dev;
  unsigned short hci_channel;
};

struct mgmt_pkt {
  uint16_t opcode;
  uint16_t index;
  uint16_t len;
  uint8_t data[MGMT_EV_SIZE_MAX];
} __attribute__((packed));

struct mgmt_event_read_index {
  uint16_t cc_opcode;
  uint8_t status;
  uint16_t num_intf;
  uint16_t index[0];
} __attribute__((packed));

int waitHciDev(int hci_interface) {
  struct sockaddr_hci addr;
  struct pollfd fds[1];
  struct mgmt_pkt ev;
  int fd;
  int ret = 0;

  fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
  if (fd < 0) {
    LOG_ERROR("Bluetooth socket error: %s", strerror(errno));
    return -1;
  }
  memset(&addr, 0, sizeof(addr));
  addr.hci_family = AF_BLUETOOTH;
  addr.hci_dev = HCI_DEV_NONE;
  addr.hci_channel = HCI_CHANNEL_CONTROL;
  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
    LOG_ERROR("HCI Channel Control: %s", strerror(errno));
    close(fd);
    return -1;
  }

  fds[0].fd = fd;
  fds[0].events = POLLIN;

  /* Read Controller Index List Command */
  ev.opcode = MGMT_OP_INDEX_LIST;
  ev.index = HCI_DEV_NONE;
  ev.len = 0;

  ssize_t wrote;
  WRITE_NO_INTR(wrote = write(fd, &ev, 6));
  if (wrote != 6) {
    LOG_ERROR("Unable to write mgmt command: %s", strerror(errno));
    close(fd);
    return -1;
  }
  /* validate mentioned hci interface is present and registered with sock system */
  while (1) {
    int n;
    WRITE_NO_INTR(n = poll(fds, 1, -1));
    if (n == -1) {
      LOG_ERROR("Poll error: %s", strerror(errno));
      ret = -1;
      break;
    } else if (n == 0) {
      LOG_ERROR("Timeout, no HCI device detected");
      ret = -1;
      break;
    }

    if (fds[0].revents & POLLIN) {
      WRITE_NO_INTR(n = read(fd, &ev, sizeof(struct mgmt_pkt)));
      if (n < 0) {
        LOG_ERROR("Error reading control channel: %s", strerror(errno));
        ret = -1;
        break;
      }

      if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
        close(fd);
        return -1;
      } else if (ev.opcode == MGMT_EV_COMMAND_COMP) {
        struct mgmt_event_read_index* cc;
        int i;

        cc = (struct mgmt_event_read_index*)ev.data;

        if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0) continue;

        for (i = 0; i < cc->num_intf; i++) {
          if (cc->index[i] == hci_interface) {
            close(fd);
            return 0;
          }
        }
      }
    }
  }

  close(fd);
  return -1;
}

// Connect to Linux HCI socket
int ConnectToSocket() {
  int socket_fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
  if (socket_fd < 1) {
    LOG_ERROR("can't create socket: %s", strerror(errno));
    return INVALID_FD;
  }

  int hci_interface = 0;  // Assume we only have HCI 0

  if (waitHciDev(hci_interface) != 0) {
    ::close(socket_fd);
    return INVALID_FD;
  }

  struct sockaddr_hci addr;
  memset(&addr, 0, sizeof(addr));
  addr.hci_family = AF_BLUETOOTH;
  addr.hci_dev = hci_interface;
  addr.hci_channel = HCI_CHANNEL_USER;
  if (bind(socket_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
    LOG_ERROR("HCI Channel Control: %s", strerror(errno));
    ::close(socket_fd);
    return INVALID_FD;
  }
  LOG_INFO("HCI device ready");
  return socket_fd;
}
#else
// Connect to root canal socket
int ConnectToSocket() {
  auto* config = bluetooth::hal::HciHalHostRootcanalConfig::Get();
  const std::string& server = config->GetServerAddress();
  int port = config->GetPort();

  int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (socket_fd < 1) {
    LOG_ERROR("can't create socket: %s", strerror(errno));
@@ -85,12 +239,13 @@ int ConnectToRootCanal(const std::string& server, int port) {
  }
  return socket_fd;
}
#endif
}  // namespace

namespace bluetooth {
namespace hal {

class HciHalHostRootcanal : public HciHal {
class HciHalHost : public HciHal {
 public:
  void registerIncomingPacketCallback(HciHalCallbacks* callback) override {
    std::lock_guard<std::mutex> lock(api_mutex_);
@@ -119,7 +274,7 @@ class HciHalHostRootcanal : public HciHal {
    std::vector<uint8_t> packet = std::move(command);
    btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::CMD);
    packet.insert(packet.cbegin(), kH4Command);
    write_to_rootcanal_fd(packet);
    write_to_fd(packet);
  }

  void sendAclData(HciPacket data) override {
@@ -128,7 +283,7 @@ class HciHalHostRootcanal : public HciHal {
    std::vector<uint8_t> packet = std::move(data);
    btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL);
    packet.insert(packet.cbegin(), kH4Acl);
    write_to_rootcanal_fd(packet);
    write_to_fd(packet);
  }

  void sendScoData(HciPacket data) override {
@@ -137,7 +292,7 @@ class HciHalHostRootcanal : public HciHal {
    std::vector<uint8_t> packet = std::move(data);
    btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::SCO);
    packet.insert(packet.cbegin(), kH4Sco);
    write_to_rootcanal_fd(packet);
    write_to_fd(packet);
  }

  void sendIsoData(HciPacket data) override {
@@ -146,7 +301,7 @@ class HciHalHostRootcanal : public HciHal {
    std::vector<uint8_t> packet = std::move(data);
    btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ISO);
    packet.insert(packet.cbegin(), kH4Iso);
    write_to_rootcanal_fd(packet);
    write_to_fd(packet);
  }

 protected:
@@ -157,25 +312,23 @@ class HciHalHostRootcanal : public HciHal {
  void Start() override {
    std::lock_guard<std::mutex> lock(api_mutex_);
    ASSERT(sock_fd_ == INVALID_FD);
    sock_fd_ = ConnectToRootCanal(config_->GetServerAddress(), config_->GetPort());
    sock_fd_ = ConnectToSocket();
    ASSERT(sock_fd_ != INVALID_FD);
    reactable_ = hci_incoming_thread_.GetReactor()->Register(
        sock_fd_,
        common::Bind(&HciHalHostRootcanal::incoming_packet_received, common::Unretained(this)),
        common::Closure());
        sock_fd_, common::Bind(&HciHalHost::incoming_packet_received, common::Unretained(this)), common::Closure());
    btsnoop_logger_ = GetDependency<SnoopLogger>();
    LOG_INFO("Rootcanal HAL opened successfully");
    LOG_INFO("HAL opened successfully");
  }

  void Stop() override {
    std::lock_guard<std::mutex> lock(api_mutex_);
    LOG_INFO("Rootcanal HAL is closing");
    LOG_INFO("HAL is closing");
    if (reactable_ != nullptr) {
      hci_incoming_thread_.GetReactor()->Unregister(reactable_);
      LOG_INFO("Rootcanal HAL is stopping, start waiting for last callback");
      LOG_INFO("HAL is stopping, start waiting for last callback");
      // Wait up to 1 second for the last incoming packet callback to finish
      hci_incoming_thread_.GetReactor()->WaitForUnregisteredReactable(std::chrono::milliseconds(1000));
      LOG_INFO("Rootcanal HAL is stopping, finished waiting for last callback");
      LOG_INFO("HAL is stopping, finished waiting for last callback");
      ASSERT(sock_fd_ != INVALID_FD);
    }
    reactable_ = nullptr;
@@ -185,13 +338,12 @@ class HciHalHostRootcanal : public HciHal {
    }
    ::close(sock_fd_);
    sock_fd_ = INVALID_FD;
    LOG_INFO("Rootcanal HAL is closed");
    LOG_INFO("HAL is closed");
  }

 private:
  // Held when APIs are called, NOT to be held during callbacks
  std::mutex api_mutex_;
  HciHalHostRootcanalConfig* config_ = HciHalHostRootcanalConfig::Get();
  HciHalCallbacks* incoming_packet_callback_ = nullptr;
  std::mutex incoming_packet_callback_mutex_;
  int sock_fd_ = INVALID_FD;
@@ -201,14 +353,14 @@ class HciHalHostRootcanal : public HciHal {
  std::queue<std::vector<uint8_t>> hci_outgoing_queue_;
  SnoopLogger* btsnoop_logger_ = nullptr;

  void write_to_rootcanal_fd(HciPacket packet) {
  void write_to_fd(HciPacket packet) {
    // TODO: replace this with new queue when it's ready
    hci_outgoing_queue_.emplace(packet);
    if (hci_outgoing_queue_.size() == 1) {
      hci_incoming_thread_.GetReactor()->ModifyRegistration(
          reactable_,
          common::Bind(&HciHalHostRootcanal::incoming_packet_received, common::Unretained(this)),
          common::Bind(&HciHalHostRootcanal::send_packet_ready, common::Unretained(this)));
          common::Bind(&HciHalHost::incoming_packet_received, common::Unretained(this)),
          common::Bind(&HciHalHost::send_packet_ready, common::Unretained(this)));
    }
  }

@@ -223,7 +375,7 @@ class HciHalHostRootcanal : public HciHal {
    if (hci_outgoing_queue_.empty()) {
      this->hci_incoming_thread_.GetReactor()->ModifyRegistration(
          this->reactable_,
          common::Bind(&HciHalHostRootcanal::incoming_packet_received, common::Unretained(this)),
          common::Bind(&HciHalHost::incoming_packet_received, common::Unretained(this)),
          common::Closure());
    }
  }
@@ -356,7 +508,7 @@ class HciHalHostRootcanal : public HciHal {
  }
};

const ModuleFactory HciHal::Factory = ModuleFactory([]() { return new HciHalHostRootcanal(); });
const ModuleFactory HciHal::Factory = ModuleFactory([]() { return new HciHalHost(); });

}  // namespace hal
}  // namespace bluetooth
Loading