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

Commit a1d3bb59 authored by Zach Johnson's avatar Zach Johnson
Browse files

rusty-gd: implement command sending via HCI shim

Bug: 171749953
Tag: #gd-refactor
Test: gd/cert/run --rhost SimpleHalTest
Change-Id: I5f2ae5613b395a57bd23f7772912383b5473d47b
parent bfa97a39
Loading
Loading
Loading
Loading
+30 −4
Original line number Diff line number Diff line
@@ -7,18 +7,44 @@ namespace bluetooth {
namespace shim {
namespace rust {

class u8SliceCallback {
template <class TArg>
class TrampolineCallback {
 public:
  u8SliceCallback(base::Callback<void(::rust::Slice<uint8_t>)> callback) : callback_(callback) {}
  TrampolineCallback(base::Callback<void(TArg)> callback) : callback_(callback) {}

  void Run(::rust::Slice<uint8_t> value) const {
  void Run(TArg value) const {
    callback_.Run(value);
  }

 private:
  base::Callback<void(::rust::Slice<uint8_t>)> callback_;
  base::Callback<void(TArg)> callback_;
};

template <class TArg>
class TrampolineOnceCallback {
 public:
  TrampolineOnceCallback(base::OnceCallback<void(TArg)> callback)
      : callback_(new base::OnceCallback<void(TArg)>(std::move(callback))) {}
  ~TrampolineOnceCallback() {
    if (callback_ != nullptr) {
      delete callback_;
      callback_ = nullptr;
    }
  }

  void Run(TArg value) const {
    std::move(*callback_).Run(value);
    delete callback_;
    callback_ == nullptr;
  }

 private:
  base::OnceCallback<void(TArg)>* callback_;
};

using u8SliceCallback = TrampolineCallback<::rust::Slice<uint8_t>>;
using u8SliceOnceCallback = TrampolineOnceCallback<::rust::Slice<uint8_t>>;

}  // namespace rust
}  // namespace shim
}  // namespace bluetooth
+6 −3
Original line number Diff line number Diff line
@@ -15,8 +15,10 @@ mod ffi {
        include!("callbacks/callbacks.h");

        type u8SliceCallback;
        fn Run(self: &u8SliceCallback, data: &[u8]);

        fn Run(&self, data: &[u8]);
        type u8SliceOnceCallback;
        fn Run(self: &u8SliceOnceCallback, data: &[u8]);
    }

    extern "Rust" {
@@ -26,7 +28,7 @@ mod ffi {
        fn hci_set_evt_callback(hci: &mut Hci, callback: UniquePtr<u8SliceCallback>);
        fn hci_set_le_evt_callback(hci: &mut Hci, callback: UniquePtr<u8SliceCallback>);

        fn hci_send_command(hci: &mut Hci, data: &[u8], callback: UniquePtr<u8SliceCallback>);
        fn hci_send_command(hci: &mut Hci, data: &[u8], callback: UniquePtr<u8SliceOnceCallback>);
        fn hci_send_acl(hci: &mut Hci, data: &[u8]);
        fn hci_register_event(hci: &mut Hci, event: u8);
        fn hci_register_le_event(hci: &mut Hci, subevent: u8);
@@ -35,6 +37,7 @@ mod ffi {

// we take ownership when we get the callbacks
unsafe impl Send for ffi::u8SliceCallback {}
unsafe impl Send for ffi::u8SliceOnceCallback {}

pub struct Hci {
    rt: Arc<Runtime>,
@@ -69,7 +72,7 @@ impl Hci {
pub fn hci_send_command(
    hci: &mut Hci,
    data: &[u8],
    callback: cxx::UniquePtr<ffi::u8SliceCallback>,
    callback: cxx::UniquePtr<ffi::u8SliceOnceCallback>,
) {
    let packet = CommandPacket::parse(data).unwrap();
    let mut clone_internal = hci.internal.clone();
+0 −12
Original line number Diff line number Diff line
#pragma once
#include "src/hci.rs.h"

namespace bluetooth {
namespace shim {
namespace rust {
void hci_on_acl(::rust::Slice<uint8_t> data);
void hci_on_event(::rust::Slice<uint8_t> data);
void hci_on_le_event(::rust::Slice<uint8_t> data);
}  // namespace rust
}  // namespace shim
}  // namespace bluetooth
+58 −9
Original line number Diff line number Diff line
@@ -273,15 +273,6 @@ static bool event_already_registered_in_le_scanning_manager(
  return false;
}

}  // namespace

namespace cpp {
bluetooth::common::BidiQueueEnd<bluetooth::hci::AclBuilder,
                                bluetooth::hci::AclView>* hci_queue_end =
    nullptr;
static bluetooth::os::EnqueueBuffer<bluetooth::hci::AclBuilder>* pending_data =
    nullptr;

class OsiObject {
 public:
  OsiObject(void* ptr) : ptr_(ptr) {}
@@ -300,6 +291,15 @@ class OsiObject {
  void* ptr_;
};

}  // namespace

namespace cpp {
bluetooth::common::BidiQueueEnd<bluetooth::hci::AclBuilder,
                                bluetooth::hci::AclView>* hci_queue_end =
    nullptr;
static bluetooth::os::EnqueueBuffer<bluetooth::hci::AclBuilder>* pending_data =
    nullptr;

static std::unique_ptr<bluetooth::packet::RawBuilder> MakeUniquePacket(
    const uint8_t* data, size_t len) {
  bluetooth::packet::RawBuilder builder;
@@ -502,6 +502,7 @@ using bluetooth::common::Unretained;
namespace rust {

using bluetooth::shim::rust::u8SliceCallback;
using bluetooth::shim::rust::u8SliceOnceCallback;

static BT_HDR* WrapRustPacketAndCopy(uint16_t event,
                                     ::rust::Slice<uint8_t>* data) {
@@ -531,9 +532,57 @@ static void on_event(::rust::Slice<uint8_t> data) {
                        WrapRustPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, &data));
}

void OnRustTransmitPacketCommandComplete(command_complete_cb complete_callback,
                                         void* context,
                                         ::rust::Slice<uint8_t> data) {
  BT_HDR* response = WrapRustPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, &data);
  complete_callback(response, context);
}

void OnRustTransmitPacketStatus(command_status_cb status_callback,
                                void* context,
                                std::unique_ptr<OsiObject> command,
                                ::rust::Slice<uint8_t> data) {
  ASSERT(data.length() >= 3);
  uint8_t status = data.data()[2];
  status_callback(status, static_cast<BT_HDR*>(command->Release()), context);
}

static void transmit_command(BT_HDR* command,
                             command_complete_cb complete_callback,
                             command_status_cb status_callback, void* context) {
  CHECK(command != nullptr);
  uint8_t* data = command->data + command->offset;
  size_t len = command->len;
  CHECK(len >= (kCommandOpcodeSize + kCommandLengthSize));

  // little endian command opcode
  uint16_t command_op_code = (data[1] << 8 | data[0]);
  // Gd stack API requires opcode specification and calculates length, so
  // no need to provide opcode or length here.
  data += (kCommandOpcodeSize + kCommandLengthSize);
  len -= (kCommandOpcodeSize + kCommandLengthSize);

  auto op_code = static_cast<const bluetooth::hci::OpCode>(command_op_code);

  LOG_DEBUG("Sending command %s", bluetooth::hci::OpCodeText(op_code).c_str());

  if (bluetooth::hci::Checker::IsCommandStatusOpcode(op_code)) {
    auto command_unique = std::make_unique<OsiObject>(command);
    bluetooth::shim::rust::hci_send_command(
        **bluetooth::shim::Stack::Stack::GetInstance()->GetRustHci(),
        ::rust::Slice(data, len),
        std::make_unique<u8SliceOnceCallback>(
            BindOnce(OnRustTransmitPacketStatus, status_callback, context,
                     std::move(command_unique))));
  } else {
    bluetooth::shim::rust::hci_send_command(
        **bluetooth::shim::Stack::Stack::GetInstance()->GetRustHci(),
        ::rust::Slice(data, len),
        std::make_unique<u8SliceOnceCallback>(BindOnce(
            OnRustTransmitPacketCommandComplete, complete_callback, context)));
    osi_free(command);
  }
}

static void transmit_fragment(uint8_t* stream, size_t length) {