HCI HAL: HCI Proxy Audio Software offload integration
Bug: 375486605
Test: mmm .
Change-Id: I6c98fef96e747721110202cbcbe5554ad3bfa4ff
diff --git a/bluetooth/aidl/default/Android.bp b/bluetooth/aidl/default/Android.bp
index 3f4ba99..d3f6364 100644
--- a/bluetooth/aidl/default/Android.bp
+++ b/bluetooth/aidl/default/Android.bp
@@ -2,81 +2,62 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-cc_defaults {
- name: "android.hardware.bluetooth-service-build-defaults",
- cflags: [
- "-Wall",
- "-Wextra",
- ],
- shared_libs: [
- "android.hardware.bluetooth-V1-ndk",
- "libbase",
- "libbinder_ndk",
- "libcutils",
- "libhidlbase",
- "liblog",
- "libutils",
- ],
- static_libs: [
- "android.hardware.bluetooth.async",
- "android.hardware.bluetooth.hci",
- ],
-}
-
cc_library_static {
name: "libbluetoothhcihalimpl",
vendor_available: true,
host_supported: true,
- defaults: ["android.hardware.bluetooth-service-build-defaults"],
srcs: [
"BluetoothHci.cpp",
"net_bluetooth_mgmt.cpp",
],
-}
-
-cc_binary {
- name: "android.hardware.bluetooth-service.default",
- relative_install_path: "hw",
- init_rc: ["bluetooth-service-default.rc"],
- vintf_fragments: [":manifest_android.hardware.bluetooth-service.default.xml"],
- vendor: true,
- defaults: ["android.hardware.bluetooth-service-build-defaults"],
- srcs: [
- "service.cpp",
+ cflags: [
+ "-Wall",
+ "-Wextra",
],
- shared_libs: [
- "android.hardware.bluetooth-V1-ndk",
- "libbase",
- "libbinder_ndk",
- "libhidlbase",
- "libutils",
- "liblog",
- ],
- static_libs: [
- "libbluetoothhcihalimpl",
- ],
-}
-
-cc_fuzz {
- name: "android.hardware.bluetooth-service.default_fuzzer",
- host_supported: true,
- defaults: ["service_fuzzer_defaults"],
- srcs: [
- "test/fuzzer.cpp",
+ header_libs: [
+ "libbluetooth_offload_hal_headers",
],
static_libs: [
"android.hardware.bluetooth.async",
"android.hardware.bluetooth.hci",
- "android.hardware.bluetooth-V1-ndk",
- "libbluetoothhcihalimpl",
- "liblog",
],
- fuzz_config: {
- componentid: 27441,
- cc: [
- "mylesgw@google.com",
- ],
- },
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+}
+
+rust_binary {
+ name: "android.hardware.bluetooth-service.default",
+ crate_name: "bluetooth_hci_hal_server",
+ relative_install_path: "hw",
+ init_rc: ["bluetooth-service-default.rc"],
+ vintf_fragments: [":manifest_android.hardware.bluetooth-service.default.xml"],
+ vendor: true,
+ prefer_rlib: true,
+ srcs: ["main.rs"],
+ rustlibs: [
+ "android.hardware.bluetooth-V1-rust",
+ "libbluetooth_offload_hal",
+ "libbluetooth_offload_leaudio_hci",
+ "libbinder_rs",
+ "liblogger",
+ "liblog_rust",
+ ],
+ static_libs: [
+ "android.hardware.bluetooth.async",
+ "android.hardware.bluetooth.hci",
+ "libbluetoothhcihalimpl",
+ ],
+ shared_libs: [
+ "libbase",
+ "libc++",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
}
filegroup {
diff --git a/bluetooth/aidl/default/BluetoothHci.cpp b/bluetooth/aidl/default/BluetoothHci.cpp
index a247cb0..bcdb67e 100644
--- a/bluetooth/aidl/default/BluetoothHci.cpp
+++ b/bluetooth/aidl/default/BluetoothHci.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2024 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.
@@ -16,18 +16,20 @@
#define LOG_TAG "android.hardware.bluetooth.service.default"
-#include "BluetoothHci.h"
-
#include <cutils/properties.h>
#include <fcntl.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <poll.h>
+#include <hal/ffi.h>
#include <string.h>
-#include <sys/uio.h>
#include <termios.h>
+#include <future>
+#include <memory>
+#include <vector>
+
+#include "async_fd_watcher.h"
+#include "h4_protocol.h"
#include "log/log.h"
+#include "net_bluetooth_mgmt.h"
namespace {
int SetTerminalRaw(int fd) {
@@ -44,12 +46,9 @@
using namespace ::android::hardware::bluetooth::hci;
using namespace ::android::hardware::bluetooth::async;
-using aidl::android::hardware::bluetooth::Status;
namespace aidl::android::hardware::bluetooth::impl {
-void OnDeath(void* cookie);
-
std::optional<std::string> GetSystemProperty(const std::string& property) {
std::array<char, PROPERTY_VALUE_MAX> value_array{0};
auto value_len = property_get(property.c_str(), value_array.data(), nullptr);
@@ -63,302 +62,298 @@
return str.compare(0, prefix.length(), prefix) == 0;
}
-class BluetoothDeathRecipient {
+class Hal {
public:
- BluetoothDeathRecipient(BluetoothHci* hci) : mHci(hci) {}
-
- void LinkToDeath(const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
- mCb = cb;
- clientDeathRecipient_ = AIBinder_DeathRecipient_new(OnDeath);
- auto linkToDeathReturnStatus = AIBinder_linkToDeath(
- mCb->asBinder().get(), clientDeathRecipient_, this /* cookie */);
- LOG_ALWAYS_FATAL_IF(linkToDeathReturnStatus != STATUS_OK,
- "Unable to link to death recipient");
+ Hal(const std::string& dev_path = "/dev/hvc5") {
+ char property_bytes[PROPERTY_VALUE_MAX];
+ property_get("vendor.ser.bt-uart", property_bytes, dev_path.c_str());
+ mDevPath = std::string(property_bytes);
}
- void UnlinkToDeath(const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
- LOG_ALWAYS_FATAL_IF(cb != mCb, "Unable to unlink mismatched pointers");
+ static void Initialize(void* instance,
+ const struct hal_callbacks* callbacks) {
+ static_cast<Hal*>(instance)->Initialize(callbacks);
}
- void serviceDied() {
- if (mCb != nullptr && !AIBinder_isAlive(mCb->asBinder().get())) {
- ALOGE("Bluetooth remote service has died");
- } else {
- ALOGE("BluetoothDeathRecipient::serviceDied called but service not dead");
- return;
- }
- {
- std::lock_guard<std::mutex> guard(mHasDiedMutex);
- has_died_ = true;
- }
- mHci->close();
+ static void Close(void* instance) { static_cast<Hal*>(instance)->Close(); }
+
+ static void SendCommand(void* instance, const uint8_t* data, size_t len) {
+ static_cast<Hal*>(instance)->SendCommand(
+ std::vector<uint8_t>(data, data + len));
}
- BluetoothHci* mHci;
- std::shared_ptr<IBluetoothHciCallbacks> mCb;
- AIBinder_DeathRecipient* clientDeathRecipient_;
- bool getHasDied() {
- std::lock_guard<std::mutex> guard(mHasDiedMutex);
- return has_died_;
+
+ static void SendAcl(void* instance, const uint8_t* data, size_t len) {
+ static_cast<Hal*>(instance)->SendAcl(
+ std::vector<uint8_t>(data, data + len));
+ }
+
+ static void SendSco(void* instance, const uint8_t* data, size_t len) {
+ static_cast<Hal*>(instance)->SendSco(
+ std::vector<uint8_t>(data, data + len));
+ }
+
+ static void SendIso(void* instance, const uint8_t* data, size_t len) {
+ static_cast<Hal*>(instance)->SendIso(
+ std::vector<uint8_t>(data, data + len));
}
private:
- std::mutex mHasDiedMutex;
- bool has_died_{false};
-};
-
-void OnDeath(void* cookie) {
- auto* death_recipient = static_cast<BluetoothDeathRecipient*>(cookie);
- death_recipient->serviceDied();
-}
-
-BluetoothHci::BluetoothHci(const std::string& dev_path) {
- char property_bytes[PROPERTY_VALUE_MAX];
- property_get("vendor.ser.bt-uart", property_bytes, dev_path.c_str());
- mDevPath = std::string(property_bytes);
- mDeathRecipient = std::make_shared<BluetoothDeathRecipient>(this);
-}
-
-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));
+ int 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 fd;
+ }
+ if (int ret = SetTerminalRaw(fd) < 0) {
+ ALOGI("Could not make %s a raw terminal %d(%s)", mDevPath.c_str(), ret,
+ strerror(errno));
+ }
return fd;
}
- if (int ret = SetTerminalRaw(fd) < 0) {
- ALOGI("Could not make %s a raw terminal %d(%s)", mDevPath.c_str(), ret,
- strerror(errno));
- }
- return fd;
-}
-void BluetoothHci::reset() {
- // Send a reset command and wait until the command complete comes back.
+ void reset() {
+ // Send a reset command and wait until the command complete comes back.
- std::vector<uint8_t> reset = {0x03, 0x0c, 0x00};
+ std::vector<uint8_t> reset = {0x03, 0x0c, 0x00};
- auto resetPromise = std::make_shared<std::promise<void>>();
- auto resetFuture = resetPromise->get_future();
+ auto resetPromise = std::make_shared<std::promise<void>>();
+ auto resetFuture = resetPromise->get_future();
- mH4 = std::make_shared<H4Protocol>(
- mFd,
- [](const std::vector<uint8_t>& raw_command) {
- ALOGI("Discarding %d bytes with command type",
- static_cast<int>(raw_command.size()));
- },
- [](const std::vector<uint8_t>& raw_acl) {
- ALOGI("Discarding %d bytes with acl type",
- static_cast<int>(raw_acl.size()));
- },
- [](const std::vector<uint8_t>& raw_sco) {
- ALOGI("Discarding %d bytes with sco type",
- static_cast<int>(raw_sco.size()));
- },
- [resetPromise](const std::vector<uint8_t>& raw_event) {
- std::vector<uint8_t> reset_complete = {0x0e, 0x04, 0x01,
- 0x03, 0x0c, 0x00};
- bool valid = raw_event.size() == 6 &&
- raw_event[0] == reset_complete[0] &&
- raw_event[1] == reset_complete[1] &&
- // Don't compare the number of packets field.
- raw_event[3] == reset_complete[3] &&
- raw_event[4] == reset_complete[4] &&
- raw_event[5] == reset_complete[5];
- if (valid) {
- resetPromise->set_value();
- } else {
- ALOGI("Discarding %d bytes with event type",
- static_cast<int>(raw_event.size()));
- }
- },
- [](const std::vector<uint8_t>& raw_iso) {
- ALOGI("Discarding %d bytes with iso type",
- static_cast<int>(raw_iso.size()));
- },
- [this]() {
- ALOGI("HCI socket device disconnected while waiting for reset");
- mFdWatcher.StopWatchingFileDescriptors();
- });
- mFdWatcher.WatchFdForNonBlockingReads(mFd,
- [this](int) { mH4->OnDataReady(); });
+ mH4 = std::make_shared<H4Protocol>(
+ mFd,
+ [](const std::vector<uint8_t>& raw_command) {
+ ALOGI("Discarding %d bytes with command type",
+ static_cast<int>(raw_command.size()));
+ },
+ [](const std::vector<uint8_t>& raw_acl) {
+ ALOGI("Discarding %d bytes with acl type",
+ static_cast<int>(raw_acl.size()));
+ },
+ [](const std::vector<uint8_t>& raw_sco) {
+ ALOGI("Discarding %d bytes with sco type",
+ static_cast<int>(raw_sco.size()));
+ },
+ [resetPromise](const std::vector<uint8_t>& raw_event) {
+ std::vector<uint8_t> reset_complete = {0x0e, 0x04, 0x01,
+ 0x03, 0x0c, 0x00};
+ bool valid = raw_event.size() == 6 &&
+ raw_event[0] == reset_complete[0] &&
+ raw_event[1] == reset_complete[1] &&
+ // Don't compare the number of packets field.
+ raw_event[3] == reset_complete[3] &&
+ raw_event[4] == reset_complete[4] &&
+ raw_event[5] == reset_complete[5];
+ if (valid) {
+ resetPromise->set_value();
+ } else {
+ ALOGI("Discarding %d bytes with event type",
+ static_cast<int>(raw_event.size()));
+ }
+ },
+ [](const std::vector<uint8_t>& raw_iso) {
+ ALOGI("Discarding %d bytes with iso type",
+ static_cast<int>(raw_iso.size()));
+ },
+ [this]() {
+ ALOGI("HCI socket device disconnected while waiting for reset");
+ mFdWatcher.StopWatchingFileDescriptors();
+ });
+ mFdWatcher.WatchFdForNonBlockingReads(mFd,
+ [this](int) { mH4->OnDataReady(); });
- ndk::ScopedAStatus result = send(PacketType::COMMAND, reset);
- if (!result.isOk()) {
- ALOGE("Error sending reset command");
- }
- auto status = resetFuture.wait_for(std::chrono::seconds(1));
- mFdWatcher.StopWatchingFileDescriptors();
- if (status == std::future_status::ready) {
- ALOGI("HCI Reset successful");
- } else {
- ALOGE("HCI Reset Response not received in one second");
- }
-
- resetPromise.reset();
-}
-
-ndk::ScopedAStatus BluetoothHci::initialize(
- const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
- ALOGI(__func__);
-
- if (cb == nullptr) {
- ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
- return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
- }
-
- HalState old_state = HalState::READY;
- {
- std::lock_guard<std::mutex> guard(mStateMutex);
- if (mState != HalState::READY) {
- old_state = mState;
+ if (!send(PacketType::COMMAND, reset)) {
+ ALOGE("Error sending reset command");
+ }
+ auto status = resetFuture.wait_for(std::chrono::seconds(1));
+ mFdWatcher.StopWatchingFileDescriptors();
+ if (status == std::future_status::ready) {
+ ALOGI("HCI Reset successful");
} else {
- mState = HalState::INITIALIZING;
+ ALOGE("HCI Reset Response not received in one second");
}
+
+ resetPromise.reset();
}
- if (old_state != HalState::READY) {
- ALOGE("initialize: Unexpected State %d", static_cast<int>(old_state));
- close();
- cb->initializationComplete(Status::ALREADY_INITIALIZED);
- return ndk::ScopedAStatus::ok();
- }
+ void Initialize(const struct hal_callbacks* callbacks) {
+ ALOGI(__func__);
- mCb = cb;
- management_.reset(new NetBluetoothMgmt);
- mFd = management_->openHci();
- if (mFd < 0) {
- management_.reset();
+ HalState old_state = HalState::READY;
+ {
+ std::lock_guard<std::mutex> guard(mStateMutex);
+ if (mState != HalState::READY) {
+ old_state = mState;
+ } else {
+ mState = HalState::INITIALIZING;
+ }
+ }
- ALOGI("Unable to open Linux interface, trying default path.");
- mFd = getFdFromDevPath();
+ if (old_state != HalState::READY) {
+ ALOGE("initialize: Unexpected State %d", static_cast<int>(old_state));
+ Close();
+ callbacks->initialization_complete(callbacks->handle,
+ STATUS_ALREADY_INITIALIZED);
+ return;
+ }
+
+ mCallbacks = std::make_unique<struct hal_callbacks>(*callbacks);
+ management_.reset(new NetBluetoothMgmt);
+ mFd = management_->openHci();
if (mFd < 0) {
+ management_.reset();
+
+ ALOGI("Unable to open Linux interface, trying default path.");
+ mFd = getFdFromDevPath();
+ if (mFd < 0) {
+ mState = HalState::READY;
+ mCallbacks->initialization_complete(mCallbacks->handle,
+ STATUS_UNABLE_TO_OPEN_INTERFACE);
+ return;
+ }
+ }
+
+ // TODO: HCI Reset on emulators since the bluetooth controller
+ // cannot be powered on/off during the HAL setup; and the stack
+ // might received spurious packets/events during boottime.
+ // Proper solution would be to use bt-virtio or vsock to better
+ // control the link to rootcanal and the controller lifetime.
+ const std::string kBoardProperty = "ro.product.board";
+ const std::string kCuttlefishBoard = "cutf";
+ auto board_name = GetSystemProperty(kBoardProperty);
+ if (board_name.has_value() &&
+ (starts_with(board_name.value(), "cutf") ||
+ starts_with(board_name.value(), "goldfish"))) {
+ reset();
+ }
+
+ mH4 = std::make_shared<H4Protocol>(
+ mFd,
+ [](const std::vector<uint8_t>& /* raw_command */) {
+ LOG_ALWAYS_FATAL("Unexpected command!");
+ },
+ [this](const std::vector<uint8_t>& raw_acl) {
+ mCallbacks->acl_received(mCallbacks->handle, raw_acl.data(),
+ raw_acl.size());
+ },
+ [this](const std::vector<uint8_t>& raw_sco) {
+ mCallbacks->sco_received(mCallbacks->handle, raw_sco.data(),
+ raw_sco.size());
+ },
+ [this](const std::vector<uint8_t>& raw_event) {
+ mCallbacks->event_received(mCallbacks->handle, raw_event.data(),
+ raw_event.size());
+ },
+ [this](const std::vector<uint8_t>& raw_iso) {
+ mCallbacks->iso_received(mCallbacks->handle, raw_iso.data(),
+ raw_iso.size());
+ },
+ [this]() {
+ ALOGI("HCI socket device disconnected");
+ mFdWatcher.StopWatchingFileDescriptors();
+ });
+ mFdWatcher.WatchFdForNonBlockingReads(mFd,
+ [this](int) { mH4->OnDataReady(); });
+
+ {
+ std::lock_guard<std::mutex> guard(mStateMutex);
+ mState = HalState::ONE_CLIENT;
+ }
+
+ ALOGI("initialization complete");
+ mCallbacks->initialization_complete(mCallbacks->handle, STATUS_SUCCESS);
+ }
+
+ void Close() {
+ ALOGI(__func__);
+ {
+ std::lock_guard<std::mutex> guard(mStateMutex);
+ if (mState != HalState::ONE_CLIENT) {
+ LOG_ALWAYS_FATAL_IF(mState == HalState::INITIALIZING,
+ "mState is INITIALIZING");
+ ALOGI("Already closed");
+ return;
+ }
+ mCallbacks.reset();
+ mState = HalState::CLOSING;
+ }
+
+ mFdWatcher.StopWatchingFileDescriptors();
+
+ if (management_) {
+ management_->closeHci();
+ } else {
+ ::close(mFd);
+ }
+
+ {
+ std::lock_guard<std::mutex> guard(mStateMutex);
mState = HalState::READY;
- cb->initializationComplete(Status::UNABLE_TO_OPEN_INTERFACE);
- return ndk::ScopedAStatus::ok();
+ mH4 = nullptr;
}
}
- mDeathRecipient->LinkToDeath(mCb);
-
- // TODO: HCI Reset on emulators since the bluetooth controller
- // cannot be powered on/off during the HAL setup; and the stack
- // might received spurious packets/events during boottime.
- // Proper solution would be to use bt-virtio or vsock to better
- // control the link to rootcanal and the controller lifetime.
- const std::string kBoardProperty = "ro.product.board";
- const std::string kCuttlefishBoard = "cutf";
- auto board_name = GetSystemProperty(kBoardProperty);
- if (board_name.has_value() && (
- starts_with(board_name.value(), "cutf") ||
- starts_with(board_name.value(), "goldfish"))) {
- reset();
+ void SendCommand(const std::vector<uint8_t>& data) {
+ send(PacketType::COMMAND, data);
+ }
+ void SendAcl(const std::vector<uint8_t>& data) {
+ send(PacketType::ACL_DATA, data);
+ }
+ void SendSco(const std::vector<uint8_t>& data) {
+ send(PacketType::SCO_DATA, data);
+ }
+ void SendIso(const std::vector<uint8_t>& data) {
+ send(PacketType::ISO_DATA, data);
}
- mH4 = std::make_shared<H4Protocol>(
- mFd,
- [](const std::vector<uint8_t>& /* raw_command */) {
- LOG_ALWAYS_FATAL("Unexpected command!");
- },
- [this](const std::vector<uint8_t>& raw_acl) {
- mCb->aclDataReceived(raw_acl);
- },
- [this](const std::vector<uint8_t>& raw_sco) {
- mCb->scoDataReceived(raw_sco);
- },
- [this](const std::vector<uint8_t>& raw_event) {
- mCb->hciEventReceived(raw_event);
- },
- [this](const std::vector<uint8_t>& raw_iso) {
- mCb->isoDataReceived(raw_iso);
- },
- [this]() {
- ALOGI("HCI socket device disconnected");
- mFdWatcher.StopWatchingFileDescriptors();
- });
- mFdWatcher.WatchFdForNonBlockingReads(mFd,
- [this](int) { mH4->OnDataReady(); });
-
- {
- std::lock_guard<std::mutex> guard(mStateMutex);
- mState = HalState::ONE_CLIENT;
- }
- ALOGI("initialization complete");
- auto status = mCb->initializationComplete(Status::SUCCESS);
- if (!status.isOk()) {
- if (!mDeathRecipient->getHasDied()) {
- ALOGE("Error sending init callback, but no death notification");
+ bool send(PacketType type, const std::vector<uint8_t>& v) {
+ if (v.empty()) {
+ ALOGE("Packet is empty, no data was found to be sent");
+ return false;
}
- close();
- return ndk::ScopedAStatus::fromServiceSpecificError(
- STATUS_FAILED_TRANSACTION);
- }
- return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus BluetoothHci::close() {
- ALOGI(__func__);
- {
std::lock_guard<std::mutex> guard(mStateMutex);
- if (mState != HalState::ONE_CLIENT) {
- LOG_ALWAYS_FATAL_IF(mState == HalState::INITIALIZING,
- "mState is INITIALIZING");
- ALOGI("Already closed");
- return ndk::ScopedAStatus::ok();
+ if (mH4 == nullptr) {
+ ALOGE("Illegal State");
+ return false;
}
- mState = HalState::CLOSING;
+
+ mH4->Send(type, v);
+ return true;
}
- mFdWatcher.StopWatchingFileDescriptors();
+ std::unique_ptr<struct hal_callbacks> mCallbacks;
+ std::string mDevPath;
+ int mFd{-1};
+ ::android::hardware::bluetooth::async::AsyncFdWatcher mFdWatcher;
+ std::shared_ptr<::android::hardware::bluetooth::hci::H4Protocol> mH4;
+ std::unique_ptr<NetBluetoothMgmt> management_{};
- if (management_) {
- management_->closeHci();
- } else {
- ::close(mFd);
- }
-
- {
- std::lock_guard<std::mutex> guard(mStateMutex);
- mState = HalState::READY;
- mH4 = nullptr;
- }
- return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus BluetoothHci::sendHciCommand(
- const std::vector<uint8_t>& packet) {
- return send(PacketType::COMMAND, packet);
-}
-
-ndk::ScopedAStatus BluetoothHci::sendAclData(
- const std::vector<uint8_t>& packet) {
- return send(PacketType::ACL_DATA, packet);
-}
-
-ndk::ScopedAStatus BluetoothHci::sendScoData(
- const std::vector<uint8_t>& packet) {
- return send(PacketType::SCO_DATA, packet);
-}
-
-ndk::ScopedAStatus BluetoothHci::sendIsoData(
- const std::vector<uint8_t>& packet) {
- return send(PacketType::ISO_DATA, packet);
-}
-
-ndk::ScopedAStatus BluetoothHci::send(PacketType type,
- const std::vector<uint8_t>& v) {
- if (v.empty()) {
- ALOGE("Packet is empty, no data was found to be sent");
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
- }
-
- std::lock_guard<std::mutex> guard(mStateMutex);
- if (mH4 == nullptr) {
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- }
-
- mH4->Send(type, v);
- return ndk::ScopedAStatus::ok();
-}
+ // Don't close twice or open before close is complete
+ std::mutex mStateMutex;
+ enum class HalState {
+ READY,
+ INITIALIZING,
+ ONE_CLIENT,
+ CLOSING,
+ } mState{HalState::READY};
+};
} // namespace aidl::android::hardware::bluetooth::impl
+
+extern "C" {
+
+using namespace aidl::android::hardware::bluetooth::impl;
+
+struct hal_interface hal_new() {
+ return (struct hal_interface){
+ .handle = new Hal(),
+ .initialize = &Hal::Initialize,
+ .close = &Hal::Close,
+ .send_command = &Hal::SendCommand,
+ .send_acl = &Hal::SendAcl,
+ .send_sco = &Hal::SendSco,
+ .send_iso = &Hal::SendIso,
+ };
+}
+}
diff --git a/bluetooth/aidl/default/BluetoothHci.h b/bluetooth/aidl/default/BluetoothHci.h
deleted file mode 100644
index 477cc5c..0000000
--- a/bluetooth/aidl/default/BluetoothHci.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <aidl/android/hardware/bluetooth/BnBluetoothHci.h>
-#include <aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.h>
-
-#include <future>
-#include <string>
-
-#include "async_fd_watcher.h"
-#include "h4_protocol.h"
-#include "net_bluetooth_mgmt.h"
-
-namespace aidl::android::hardware::bluetooth::impl {
-
-class BluetoothDeathRecipient;
-
-// This Bluetooth HAL implementation connects with a serial port at dev_path_.
-class BluetoothHci : public BnBluetoothHci {
- public:
- BluetoothHci(const std::string& dev_path = "/dev/hvc5");
-
- ndk::ScopedAStatus initialize(
- const std::shared_ptr<IBluetoothHciCallbacks>& cb) override;
-
- ndk::ScopedAStatus sendHciCommand(
- const std::vector<uint8_t>& packet) override;
-
- ndk::ScopedAStatus sendAclData(const std::vector<uint8_t>& packet) override;
-
- ndk::ScopedAStatus sendScoData(const std::vector<uint8_t>& packet) override;
-
- ndk::ScopedAStatus sendIsoData(const std::vector<uint8_t>& packet) override;
-
- ndk::ScopedAStatus close() override;
-
- static void OnPacketReady();
-
- static BluetoothHci* get();
-
- private:
- int mFd{-1};
- std::shared_ptr<IBluetoothHciCallbacks> mCb = nullptr;
-
- std::shared_ptr<::android::hardware::bluetooth::hci::H4Protocol> mH4;
-
- std::shared_ptr<BluetoothDeathRecipient> mDeathRecipient;
-
- std::string mDevPath;
-
- ::android::hardware::bluetooth::async::AsyncFdWatcher mFdWatcher;
-
- int getFdFromDevPath();
- [[nodiscard]] ndk::ScopedAStatus send(
- ::android::hardware::bluetooth::hci::PacketType type,
- const std::vector<uint8_t>& packet);
- std::unique_ptr<NetBluetoothMgmt> management_{};
-
- // Send a reset command and discard all packets until a reset is received.
- void reset();
-
- // Don't close twice or open before close is complete
- std::mutex mStateMutex;
- enum class HalState {
- READY,
- INITIALIZING,
- ONE_CLIENT,
- CLOSING,
- } mState{HalState::READY};
-};
-
-} // namespace aidl::android::hardware::bluetooth::impl
diff --git a/bluetooth/aidl/default/main.rs b/bluetooth/aidl/default/main.rs
new file mode 100644
index 0000000..b30162a
--- /dev/null
+++ b/bluetooth/aidl/default/main.rs
@@ -0,0 +1,58 @@
+// Copyright 2024, 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.
+
+use android_hardware_bluetooth::aidl::android::hardware::bluetooth::IBluetoothHci::{
+ self,
+ IBluetoothHci as _
+};
+use android_hardware_bluetooth::binder;
+use bluetooth_offload_hal::{ HciHalProxy, CInterface };
+use bluetooth_offload_leaudio_hci::LeAudioModuleBuilder;
+use log;
+use std::panic;
+
+fn new_hal() -> CInterface {
+ extern "C" { fn hal_new() -> CInterface; }
+ unsafe { hal_new() }
+}
+
+fn main() {
+ logger::init(
+ logger::Config::default()
+ .with_max_level(log::LevelFilter::Debug)
+ .with_tag_on_device("android.hardware.bluetooth"),
+ );
+
+ panic::set_hook(Box::new(|panic_info| {
+ log::error!("{}", panic_info);
+ }));
+
+ log::info!("Bluetooth HAL starting up");
+
+ binder::ProcessState::set_thread_pool_max_thread_count(0);
+ binder::ProcessState::start_thread_pool();
+
+ binder::add_service(
+ &format!("{}/default", IBluetoothHci::BpBluetoothHci::get_descriptor()),
+ IBluetoothHci::BnBluetoothHci::new_binder(
+ HciHalProxy::new(
+ vec![ Box::new(LeAudioModuleBuilder {}) ],
+ new_hal()
+ ),
+ binder::BinderFeatures::default(),
+ ).as_binder()
+ ).expect("Failed to register service");
+
+ binder::ProcessState::join_thread_pool();
+}
diff --git a/bluetooth/aidl/default/service.cpp b/bluetooth/aidl/default/service.cpp
deleted file mode 100644
index ef4b884..0000000
--- a/bluetooth/aidl/default/service.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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 "aidl.android.hardware.bluetooth.service.default"
-
-#include <aidl/android/hardware/bluetooth/IBluetoothHci.h>
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/HidlTransportSupport.h>
-
-#include "BluetoothHci.h"
-
-using ::aidl::android::hardware::bluetooth::impl::BluetoothHci;
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::joinRpcThreadpool;
-
-int main(int /* argc */, char** /* argv */) {
- ALOGI("Bluetooth HAL starting");
- if (!ABinderProcess_setThreadPoolMaxThreadCount(0)) {
- ALOGI("failed to set thread pool max thread count");
- return 1;
- }
-
- std::shared_ptr<BluetoothHci> service =
- ndk::SharedRefBase::make<BluetoothHci>();
- std::string instance = std::string() + BluetoothHci::descriptor + "/default";
- auto result =
- AServiceManager_addService(service->asBinder().get(), instance.c_str());
- if (result == STATUS_OK) {
- ABinderProcess_joinThreadPool();
- } else {
- ALOGE("Could not register as a service!");
- }
- return 0;
-}
diff --git a/bluetooth/aidl/default/test/fuzzer.cpp b/bluetooth/aidl/default/test/fuzzer.cpp
deleted file mode 100644
index e7a1eef..0000000
--- a/bluetooth/aidl/default/test/fuzzer.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.
- */
-
-#include <fuzzbinder/libbinder_ndk_driver.h>
-#include <fuzzer/FuzzedDataProvider.h>
-
-#include "BluetoothHci.h"
-
-using aidl::android::hardware::bluetooth::impl::BluetoothHci;
-using android::fuzzService;
-using ndk::SharedRefBase;
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- auto service = SharedRefBase::make<BluetoothHci>();
-
- fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
-
- return 0;
-}