encryption_change_listener_.push_back(listener);
}
+void Link::OnPendingPacketChange(Cid local_cid, bool has_packet) {
+ if (has_packet) {
+ remaining_packets_to_be_sent_++;
+ } else {
+ remaining_packets_to_be_sent_--;
+ }
+ if (link_manager_ != nullptr) {
+ link_manager_->OnPendingPacketChange(GetDevice().GetAddress(), remaining_packets_to_be_sent_);
+ }
+}
+
} // namespace internal
} // namespace classic
} // namespace l2cap
#pragma once
+#include <atomic>
#include <memory>
#include <unordered_map>
return role_;
}
+ void OnPendingPacketChange(Cid local_cid, bool has_packet) override;
+
private:
friend class DumpsysHelper;
void connect_to_pending_dynamic_channels();
bool used_by_security_module_ = false;
bool has_requested_authentication_ = false;
std::list<EncryptionChangeListener> encryption_change_listener_;
+ std::atomic_int remaining_packets_to_be_sent_ = 0;
DISALLOW_COPY_AND_ASSIGN(Link);
};
link_property_listener_ = listener;
}
+void LinkManager::OnPendingPacketChange(hci::Address remote, int num_packets) {
+ if (disconnected_links_.count(remote) != 0 && num_packets == 0) {
+ links_.erase(remote);
+ links_with_pending_packets_.erase(remote);
+ } else if (num_packets != 0) {
+ links_with_pending_packets_.emplace(remote);
+ } else {
+ links_with_pending_packets_.erase(remote);
+ }
+}
+
Link* LinkManager::GetLink(const hci::Address device) {
if (links_.find(device) == links_.end()) {
return nullptr;
link_property_callback_handler_->CallOn(link_property_listener_, &LinkPropertyListener::OnLinkDisconnected, device);
}
- links_.erase(device);
+ if (links_with_pending_packets_.count(device) != 0) {
+ disconnected_links_.emplace(device);
+ } else {
+ links_.erase(device);
+ }
}
void LinkManager::OnAuthenticationComplete(hci::ErrorCode hci_status, hci::Address device) {
// Registerlink callbacks
void RegisterLinkPropertyListener(os::Handler* handler, LinkPropertyListener* listener);
+ // Reported by link to indicate how many pending packets are remaining to be set.
+ // If there is anything outstanding, don't delete link
+ void OnPendingPacketChange(hci::Address remote, int num_packets);
+
private:
// Handles requests from LinkSecurityInterface
friend class LinkSecurityInterfaceImpl;
LinkSecurityInterfaceListener* link_security_interface_listener_ = nullptr;
LinkPropertyListener* link_property_listener_ = nullptr;
os::Handler* link_property_callback_handler_ = nullptr;
+ std::unordered_set<hci::Address> disconnected_links_;
+ std::unordered_set<hci::Address> links_with_pending_packets_;
DISALLOW_COPY_AND_ASSIGN(LinkManager);
};
virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid) = 0;
virtual hci::AddressWithType GetDevice() const = 0;
+ // Used by sender to indicate whether there is any pending packet to be sent.
+ // If there is pending packet, don't delete the link.
+ virtual void OnPendingPacketChange(Cid local_cid, bool has_packet) {}
+
// To be used by LE credit based channel data controller over LE link
virtual void SendLeCredit(Cid local_cid, uint16_t credit) {}
}
void Sender::OnPacketSent() {
+ link_->OnPendingPacketChange(channel_id_, false);
try_register_dequeue();
}
if (is_dequeue_registered_.exchange(false)) {
queue_end_->UnregisterDequeue();
}
+ link_->OnPendingPacketChange(channel_id_, true);
}
void Sender::UpdateClassicConfiguration(classic::internal::ChannelConfigurationState config) {
#include <future>
#include "l2cap/internal/channel_impl_mock.h"
+#include "l2cap/internal/ilink_mock.h"
#include "l2cap/internal/scheduler.h"
#include "os/handler.h"
#include "os/queue.h"
EXPECT_CALL(*mock_channel_, GetQueueDownEnd()).WillRepeatedly(Return(channel_queue_.GetDownEnd()));
EXPECT_CALL(*mock_channel_, GetCid()).WillRepeatedly(Return(cid_));
EXPECT_CALL(*mock_channel_, GetRemoteCid()).WillRepeatedly(Return(cid_));
- sender_ = new Sender(queue_handler_, nullptr, &scheduler_, mock_channel_);
+ sender_ = new Sender(queue_handler_, &link_, &scheduler_, mock_channel_);
}
void TearDown() override {
Sender* sender_ = nullptr;
Cid cid_ = 0x41;
FakeScheduler scheduler_;
+ testing::MockILink link_;
};
TEST_F(L2capSenderTest, send_packet) {
signalling_manager_.SendConnectionParameterUpdateResponse(SignalId(), result);
}
+void Link::OnPendingPacketChange(Cid local_cid, bool has_packet) {
+ if (has_packet) {
+ remaining_packets_to_be_sent_++;
+ } else {
+ remaining_packets_to_be_sent_--;
+ }
+ link_manager_->OnPendingPacketChange(GetDevice(), remaining_packets_to_be_sent_);
+}
+
} // namespace internal
} // namespace le
} // namespace l2cap
#pragma once
+#include <atomic>
#include <chrono>
#include <memory>
void ReadRemoteVersionInformation();
+ void OnPendingPacketChange(Cid local_cid, bool has_packet) override;
+
private:
os::Handler* l2cap_handler_;
l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
uint16_t update_request_interval_max_;
uint16_t update_request_latency_;
uint16_t update_request_supervision_timeout_;
+ std::atomic_int remaining_packets_to_be_sent_ = 0;
DISALLOW_COPY_AND_ASSIGN(Link);
// Received connection update complete from ACL manager. SignalId is bound to a valid number when we need to send a
auto* link = GetLink(address_with_type);
ASSERT_LOG(link != nullptr, "Device %s is disconnected but not in local database",
address_with_type.ToString().c_str());
- links_.erase(address_with_type);
+ if (links_with_pending_packets_.count(address_with_type) != 0) {
+ disconnected_links_.emplace(address_with_type);
+ } else {
+ links_.erase(address_with_type);
+ }
if (link_property_callback_handler_ != nullptr) {
link_property_callback_handler_->CallOn(
}
}
+void LinkManager::OnPendingPacketChange(hci::AddressWithType remote, int num_packets) {
+ if (disconnected_links_.count(remote) != 0 && num_packets == 0) {
+ links_.erase(remote);
+ links_with_pending_packets_.erase(remote);
+ } else if (num_packets != 0) {
+ links_with_pending_packets_.emplace(remote);
+ } else {
+ links_with_pending_packets_.erase(remote);
+ }
+}
+
} // namespace internal
} // namespace le
} // namespace l2cap
#include <memory>
#include <unordered_map>
+#include <unordered_set>
#include <utility>
#include "os/handler.h"
uint16_t manufacturer_name,
uint16_t sub_version);
+ // Reported by link to indicate how many pending packets are remaining to be set.
+ // If there is anything outstanding, don't delete link
+ void OnPendingPacketChange(hci::AddressWithType remote, int num_packets);
+
private:
// Dependencies
os::Handler* l2cap_handler_;
pending_dynamic_channels_;
os::Handler* link_property_callback_handler_ = nullptr;
LinkPropertyListener* link_property_listener_ = nullptr;
+ std::unordered_set<hci::AddressWithType> disconnected_links_;
+ std::unordered_set<hci::AddressWithType> links_with_pending_packets_;
DISALLOW_COPY_AND_ASSIGN(LinkManager);
};