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;
-}