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

Commit 7b8d3dc7 authored by Myles Watson's avatar Myles Watson Committed by android-build-merger
Browse files

Merge "HCI: Add classic interface definitions"

am: d800417a

Change-Id: If2710b9c0327ac8456984722524d464512abfe81
parents e3c8ae93 d800417a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ cc_library {
        "module.cc",
        ":BluetoothCommonSources",
        ":BluetoothHalSources",
        ":BluetoothHciSources",
        ":BluetoothPacketSources",
    ],
    generated_headers: [
+8 −0
Original line number Diff line number Diff line
filegroup {
    name: "BluetoothHciSources",
    srcs: [
        "hci_layer.cc",
    ],
}

filegroup {
    name: "BluetoothHciTestSources",
    srcs: [
        "acl_builder_test.cc",
        "hci_layer_test.cc",
    ],
}
+245 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 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 "hci/hci_layer.h"

#include "packet/packet_builder.h"

namespace {
using bluetooth::hci::CommandCompleteView;
using bluetooth::hci::CommandPacketBuilder;
using bluetooth::hci::CommandStatusView;
using bluetooth::hci::EventPacketView;
using bluetooth::os::Handler;

class EventHandler {
 public:
  EventHandler() : event_handler(), handler(nullptr) {}
  EventHandler(std::function<void(EventPacketView)> on_event, Handler* on_event_handler)
      : event_handler(on_event), handler(on_event_handler) {}
  std::function<void(EventPacketView)> event_handler;
  Handler* handler;
};

class CommandQueueEntry {
 public:
  CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
                    std::function<void(CommandStatusView)> on_status_function,
                    std::function<void(CommandCompleteView)> on_complete_function, Handler* handler)
      : command(std::move(command_packet)), on_status(on_status_function), on_complete(on_complete_function),
        caller_handler(handler) {}

  std::unique_ptr<CommandPacketBuilder> command;
  std::function<void(CommandStatusView)> on_status;
  std::function<void(CommandCompleteView)> on_complete;
  Handler* caller_handler;
};
}  // namespace

namespace bluetooth {
namespace hci {

using common::Address;
using common::BidiQueue;
using common::BidiQueueEnd;
using os::Handler;

struct HciLayer::impl : public hal::HciHalCallbacks {
  impl(HciLayer& module) : hal_(nullptr), module_(module) {
    RegisterEventHandler(EventCode::COMMAND_COMPLETE, [this](EventPacketView event) { CommandCompleteCallback(event); },
                         module_.GetHandler());
    RegisterEventHandler(EventCode::COMMAND_STATUS, [this](EventPacketView event) { CommandStatusCallback(event); },
                         module_.GetHandler());
  }

  void Start(hal::HciHal* hal) {
    hal_ = hal;
    hal_->registerIncomingPacketCallback(this);

    send_acl_ = [this](std::unique_ptr<hci::BasePacketBuilder> packet) {
      std::vector<uint8_t> bytes;
      BitInserter bi(bytes);
      packet->Serialize(bi);
      hal_->sendAclData(bytes);
    };
    send_sco_ = [this](std::unique_ptr<hci::BasePacketBuilder> packet) {
      std::vector<uint8_t> bytes;
      BitInserter bi(bytes);
      packet->Serialize(bi);
      hal_->sendScoData(bytes);
    };
    auto queue_end = acl_queue_.GetDownEnd();
    Handler* handler = module_.GetHandler();
    queue_end->RegisterDequeue(handler, [queue_end, this]() { send_acl_(queue_end->TryDequeue()); });
  }

  void Stop() {
    acl_queue_.GetDownEnd()->UnregisterDequeue();
    hal_ = nullptr;
  }

  void CommandStatusCallback(EventPacketView event) {
    CommandStatusView status_view = CommandStatusView::Create(event);
    ASSERT(status_view.IsValid());
    if (command_queue_.size() == 0) {
      ASSERT_LOG(status_view.GetCommandOpCode() == OpCode::NONE, "Unexpected status event with OpCode 0x%02hx",
                 status_view.GetCommandOpCode());
      return;
    }
    // TODO: Check whether this is the CommandOpCode we're looking for.
    auto caller_handler = command_queue_.front().caller_handler;
    auto on_status = command_queue_.front().on_status;
    caller_handler->Post([on_status, status_view]() { on_status(status_view); });
    command_queue_.pop();
  }

  void CommandCompleteCallback(EventPacketView event) {
    CommandCompleteView complete_view = CommandCompleteView::Create(event);
    ASSERT(complete_view.IsValid());
    if (command_queue_.size() == 0) {
      ASSERT_LOG(complete_view.GetCommandOpCode() == OpCode::NONE,
                 "Unexpected command complete event with OpCode 0x%02hx", complete_view.GetCommandOpCode());
      return;
    }
    // TODO: Check whether this is the CommandOpCode we're looking for.
    auto caller_handler = command_queue_.front().caller_handler;
    auto on_complete = command_queue_.front().on_complete;
    caller_handler->Post([on_complete, complete_view]() { on_complete(complete_view); });
    command_queue_.pop();
  }

  void hciEventReceived(hal::HciPacket event_bytes) override {
    auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(event_bytes));
    EventPacketView event = EventPacketView::Create(packet);
    ASSERT(event.IsValid());
    EventCode event_code = event.GetEventCode();

    Handler* hci_handler = module_.GetHandler();
    hci_handler->Post([this, event, event_code]() {
      ASSERT_LOG(event_handlers_.find(event_code) != event_handlers_.end(), "Unhandled event of type 0x%02hhx",
                 event.GetEventCode());
      auto& registered_handler = event_handlers_[event_code].event_handler;
      event_handlers_[event_code].handler->Post([event, registered_handler]() { registered_handler(event); });
    });
    // TODO: Credits
  }

  void aclDataReceived(hal::HciPacket data_bytes) override {
    module_.GetHandler()->Post([this, data_bytes]() {
      auto queue_end = acl_queue_.GetDownEnd();
      Handler* hci_handler = module_.GetHandler();
      queue_end->RegisterEnqueue(hci_handler, [queue_end, data_bytes]() {
        auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(data_bytes));
        AclPacketView acl2 = AclPacketView::Create(packet);
        queue_end->UnregisterEnqueue();
        return std::make_unique<AclPacketView>(acl2);
      });
    });
  }

  void scoDataReceived(hal::HciPacket data_bytes) override {
    auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(data_bytes));
    ScoPacketView sco = ScoPacketView::Create(packet);
  }

  void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, std::function<void(CommandStatusView)> on_status,
                      std::function<void(CommandCompleteView)> on_complete, Handler* handler) {
    command_queue_.emplace(std::move(command), on_status, on_complete, handler);

    if (command_queue_.size() == 1) {
      std::vector<uint8_t> bytes;
      BitInserter bi(bytes);
      command_queue_.front().command->Serialize(bi);
      hal_->sendHciCommand(bytes);
    }
  }

  BidiQueueEnd<AclPacketBuilder, AclPacketView>* GetAclQueueEnd() {
    return acl_queue_.GetUpEnd();
  }

  void RegisterEventHandler(EventCode event_code, std::function<void(EventPacketView)> event_handler,
                            Handler* handler) {
    ASSERT_LOG(event_handlers_.count(event_code) == 0, "Can not register a second handler for event_code %02hhx",
               event_code);
    EventHandler to_save(event_handler, handler);
    event_handlers_[event_code] = to_save;
  }

  void UnregisterEventHandler(EventCode event_code) {
    event_handlers_.erase(event_code);
  }

  // The HAL
  hal::HciHal* hal_;

  // A reference to the HciLayer module
  HciLayer& module_;

  // Conversion functions for sending bytes from Builders
  std::function<void(std::unique_ptr<hci::BasePacketBuilder>)> send_acl_;
  std::function<void(std::unique_ptr<hci::BasePacketBuilder>)> send_sco_;

  // Command Handling
  std::queue<CommandQueueEntry> command_queue_;

  std::map<EventCode, EventHandler> event_handlers_;
  OpCode waiting_command_;

  // Acl packets
  BidiQueue<AclPacketView, AclPacketBuilder> acl_queue_{3 /* TODO: Set queue depth */};
};

HciLayer::HciLayer() : impl_(std::make_unique<impl>(*this)) {}

HciLayer::~HciLayer() {
  impl_.reset();
}

void HciLayer::EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
                              std::function<void(CommandStatusView)> on_status,
                              std::function<void(CommandCompleteView)> on_complete, Handler* handler) {
  impl_->EnqueueCommand(std::move(command), on_status, on_complete, handler);
}

common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* HciLayer::GetAclQueueEnd() {
  return impl_->GetAclQueueEnd();
}

void HciLayer::RegisterEventHandler(EventCode event_code, std::function<void(EventPacketView)> event_handler,
                                    Handler* handler) {
  impl_->RegisterEventHandler(event_code, event_handler, handler);
}

void HciLayer::UnregisterEventHandler(EventCode event_code) {
  impl_->UnregisterEventHandler(event_code);
}

const ModuleFactory HciLayer::Factory = ModuleFactory([]() { return new HciLayer(); });

void HciLayer::ListDependencies(ModuleList* list) {
  list->add<hal::HciHal>();
}

void HciLayer::Start() {
  impl_->Start(GetDependency<hal::HciHal>());
}

void HciLayer::Stop() {
  impl_->Stop();
}
}  // namespace hci
}  // namespace bluetooth
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 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 <map>

#include "common/address.h"
#include "common/bidi_queue.h"
#include "common/class_of_device.h"
#include "hal/hci_hal.h"
#include "hci/hci_packets.h"
#include "module.h"
#include "os/utils.h"

namespace bluetooth {
namespace hci {

class HciLayer : public Module {
 public:
  HciLayer();
  virtual ~HciLayer();
  DISALLOW_COPY_AND_ASSIGN(HciLayer);

  virtual void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
                              std::function<void(CommandStatusView)> on_status,
                              std::function<void(CommandCompleteView)> on_complete, os::Handler* handler);

  virtual common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* GetAclQueueEnd();

  virtual void RegisterEventHandler(EventCode event_code, std::function<void(EventPacketView)> event_handler,
                                    os::Handler* handler);

  virtual void UnregisterEventHandler(EventCode event_code);

  static const ModuleFactory Factory;

  void ListDependencies(ModuleList* list) override;

  void Start() override;

  void Stop() override;

 private:
  struct impl;
  std::unique_ptr<impl> impl_;
};
}  // namespace hci
}  // namespace bluetooth
+287 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 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 "hci/hci_layer.h"

#include <gtest/gtest.h>
#include <list>
#include <memory>

#include "hal/hci_hal.h"
#include "hci/hci_packets.h"
#include "module.h"
#include "os/log.h"
#include "os/thread.h"
#include "packet/bit_inserter.h"
#include "packet/raw_builder.h"

using bluetooth::os::Thread;
using bluetooth::packet::BitInserter;
using bluetooth::packet::RawBuilder;
using std::vector;

namespace {
vector<uint8_t> information_request = {
    0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
};
// 0x00, 0x01, 0x02, 0x03, ...
vector<uint8_t> counting_bytes;
// 0xFF, 0xFE, 0xFD, 0xFC, ...
vector<uint8_t> counting_down_bytes;
const size_t count_size = 0x8;

}  // namespace

namespace bluetooth {
namespace hci {

class TestHciHal : public hal::HciHal {
 public:
  TestHciHal() : hal::HciHal() {}

  virtual void registerIncomingPacketCallback(hal::HciHalCallbacks* callback) {
    callbacks = callback;
  }

  virtual void sendHciCommand(hal::HciPacket command) {
    outgoing_commands_.push_back(std::move(command));
  }

  virtual void sendAclData(hal::HciPacket data) {
    outgoing_acl_.push_front(std::move(data));
  }

  virtual void sendScoData(hal::HciPacket data) {
    outgoing_sco_.push_front(std::move(data));
  }

  hal::HciHalCallbacks* callbacks = nullptr;

  PacketView<kLittleEndian> GetPacketView(hal::HciPacket data) {
    auto shared = std::make_shared<std::vector<uint8_t>>(data);
    return PacketView<kLittleEndian>(shared);
  }

  PacketView<kLittleEndian> GetSentCommand() {
    while (outgoing_commands_.size() == 0)
      ;
    auto packetview = GetPacketView(std::move(outgoing_commands_.front()));
    outgoing_commands_.pop_front();
    return packetview;
  }

  PacketView<kLittleEndian> GetSentAcl() {
    while (outgoing_acl_.size() == 0)
      ;
    auto packetview = GetPacketView(std::move(outgoing_acl_.front()));
    outgoing_acl_.pop_front();
    return packetview;
  }

  void Start() {}

  void Stop() {}

  void ListDependencies(ModuleList*) {}

  static const ModuleFactory Factory;

 private:
  std::list<hal::HciPacket> outgoing_commands_;
  std::list<hal::HciPacket> outgoing_acl_;
  std::list<hal::HciPacket> outgoing_sco_;
};

const ModuleFactory TestHciHal::Factory = ModuleFactory([]() { return new TestHciHal(); });

class DependsOnHci : public Module {
 public:
  DependsOnHci() : Module() {}

  void SendHciCommand(std::unique_ptr<CommandPacketBuilder> command) {
    hci_->EnqueueCommand(std::move(command), [this](CommandStatusView status) { incoming_events_.push_back(status); },
                         [this](CommandCompleteView complete) { incoming_events_.push_back(complete); }, GetHandler());
  }

  void SendAclData(std::unique_ptr<AclPacketBuilder> acl) {
    AclPacketBuilder* raw_acl_pointer = acl.release();
    auto queue_end = hci_->GetAclQueueEnd();
    queue_end->RegisterEnqueue(GetHandler(), [queue_end, raw_acl_pointer]() -> std::unique_ptr<AclPacketBuilder> {
      queue_end->UnregisterEnqueue();
      return std::unique_ptr<AclPacketBuilder>(raw_acl_pointer);
    });
  }

  EventPacketView GetReceivedEvent() {
    while (incoming_events_.size() == 0)
      ;
    EventPacketView packetview = incoming_events_.front();
    incoming_events_.pop_front();
    return packetview;
  }

  AclPacketView GetReceivedAcl() {
    auto queue_end = hci_->GetAclQueueEnd();
    std::unique_ptr<AclPacketView> incoming_acl_ptr;
    while (incoming_acl_ptr == nullptr) {
      incoming_acl_ptr = queue_end->TryDequeue();
    }
    AclPacketView packetview = *incoming_acl_ptr;
    return packetview;
  }

  void Start() {
    hci_ = GetDependency<HciLayer>();
    hci_->RegisterEventHandler(EventCode::CONNECTION_COMPLETE,
                               [this](EventPacketView event) { incoming_events_.push_back(event); }, GetHandler());
  }

  void Stop() {}

  void ListDependencies(ModuleList* list) {
    list->add<HciLayer>();
  }

  static const ModuleFactory Factory;

 private:
  HciLayer* hci_ = nullptr;
  std::list<EventPacketView> incoming_events_;
};

const ModuleFactory DependsOnHci::Factory = ModuleFactory([]() { return new DependsOnHci(); });

class HciTest : public ::testing::Test {
 public:
  void SetUp() override {
    counting_bytes.reserve(count_size);
    counting_down_bytes.reserve(count_size);
    for (size_t i = 0; i < count_size; i++) {
      counting_bytes.push_back(i);
      counting_down_bytes.push_back(~i);
    }
    thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
    hal = new TestHciHal();
    fake_registry_.inject_test_module(&hal::HciHal::Factory, hal, thread_);
    fake_registry_.Start<DependsOnHci>(thread_);
    hci = fake_registry_.get_module_under_test<HciLayer>();
    upper = fake_registry_.get_module_under_test<DependsOnHci>();
    ASSERT(fake_registry_.IsStarted<HciLayer>());
  }

  void TearDown() override {
    fake_registry_.StopAll();
    delete thread_;
  }

  std::vector<uint8_t> GetPacketBytes(std::unique_ptr<packet::BasePacketBuilder> packet) {
    std::vector<uint8_t> bytes;
    BitInserter i(bytes);
    bytes.reserve(packet->size());
    packet->Serialize(i);
    return bytes;
  }

  DependsOnHci* upper = nullptr;
  TestHciHal* hal = nullptr;
  HciLayer* hci = nullptr;
  ModuleRegistry fake_registry_;
  Thread* thread_ = nullptr;
};

TEST_F(HciTest, initAndClose) {}

TEST_F(HciTest, createConnectionTest) {
  // Send CreateConnection to the controller
  common::Address bd_addr;
  ASSERT_TRUE(common::Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
  uint16_t packet_type = 0x1234;
  PageScanRepetitionMode page_scan_repetition_mode = PageScanRepetitionMode::R0;
  uint16_t clock_offset = 0x3456;
  ClockOffsetValid clock_offset_valid = ClockOffsetValid::VALID;
  CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
  upper->SendHciCommand(CreateConnectionBuilder::Create(bd_addr, packet_type, page_scan_repetition_mode, clock_offset,
                                                        clock_offset_valid, allow_role_switch));

  // Check the command
  auto sent_command = hal->GetSentCommand();
  ASSERT_LT(0, sent_command.size());
  CreateConnectionView view =
      CreateConnectionView::Create(ConnectionManagementCommandView::Create(CommandPacketView::Create(sent_command)));
  ASSERT_TRUE(view.IsValid());
  ASSERT_EQ(bd_addr, view.GetBdAddr());
  ASSERT_EQ(packet_type, view.GetPacketType());
  ASSERT_EQ(page_scan_repetition_mode, view.GetPageScanRepetitionMode());
  ASSERT_EQ(clock_offset, view.GetClockOffset());
  ASSERT_EQ(clock_offset_valid, view.GetClockOffsetValid());
  ASSERT_EQ(allow_role_switch, view.GetAllowRoleSwitch());

  // Send a ConnectionComplete to the host
  ErrorCode status = ErrorCode::SUCCESS;
  uint16_t handle = 0x123;
  LinkType link_type = LinkType::ACL;
  Enable encryption_enabled = Enable::DISABLED;
  hal->callbacks->hciEventReceived(
      GetPacketBytes(ConnectionCompleteBuilder::Create(status, handle, bd_addr, link_type, encryption_enabled)));

  // Verify the event
  auto event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.IsValid());
  ASSERT_EQ(EventCode::CONNECTION_COMPLETE, event.GetEventCode());
  ConnectionCompleteView connection_complete_view = ConnectionCompleteView::Create(event);
  ASSERT_TRUE(connection_complete_view.IsValid());
  ASSERT_EQ(status, connection_complete_view.GetStatus());
  ASSERT_EQ(handle, connection_complete_view.GetConnectionHandle());
  ASSERT_EQ(link_type, connection_complete_view.GetLinkType());
  ASSERT_EQ(encryption_enabled, connection_complete_view.GetEncryptionEnabled());

  // Send an ACL packet from the remote
  PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::COMPLETE_PDU;
  BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
  auto acl_payload = std::make_unique<RawBuilder>();
  acl_payload->AddAddress(bd_addr);
  acl_payload->AddOctets2(handle);
  hal->callbacks->aclDataReceived(
      GetPacketBytes(AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(acl_payload))));

  // Verify the ACL packet
  auto acl_view = upper->GetReceivedAcl();
  ASSERT_TRUE(acl_view.IsValid());
  ASSERT_EQ(sizeof(bd_addr) + sizeof(handle), acl_view.GetPayload().size());
  auto itr = acl_view.GetPayload().begin();
  ASSERT_EQ(bd_addr, itr.extract<Address>());
  ASSERT_EQ(handle, itr.extract<uint16_t>());

  // Send an ACL packet from DependsOnHci
  PacketBoundaryFlag packet_boundary_flag2 = PacketBoundaryFlag::COMPLETE_PDU;
  BroadcastFlag broadcast_flag2 = BroadcastFlag::POINT_TO_POINT;
  auto acl_payload2 = std::make_unique<RawBuilder>();
  acl_payload2->AddOctets2(handle);
  acl_payload2->AddAddress(bd_addr);
  upper->SendAclData(AclPacketBuilder::Create(handle, packet_boundary_flag2, broadcast_flag2, std::move(acl_payload2)));

  // Verify the ACL packet
  auto sent_acl = hal->GetSentAcl();
  ASSERT_LT(0, sent_acl.size());
  AclPacketView sent_acl_view = AclPacketView::Create(sent_acl);
  ASSERT_TRUE(sent_acl_view.IsValid());
  ASSERT_EQ(sizeof(bd_addr) + sizeof(handle), sent_acl_view.GetPayload().size());
  auto sent_itr = sent_acl_view.GetPayload().begin();
  ASSERT_EQ(handle, sent_itr.extract<uint16_t>());
  ASSERT_EQ(bd_addr, sent_itr.extract<Address>());
}
}  // namespace hci
}  // namespace bluetooth