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

Commit 5ccd0321 authored by Zach Johnson's avatar Zach Johnson
Browse files

rusty-gd: Add cxx interop layer for the BT HIDL HAL

Bug: 171749953
Tag: #gd-refactor
Test: gd/cert/run --rhost SimpleHalTest
Change-Id: Id8f90a59bdce36224d9de2a05746227a69dc24fb
parent a893d66c
Loading
Loading
Loading
Loading
+2 −6
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@ use rootservice::*;
use rootservice_grpc::{create_root_facade, RootFacade};

use bt_hal::facade::HciHalFacadeService;
use bt_hal::hal_facade_module;
use bt_hal::hal_module;
use bt_hal::rootcanal_hal::RootcanalConfig;
use bt_hci::facade::HciLayerFacadeService;
use bt_hci::hci_module;
@@ -34,7 +34,7 @@ use futures::executor::block_on;
module! {
    stack_module,
    submodules {
        hal_facade_module,
        hal_module,
        hci_module,
    }
}
@@ -113,10 +113,6 @@ impl FacadeServiceManager {
                        let registry = {
                            let mut builder = RegistryBuilder::new();
                            builder.register_module(stack_module);
                            if rootcanal_port.is_some() {
                                builder.register_module(bt_hal::rootcanal_hal_module);
                            }

                            Arc::new(builder.build())
                        };

+41 −0
Original line number Diff line number Diff line
@@ -14,6 +14,47 @@ rust_library {
        "libprotobuf",
        "libbt_packets",
        "libgddi",
        "libcxx",
        "liblazy_static",
    ],
    host_supported: true,
    target: {
        android: {
            static_libs: ["libbt_hidl_hal_cxx"],
            shared_libs: [
                "android.hardware.bluetooth@1.0",
                "libhidlbase",
                "libutils",
            ],
        },
    },
}

genrule {
    name: "libbt_hidl_hal_bridge_header",
    tools: ["cxxbridge"],
    cmd: "$(location cxxbridge) $(in) --header > $(out)",
    srcs: ["src/hidl_hal.rs"],
    out: ["src/hidl_hal.rs.h"],
}

genrule {
    name: "libbt_hidl_hal_bridge_code",
    tools: ["cxxbridge"],
    cmd: "$(location cxxbridge) $(in) >> $(out)",
    srcs: ["src/hidl_hal.rs"],
    out: ["hidl_hal_generated.cc"],
}

cc_library_static {
    name: "libbt_hidl_hal_cxx",
    srcs: ["src/hidl/interop.cc"],
    local_include_dirs: ["src/hidl"],
    generated_headers: ["libbt_hidl_hal_bridge_header", "cxx-bridge-header"],
    generated_sources: ["libbt_hidl_hal_bridge_code"],
    shared_libs: [
        "android.hardware.bluetooth@1.0",
        "libhidlbase",
        "libutils",
    ],
}
+100 −0
Original line number Diff line number Diff line
#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
#include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
#include <android/hardware/bluetooth/1.0/types.h>
#include <stdlib.h>

#include "../../os/log.h"
#include "src/hidl/interop.h"

using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
using ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
using HidlStatus = ::android::hardware::bluetooth::V1_0::Status;

namespace bluetooth {
namespace hal {
namespace {

class HciDeathRecipient : public ::android::hardware::hidl_death_recipient {
 public:
  virtual void serviceDied(uint64_t /*cookie*/, const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
    LOG_ERROR("Bluetooth HAL service died!");
    abort();
  }
};

class HciCallbackTrampoline : public IBluetoothHciCallbacks {
 public:
  HciCallbackTrampoline() {}

  Return<void> initializationComplete(HidlStatus status) {
    ASSERT(status == HidlStatus::SUCCESS);
    on_init_complete();
    return Void();
  }

  Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
    on_event(rust::Slice(&event[0], event.size()));
    return Void();
  }

  Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
    on_acl(rust::Slice(&data[0], data.size()));
    return Void();
  }

  Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
    on_sco(rust::Slice(&data[0], data.size()));
    return Void();
  }
};

android::sp<HciDeathRecipient> hci_death_recipient_ = new HciDeathRecipient();
android::sp<IBluetoothHci> bt_hci_;
android::sp<HciCallbackTrampoline> trampoline_;

}  // namespace

void start_hal() {
  ASSERT(bt_hci_ == nullptr);

  bt_hci_ = IBluetoothHci::getService();
  ASSERT(bt_hci_ != nullptr);
  auto death_link = bt_hci_->linkToDeath(hci_death_recipient_, 0);
  ASSERT_LOG(death_link.isOk(), "Unable to set the death recipient for the Bluetooth HAL");

  trampoline_ = new HciCallbackTrampoline();
  bt_hci_->initialize(trampoline_);
}

void stop_hal() {
  ASSERT(bt_hci_ != nullptr);

  auto death_unlink = bt_hci_->unlinkToDeath(hci_death_recipient_);
  if (!death_unlink.isOk()) {
    LOG_ERROR("Error unlinking death recipient from the Bluetooth HAL");
  }
  bt_hci_->close();
  bt_hci_ = nullptr;
  trampoline_ = nullptr;
}

void send_command(rust::Slice<uint8_t> data) {
  ASSERT(bt_hci_ != nullptr);
  bt_hci_->sendHciCommand(hidl_vec<uint8_t>(data.data(), data.data() + data.length()));
}

void send_acl(rust::Slice<uint8_t> data) {
  ASSERT(bt_hci_ != nullptr);
  bt_hci_->sendAclData(hidl_vec<uint8_t>(data.data(), data.data() + data.length()));
}

void send_sco(rust::Slice<uint8_t> data) {
  ASSERT(bt_hci_ != nullptr);
  bt_hci_->sendScoData(hidl_vec<uint8_t>(data.data(), data.data() + data.length()));
}

}  // namespace hal
}  // namespace bluetooth
+14 −0
Original line number Diff line number Diff line
#pragma once
#include "src/hidl_hal.rs.h"

namespace bluetooth {
namespace hal {

void start_hal();
void stop_hal();
void send_command(rust::Slice<uint8_t> data);
void send_acl(rust::Slice<uint8_t> data);
void send_sco(rust::Slice<uint8_t> data);

}  // namespace hal
}  // namespace bluetooth
+103 −0
Original line number Diff line number Diff line
//! Implementation of the HAl that talks to BT controller over Android's HIDL
use crate::{Hal, HalExports};
use bt_packet::{HciCommand, HciEvent, RawPacket};
use bytes::Bytes;
use gddi::{module, provides};
use std::sync::Arc;
use std::sync::Mutex;
use tokio::runtime::Runtime;
use tokio::select;
use tokio::sync::mpsc;

module! {
    hidl_hal_module,
    providers {
        HalExports => provide_hidl_hal,
    }
}

#[provides]
async fn provide_hidl_hal(rt: Arc<Runtime>) -> HalExports {
    let (hal_exports, hal) = Hal::new();
    let (init_tx, mut init_rx) = mpsc::unbounded_channel();
    *CALLBACKS.lock().unwrap() = Some(Callbacks {
        init_tx,
        evt_tx: hal.evt_tx,
        acl_tx: hal.acl_tx,
    });
    ffi::start_hal();
    init_rx.recv().await.unwrap();

    rt.spawn(dispatch_outgoing(hal.cmd_rx, hal.acl_rx));

    hal_exports
}

#[cxx::bridge(namespace = bluetooth::hal)]
mod ffi {
    extern "C" {
        include!("src/hidl/interop.h");
        fn start_hal();
        fn stop_hal();
        fn send_command(data: &[u8]);
        fn send_acl(data: &[u8]);
        fn send_sco(data: &[u8]);
    }

    extern "Rust" {
        fn on_init_complete();
        fn on_event(data: &[u8]);
        fn on_acl(data: &[u8]);
        fn on_sco(data: &[u8]);
    }
}

struct Callbacks {
    init_tx: mpsc::UnboundedSender<()>,
    evt_tx: mpsc::UnboundedSender<HciEvent>,
    acl_tx: mpsc::UnboundedSender<RawPacket>,
}

lazy_static! {
    static ref CALLBACKS: Mutex<Option<Callbacks>> = Mutex::new(None);
}

fn on_init_complete() {
    let callbacks = CALLBACKS.lock().unwrap();
    callbacks.as_ref().unwrap().init_tx.send(()).unwrap();
}

fn on_event(data: &[u8]) {
    let callbacks = CALLBACKS.lock().unwrap();
    callbacks
        .as_ref()
        .unwrap()
        .evt_tx
        .send(Bytes::copy_from_slice(data))
        .unwrap();
}

fn on_acl(data: &[u8]) {
    let callbacks = CALLBACKS.lock().unwrap();
    callbacks
        .as_ref()
        .unwrap()
        .acl_tx
        .send(Bytes::copy_from_slice(data))
        .unwrap();
}

fn on_sco(_data: &[u8]) {}

async fn dispatch_outgoing(
    mut cmd_rx: mpsc::UnboundedReceiver<HciCommand>,
    mut acl_rx: mpsc::UnboundedReceiver<RawPacket>,
) {
    loop {
        select! {
            Some(cmd) = cmd_rx.recv() => ffi::send_command(&cmd),
            Some(acl) = acl_rx.recv() => ffi::send_acl(&acl),
            else => break,
        }
    }
}
Loading