Loading system/gd/hci/acl_manager_test.cc +144 −436 File changed.Preview size limit exceeded, changes collapsed. Show changes system/gd/hci/hci_layer_fake.cc +68 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ namespace bluetooth { namespace hci { using common::BidiQueue; using common::BidiQueueEnd; using packet::kLittleEndian; using packet::PacketView; using packet::RawBuilder; Loading @@ -37,6 +39,22 @@ PacketView<packet::kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePack return packet::PacketView<packet::kLittleEndian>(bytes); } std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle) { static uint32_t packet_number = 1; auto payload = std::make_unique<RawBuilder>(); payload->AddOctets2(6); // L2CAP PDU size payload->AddOctets2(2); // L2CAP CID payload->AddOctets2(handle); payload->AddOctets4(packet_number++); return std::move(payload); } static std::unique_ptr<AclBuilder> NextAclPacket(uint16_t handle) { PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE; BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT; return AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, NextPayload(handle)); } void TestHciLayer::EnqueueCommand( std::unique_ptr<CommandBuilder> command, common::ContextualOnceCallback<void(CommandStatusView)> on_status) { std::lock_guard<std::mutex> lock(mutex_); Loading Loading @@ -150,10 +168,59 @@ void TestHciLayer::InitEmptyCommand() { ASSERT_TRUE(empty_command_view_.IsValid()); } void TestHciLayer::IncomingAclData(uint16_t handle) { os::Handler* hci_handler = GetHandler(); auto* queue_end = acl_queue_.GetDownEnd(); std::promise<void> promise; auto future = promise.get_future(); queue_end->RegisterEnqueue( hci_handler, common::Bind( [](decltype(queue_end) queue_end, uint16_t handle, std::promise<void> promise) { auto packet = GetPacketView(NextAclPacket(handle)); AclView acl2 = AclView::Create(packet); queue_end->UnregisterEnqueue(); promise.set_value(); return std::make_unique<AclView>(acl2); }, queue_end, handle, common::Passed(std::move(promise)))); auto status = future.wait_for(std::chrono::milliseconds(1000)); ASSERT_EQ(status, std::future_status::ready); } void TestHciLayer::AssertNoOutgoingAclData() { auto queue_end = acl_queue_.GetDownEnd(); EXPECT_EQ(queue_end->TryDequeue(), nullptr); } PacketView<kLittleEndian> TestHciLayer::OutgoingAclData() { auto queue_end = acl_queue_.GetDownEnd(); std::unique_ptr<AclBuilder> received; do { received = queue_end->TryDequeue(); } while (received == nullptr); return GetPacketView(std::move(received)); } BidiQueueEnd<AclBuilder, AclView>* TestHciLayer::GetAclQueueEnd() { return acl_queue_.GetUpEnd(); } void TestHciLayer::Disconnect(uint16_t handle, ErrorCode reason) { GetHandler()->Post( common::BindOnce(&TestHciLayer::do_disconnect, common::Unretained(this), handle, reason)); } void TestHciLayer::do_disconnect(uint16_t handle, ErrorCode reason) { HciLayer::Disconnect(handle, reason); } void TestHciLayer::ListDependencies(ModuleList* list) const {} void TestHciLayer::Start() { std::lock_guard<std::mutex> lock(mutex_); InitEmptyCommand(); } void TestHciLayer::Stop() {} Loading system/gd/hci/hci_layer_fake.h +28 −13 Original line number Diff line number Diff line Loading @@ -25,10 +25,10 @@ namespace bluetooth { namespace hci { using packet::kLittleEndian; using packet::PacketView; packet::PacketView<packet::kLittleEndian> GetPacketView( std::unique_ptr<packet::BasePacketBuilder> packet); PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet); std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle); class TestHciLayer : public HciLayer { public: Loading Loading @@ -59,6 +59,16 @@ class TestHciLayer : public HciLayer { void CommandStatusCallback(EventView event); void IncomingAclData(uint16_t handle); void AssertNoOutgoingAclData(); packet::PacketView<packet::kLittleEndian> OutgoingAclData(); common::BidiQueueEnd<AclBuilder, AclView>* GetAclQueueEnd() override; void Disconnect(uint16_t handle, ErrorCode reason) override; protected: void ListDependencies(ModuleList* list) const override; void Start() override; Loading @@ -66,6 +76,7 @@ class TestHciLayer : public HciLayer { private: void InitEmptyCommand(); void do_disconnect(uint16_t handle, ErrorCode reason); // Handler-only state. Mutexes are not needed when accessing these fields. std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks; Loading @@ -73,9 +84,12 @@ class TestHciLayer : public HciLayer { std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_; std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_; // Most operations must acquire this mutex before manipulating shared state. The ONLY exception is blocking on a // promise, IF your thread is the only one mutating it. Note that SETTING a promise REQUIRES a lock, since another // thread may replace the promise while you are doing so. // thread-safe common::BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */}; // Most operations must acquire this mutex before manipulating shared state. The ONLY exception // is blocking on a promise, IF your thread is the only one mutating it. Note that SETTING a // promise REQUIRES a lock, since another thread may replace the promise while you are doing so. mutable std::mutex mutex_{}; // Shared state between the test and stack threads Loading @@ -83,13 +97,14 @@ class TestHciLayer : public HciLayer { // We start with Consumed=Set, Command=Unset. // When a command is enqueued, we set Command=set // When a command is popped, we block until Command=Set, then (if the queue is now empty) we reset Command=Unset and // set Consumed=Set. This way we emulate a blocking queue. // When a command is popped, we block until Command=Set, then (if the queue is now empty) we // reset Command=Unset and set Consumed=Set. This way we emulate a blocking queue. std::promise<void> command_promise_{}; // Set when at least one command is in the queue std::future<void> command_future_ = command_promise_.get_future(); // GetCommand() blocks until this is fulfilled std::future<void> command_future_ = command_promise_.get_future(); // GetCommand() blocks until this is fulfilled CommandView empty_command_view_ = CommandView::Create(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>())); CommandView empty_command_view_ = CommandView::Create( PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>())); }; } // namespace hci Loading Loading
system/gd/hci/acl_manager_test.cc +144 −436 File changed.Preview size limit exceeded, changes collapsed. Show changes
system/gd/hci/hci_layer_fake.cc +68 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ namespace bluetooth { namespace hci { using common::BidiQueue; using common::BidiQueueEnd; using packet::kLittleEndian; using packet::PacketView; using packet::RawBuilder; Loading @@ -37,6 +39,22 @@ PacketView<packet::kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePack return packet::PacketView<packet::kLittleEndian>(bytes); } std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle) { static uint32_t packet_number = 1; auto payload = std::make_unique<RawBuilder>(); payload->AddOctets2(6); // L2CAP PDU size payload->AddOctets2(2); // L2CAP CID payload->AddOctets2(handle); payload->AddOctets4(packet_number++); return std::move(payload); } static std::unique_ptr<AclBuilder> NextAclPacket(uint16_t handle) { PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE; BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT; return AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, NextPayload(handle)); } void TestHciLayer::EnqueueCommand( std::unique_ptr<CommandBuilder> command, common::ContextualOnceCallback<void(CommandStatusView)> on_status) { std::lock_guard<std::mutex> lock(mutex_); Loading Loading @@ -150,10 +168,59 @@ void TestHciLayer::InitEmptyCommand() { ASSERT_TRUE(empty_command_view_.IsValid()); } void TestHciLayer::IncomingAclData(uint16_t handle) { os::Handler* hci_handler = GetHandler(); auto* queue_end = acl_queue_.GetDownEnd(); std::promise<void> promise; auto future = promise.get_future(); queue_end->RegisterEnqueue( hci_handler, common::Bind( [](decltype(queue_end) queue_end, uint16_t handle, std::promise<void> promise) { auto packet = GetPacketView(NextAclPacket(handle)); AclView acl2 = AclView::Create(packet); queue_end->UnregisterEnqueue(); promise.set_value(); return std::make_unique<AclView>(acl2); }, queue_end, handle, common::Passed(std::move(promise)))); auto status = future.wait_for(std::chrono::milliseconds(1000)); ASSERT_EQ(status, std::future_status::ready); } void TestHciLayer::AssertNoOutgoingAclData() { auto queue_end = acl_queue_.GetDownEnd(); EXPECT_EQ(queue_end->TryDequeue(), nullptr); } PacketView<kLittleEndian> TestHciLayer::OutgoingAclData() { auto queue_end = acl_queue_.GetDownEnd(); std::unique_ptr<AclBuilder> received; do { received = queue_end->TryDequeue(); } while (received == nullptr); return GetPacketView(std::move(received)); } BidiQueueEnd<AclBuilder, AclView>* TestHciLayer::GetAclQueueEnd() { return acl_queue_.GetUpEnd(); } void TestHciLayer::Disconnect(uint16_t handle, ErrorCode reason) { GetHandler()->Post( common::BindOnce(&TestHciLayer::do_disconnect, common::Unretained(this), handle, reason)); } void TestHciLayer::do_disconnect(uint16_t handle, ErrorCode reason) { HciLayer::Disconnect(handle, reason); } void TestHciLayer::ListDependencies(ModuleList* list) const {} void TestHciLayer::Start() { std::lock_guard<std::mutex> lock(mutex_); InitEmptyCommand(); } void TestHciLayer::Stop() {} Loading
system/gd/hci/hci_layer_fake.h +28 −13 Original line number Diff line number Diff line Loading @@ -25,10 +25,10 @@ namespace bluetooth { namespace hci { using packet::kLittleEndian; using packet::PacketView; packet::PacketView<packet::kLittleEndian> GetPacketView( std::unique_ptr<packet::BasePacketBuilder> packet); PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet); std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle); class TestHciLayer : public HciLayer { public: Loading Loading @@ -59,6 +59,16 @@ class TestHciLayer : public HciLayer { void CommandStatusCallback(EventView event); void IncomingAclData(uint16_t handle); void AssertNoOutgoingAclData(); packet::PacketView<packet::kLittleEndian> OutgoingAclData(); common::BidiQueueEnd<AclBuilder, AclView>* GetAclQueueEnd() override; void Disconnect(uint16_t handle, ErrorCode reason) override; protected: void ListDependencies(ModuleList* list) const override; void Start() override; Loading @@ -66,6 +76,7 @@ class TestHciLayer : public HciLayer { private: void InitEmptyCommand(); void do_disconnect(uint16_t handle, ErrorCode reason); // Handler-only state. Mutexes are not needed when accessing these fields. std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks; Loading @@ -73,9 +84,12 @@ class TestHciLayer : public HciLayer { std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_; std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_; // Most operations must acquire this mutex before manipulating shared state. The ONLY exception is blocking on a // promise, IF your thread is the only one mutating it. Note that SETTING a promise REQUIRES a lock, since another // thread may replace the promise while you are doing so. // thread-safe common::BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */}; // Most operations must acquire this mutex before manipulating shared state. The ONLY exception // is blocking on a promise, IF your thread is the only one mutating it. Note that SETTING a // promise REQUIRES a lock, since another thread may replace the promise while you are doing so. mutable std::mutex mutex_{}; // Shared state between the test and stack threads Loading @@ -83,13 +97,14 @@ class TestHciLayer : public HciLayer { // We start with Consumed=Set, Command=Unset. // When a command is enqueued, we set Command=set // When a command is popped, we block until Command=Set, then (if the queue is now empty) we reset Command=Unset and // set Consumed=Set. This way we emulate a blocking queue. // When a command is popped, we block until Command=Set, then (if the queue is now empty) we // reset Command=Unset and set Consumed=Set. This way we emulate a blocking queue. std::promise<void> command_promise_{}; // Set when at least one command is in the queue std::future<void> command_future_ = command_promise_.get_future(); // GetCommand() blocks until this is fulfilled std::future<void> command_future_ = command_promise_.get_future(); // GetCommand() blocks until this is fulfilled CommandView empty_command_view_ = CommandView::Create(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>())); CommandView empty_command_view_ = CommandView::Create( PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>())); }; } // namespace hci Loading