OSDN Git Service

rusty-gd: Add cxx interop layer for the BT HIDL HAL
authorZach Johnson <zachoverflow@google.com>
Thu, 19 Nov 2020 04:29:56 +0000 (20:29 -0800)
committerZach Johnson <zachoverflow@google.com>
Tue, 24 Nov 2020 00:44:40 +0000 (16:44 -0800)
Bug: 171749953
Tag: #gd-refactor
Test: gd/cert/run --rhost SimpleHalTest
Change-Id: Id8f90a59bdce36224d9de2a05746227a69dc24fb

gd/rust/facade/src/lib.rs
gd/rust/hal/Android.bp
gd/rust/hal/src/hidl/interop.cc [new file with mode: 0644]
gd/rust/hal/src/hidl/interop.h [new file with mode: 0644]
gd/rust/hal/src/hidl_hal.rs [new file with mode: 0644]
gd/rust/hal/src/lib.rs

index 3e2aaf3..30fcf2e 100644 (file)
@@ -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())
                         };
 
index 6a8f4f4..3a805f0 100644 (file)
@@ -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",
+    ],
 }
diff --git a/gd/rust/hal/src/hidl/interop.cc b/gd/rust/hal/src/hidl/interop.cc
new file mode 100644 (file)
index 0000000..29b428e
--- /dev/null
@@ -0,0 +1,100 @@
+#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
diff --git a/gd/rust/hal/src/hidl/interop.h b/gd/rust/hal/src/hidl/interop.h
new file mode 100644 (file)
index 0000000..468996d
--- /dev/null
@@ -0,0 +1,14 @@
+#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
diff --git a/gd/rust/hal/src/hidl_hal.rs b/gd/rust/hal/src/hidl_hal.rs
new file mode 100644 (file)
index 0000000..643badd
--- /dev/null
@@ -0,0 +1,103 @@
+//! 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,
+        }
+    }
+}
index bb6ad84..25f68ac 100644 (file)
@@ -1,19 +1,47 @@
 //! HCI Hardware Abstraction Layer
 //! Supports sending HCI commands to the HAL and receving
 //! HCI events from the HAL
+#[cfg(target_os = "android")]
+#[macro_use]
+extern crate lazy_static;
+
 pub mod facade;
 pub mod rootcanal_hal;
+#[cfg(not(target_os = "android"))]
+use rootcanal_hal::rootcanal_hal_module;
 
-pub use facade::hal_facade_module;
-pub use rootcanal_hal::rootcanal_hal_module;
+#[cfg(target_os = "android")]
+mod hidl_hal;
+#[cfg(target_os = "android")]
+use hidl_hal::hidl_hal_module;
 
 use std::sync::Arc;
 use thiserror::Error;
 use tokio::sync::mpsc;
 use tokio::sync::Mutex;
+use gddi::module;
 
 use bt_packet::{HciCommand, HciEvent, RawPacket};
 
+use facade::hal_facade_module;
+
+#[cfg(target_os = "android")]
+module! {
+    hal_module,
+    submodules {
+        hal_facade_module,
+        hidl_hal_module
+    },
+}
+
+#[cfg(not(target_os = "android"))]
+module! {
+    hal_module,
+    submodules {
+        hal_facade_module,
+        rootcanal_hal_module
+    },
+}
 /// H4 packet header size
 const H4_HEADER_SIZE: usize = 1;