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

Commit 75928372 authored by Alistair Delva's avatar Alistair Delva Committed by Gerrit Code Review
Browse files

Merge "bluetooth: Add support for linux bluetooth raw hci sockets"

parents 2524ba06 efa25d72
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ cc_library_static {
    defaults: ["android.hardware.bluetooth-service-build-defaults"],
    srcs: [
        "BluetoothHci.cpp",
        "net_bluetooth_mgmt.cpp",
    ],
}

@@ -37,7 +38,7 @@ cc_binary {
    name: "android.hardware.bluetooth-service.default",
    relative_install_path: "hw",
    init_rc: ["bluetooth-service-default.rc"],
    vintf_fragments: ["bluetooth-service-default.xml"],
    vintf_fragments: [":manifest_android.hardware.bluetooth-service.default.xml"],
    vendor: true,
    defaults: ["android.hardware.bluetooth-service-build-defaults"],
    srcs: [
@@ -77,3 +78,8 @@ cc_fuzz {
        ],
    },
}

filegroup {
    name: "manifest_android.hardware.bluetooth-service.default.xml",
    srcs: ["bluetooth-service-default.xml"],
}
+41 −16
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ int SetTerminalRaw(int fd) {

using namespace ::android::hardware::bluetooth::hci;
using namespace ::android::hardware::bluetooth::async;
using aidl::android::hardware::bluetooth::Status;

namespace aidl::android::hardware::bluetooth::impl {

@@ -97,38 +98,46 @@ BluetoothHci::BluetoothHci(const std::string& dev_path) {
  mDeathRecipient = std::make_shared<BluetoothDeathRecipient>(this);
}

ndk::ScopedAStatus BluetoothHci::initialize(
    const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
  ALOGI(__func__);

  mFd = open(mDevPath.c_str(), O_RDWR);
  if (mFd < 0) {
int BluetoothHci::getFdFromDevPath() {
  int fd = open(mDevPath.c_str(), O_RDWR);
  if (fd < 0) {
    ALOGE("Could not connect to bt: %s (%s)", mDevPath.c_str(),
          strerror(errno));
    return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
    return fd;
  }
  if (int ret = SetTerminalRaw(mFd) < 0) {
    ALOGE("Could not make %s a raw terminal %d(%s)", mDevPath.c_str(), ret,
          strerror(errno));
    return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
    ::close(fd);
    return -1;
  }
  return fd;
}

ndk::ScopedAStatus BluetoothHci::initialize(
    const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
  ALOGI(__func__);

  mCb = cb;
  if (mCb == nullptr) {
    ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
    return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
  }

  mDeathRecipient->LinkToDeath(mCb);
  management_.reset(new NetBluetoothMgmt);
  mFd = management_->openHci();
  if (mFd < 0) {
    management_.reset();

  auto init_ret = cb->initializationComplete(Status::SUCCESS);
  if (!init_ret.isOk()) {
    if (!mDeathRecipient->getHasDied()) {
      ALOGE("Error sending init callback, but no death notification.");
    ALOGI("Unable to open Linux interface, trying default path.");
    mFd = getFdFromDevPath();
    if (mFd < 0) {
      return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
    }
    return ndk::ScopedAStatus::fromServiceSpecificError(
        STATUS_FAILED_TRANSACTION);
  }

  mDeathRecipient->LinkToDeath(mCb);

  mH4 = std::make_shared<H4Protocol>(
      mFd,
      [](const std::vector<uint8_t>& /* raw_command */) {
@@ -152,13 +161,29 @@ ndk::ScopedAStatus BluetoothHci::initialize(
      });
  mFdWatcher.WatchFdForNonBlockingReads(mFd,
                                        [this](int) { mH4->OnDataReady(); });

  ALOGI("initialization complete");
  auto status = mCb->initializationComplete(Status::SUCCESS);
  if (!status.isOk()) {
    if (!mDeathRecipient->getHasDied()) {
      ALOGE("Error sending init callback, but no death notification");
    }
    close();
    return ndk::ScopedAStatus::fromServiceSpecificError(
        STATUS_FAILED_TRANSACTION);
  }

  return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus BluetoothHci::close() {
  ALOGI(__func__);
  mFdWatcher.StopWatchingFileDescriptors();
  if (management_) {
    management_->closeHci();
  } else {
    ::close(mFd);
  }

  return ndk::ScopedAStatus::ok();
}
+3 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

#include "async_fd_watcher.h"
#include "h4_protocol.h"
#include "net_bluetooth_mgmt.h"

namespace aidl::android::hardware::bluetooth::impl {

@@ -64,8 +65,10 @@ class BluetoothHci : public BnBluetoothHci {

  ::android::hardware::bluetooth::async::AsyncFdWatcher mFdWatcher;

  int getFdFromDevPath();
  void send(::android::hardware::bluetooth::hci::PacketType type,
            const std::vector<uint8_t>& packet);
  std::unique_ptr<NetBluetoothMgmt> management_{};
};

}  // namespace aidl::android::hardware::bluetooth::impl
+1 −1
Original line number Diff line number Diff line
service bluetooth_hal_service /vendor/bin/hw/android.hardware.bluetooth-service.default
service vendor.bluetooth-default /vendor/bin/hw/android.hardware.bluetooth-service.default
    class hal
    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
    user bluetooth
+296 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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 "android.hardware.bluetooth.service.default"

#include "net_bluetooth_mgmt.h"

#include <fcntl.h>
#include <log/log.h>
#include <poll.h>
#include <sys/socket.h>
#include <unistd.h>

#include <cerrno>
#include <cstdint>
#include <cstdlib>
#include <cstring>

// Definitions imported from <linux/net/bluetooth/bluetooth.h>
#define BTPROTO_HCI 1

// Definitions imported from <linux/net/bluetooth/hci_sock.h>
#define HCI_CHANNEL_USER 1
#define HCI_CHANNEL_CONTROL 3
#define HCI_DEV_NONE 0xffff

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

// Definitions imported from <linux/net/bluetooth/mgmt.h>
#define MGMT_OP_READ_INDEX_LIST 0x0003
#define MGMT_EV_INDEX_ADDED 0x0004
#define MGMT_EV_CMD_COMPLETE 0x0001
#define MGMT_PKT_SIZE_MAX 1024
#define MGMT_INDEX_NONE 0xFFFF

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

struct mgmt_ev_read_index_list {
  uint16_t opcode;
  uint8_t status;
  uint16_t num_controllers;
  uint16_t index[];
} __attribute__((packed));

// Definitions imported from <linux/rfkill.h>
#define RFKILL_STATE_SOFT_BLOCKED 0
#define RFKILL_STATE_UNBLOCKED 1
#define RFKILL_STATE_HARD_BLOCKED 2

#define RFKILL_TYPE_BLUETOOTH 2

#define RFKILL_OP_ADD 0
#define RFKILL_OP_CHANGE 2

struct rfkill_event {
  uint32_t idx;
  uint8_t type;
  uint8_t op;
  uint8_t soft;
  uint8_t hard;
} __attribute__((packed));

namespace aidl::android::hardware::bluetooth::impl {

// Wait indefinitely for the selected HCI interface to be enabled in the
// bluetooth driver.
int NetBluetoothMgmt::waitHciDev(int hci_interface) {
  ALOGI("waiting for hci interface %d", hci_interface);

  int ret = -1;
  struct mgmt_pkt cmd;
  struct pollfd pollfd;
  struct sockaddr_hci hci_addr = {
      .hci_family = AF_BLUETOOTH,
      .hci_dev = HCI_DEV_NONE,
      .hci_channel = HCI_CHANNEL_CONTROL,
  };

  // Open and bind a socket to the bluetooth control interface in the
  // kernel driver, used to send control commands and receive control
  // events.
  int fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
  if (fd < 0) {
    ALOGE("unable to open raw bluetooth socket: %s", strerror(errno));
    return -1;
  }

  if (bind(fd, (struct sockaddr*)&hci_addr, sizeof(hci_addr)) < 0) {
    ALOGE("unable to bind bluetooth control channel: %s", strerror(errno));
    goto end;
  }

  // Send the control command [Read Index List].
  cmd = {
      .opcode = MGMT_OP_READ_INDEX_LIST,
      .index = MGMT_INDEX_NONE,
      .len = 0,
  };

  if (write(fd, &cmd, 6) != 6) {
    ALOGE("error writing mgmt command: %s", strerror(errno));
    goto end;
  }

  // Poll the control socket waiting for the command response,
  // and subsequent [Index Added] events. The loops continue without
  // timeout until the selected hci interface is detected.
  pollfd = {.fd = fd, .events = POLLIN};

  for (;;) {
    ret = poll(&pollfd, 1, -1);

    // Poll interrupted, try again.
    if (ret == -1 && (errno == EINTR || errno == EAGAIN)) {
      continue;
    }

    // Poll failure, abandon.
    if (ret == -1) {
      ALOGE("poll error: %s", strerror(errno));
      break;
    }

    // Spurious wakeup, try again.
    if (ret == 0 || (pollfd.revents & POLLIN) == 0) {
      continue;
    }

    // Read the next control event.
    struct mgmt_pkt ev {};
    ret = read(fd, &ev, sizeof(ev));
    if (ret < 0) {
      ALOGE("error reading mgmt event: %s", strerror(errno));
      goto end;
    }

    // Received [Read Index List] command response.
    if (ev.opcode == MGMT_EV_CMD_COMPLETE) {
      struct mgmt_ev_read_index_list* data =
          (struct mgmt_ev_read_index_list*)ev.data;

      for (int i = 0; i < data->num_controllers; i++) {
        if (data->index[i] == hci_interface) {
          ALOGI("hci interface %d found", hci_interface);
          ret = 0;
          goto end;
        }
      }
    }

    // Received [Index Added] event.
    if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
      ALOGI("hci interface %d added", hci_interface);
      ret = 0;
      goto end;
    }
  }

end:
  ::close(fd);
  return ret;
}

int NetBluetoothMgmt::openRfkill() {
  int fd = open("/dev/rfkill", O_RDWR);
  if (fd < 0) {
    ALOGE("unable to open /dev/rfkill: %s", strerror(errno));
    return -1;
  }

  if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
    ALOGE("unable to set rfkill control device to non-blocking: %s",
          strerror(errno));
    ::close(fd);
    return -1;
  }

  for (;;) {
    struct rfkill_event event {};
    ssize_t res = read(fd, &event, sizeof(event));
    if (res < 0) {
      ALOGE("error reading rfkill events: %s", strerror(errno));
      break;
    }

    ALOGI("index:%d type:%d op:%d", event.idx, event.type, event.op);

    if (event.op == RFKILL_OP_ADD && event.type == RFKILL_TYPE_BLUETOOTH) {
      rfkill_bt_index_ = event.idx;
      rfkill_fd_ = fd;
      return 0;
    }
  }

  ::close(fd);
  return -1;
}

// Block or unblock Bluetooth.
int NetBluetoothMgmt::rfkill(int block) {
  if (rfkill_fd_ == -1) {
    openRfkill();
  }

  if (rfkill_fd_ == -1) {
    ALOGE("rfkill unavailable");
    return -1;
  }

  struct rfkill_event event = {
      .idx = static_cast<uint32_t>(rfkill_bt_index_),
      .type = RFKILL_TYPE_BLUETOOTH,
      .op = RFKILL_OP_CHANGE,
      .soft = static_cast<uint8_t>(block),
      .hard = 0,
  };

  int res = write(rfkill_fd_, &event, sizeof(event));
  if (res < 0) {
    ALOGE("error writing rfkill command: %s", strerror(errno));
    return -1;
  }

  return 0;
}

int NetBluetoothMgmt::openHci(int hci_interface) {
  ALOGI("opening hci interface %d", hci_interface);

  // Block Bluetooth.
  rfkill(1);

  // Wait for the HCI interface to complete initialization or to come online.
  if (waitHciDev(hci_interface)) {
    ALOGE("hci interface %d not found", hci_interface);
    return -1;
  }

  // Open the raw HCI socket.
  int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
  if (fd < 0) {
    ALOGE("unable to open raw bluetooth socket: %s", strerror(errno));
    return -1;
  }

  struct sockaddr_hci hci_addr = {
      .hci_family = AF_BLUETOOTH,
      .hci_dev = static_cast<uint16_t>(hci_interface),
      .hci_channel = HCI_CHANNEL_USER,
  };

  // Bind the socket to the selected interface.
  if (bind(fd, (struct sockaddr*)&hci_addr, sizeof(hci_addr)) < 0) {
    ALOGE("unable to bind bluetooth user channel: %s", strerror(errno));
    ::close(fd);
    return -1;
  }

  ALOGI("hci interface %d ready", hci_interface);
  bt_fd_ = fd;
  return fd;
}

void NetBluetoothMgmt::closeHci() {
  if (bt_fd_ != -1) {
    ::close(bt_fd_);
    bt_fd_ = -1;
  }

  // Unblock Bluetooth.
  rfkill(0);
}

}  // namespace aidl::android::hardware::bluetooth::impl
Loading