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

Commit 4a4cd845 authored by Jack He's avatar Jack He Committed by android-build-merger
Browse files

L2CAP: Classic fixed channel reference counting

am: f2452034

Change-Id: I9ab34626425fadd3e756d46f6bd93b706e25df14
parents 5c8f95f0 f2452034
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -6,8 +6,9 @@ filegroup {
        "classic_fixed_channel.cc",
        "classic_fixed_channel_manager.cc",
        "classic_fixed_channel_service.cc",
        "internal/classic_fixed_channel_service_manager_impl.cc",
        "internal/classic_fixed_channel_allocator.cc",
        "internal/classic_fixed_channel_impl.cc",
        "internal/classic_fixed_channel_service_manager_impl.cc",
        "internal/classic_link_manager.cc",
        "internal/scheduler_fifo.cc",
    ],
@@ -17,8 +18,9 @@ filegroup {
    name: "BluetoothL2capTestSources",
    srcs: [
        "l2cap_packet_test.cc",
        "internal/classic_fixed_channel_service_manager_test.cc",
        "internal/classic_fixed_channel_allocator_test.cc",
        "internal/classic_fixed_channel_impl_test.cc",
        "internal/classic_fixed_channel_service_manager_test.cc",
        "internal/classic_link_manager_test.cc",
        "internal/scheduler_fifo_test.cc",
        "signal_id_test.cc",
+21 −3
Original line number Diff line number Diff line
@@ -15,12 +15,30 @@
 */

#include "l2cap/classic_fixed_channel.h"
#include "common/bind.h"
#include "l2cap/internal/classic_fixed_channel_impl.h"

namespace bluetooth {
namespace l2cap {
void ClassicFixedChannel::RegisterOnCloseCallback(os::Handler* handler, OnCloseCallback callback) {}
void ClassicFixedChannel::Acquire() {}
void ClassicFixedChannel::Release() {}

hci::Address ClassicFixedChannel::GetDevice() const {
  return impl_->GetDevice();
}

void ClassicFixedChannel::RegisterOnCloseCallback(os::Handler* user_handler,
                                                  ClassicFixedChannel::OnCloseCallback on_close_callback) {
  l2cap_handler_->Post(common::BindOnce(&internal::ClassicFixedChannelImpl::RegisterOnCloseCallback, impl_,
                                        user_handler, std::move(on_close_callback)));
}

void ClassicFixedChannel::Acquire() {
  l2cap_handler_->Post(common::BindOnce(&internal::ClassicFixedChannelImpl::Acquire, impl_));
}

void ClassicFixedChannel::Release() {
  l2cap_handler_->Post(common::BindOnce(&internal::ClassicFixedChannelImpl::Release, impl_));
}

common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>*
ClassicFixedChannel::GetQueueUpEnd() const {
  return nullptr;
+20 −16
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@

#include "common/bidi_queue.h"
#include "common/callback.h"
#include "hci/acl_manager.h"
#include "l2cap/cid.h"
#include "os/handler.h"
#include "packet/base_packet_builder.h"
#include "packet/packet_view.h"
@@ -31,33 +33,40 @@ class ClassicFixedChannelImpl;
/**
 * L2CAP fixed channel object. When a new object is created, it must be
 * acquired through calling {@link FixedChannel#Acquire()} within X seconds.
 * Otherwise, {@link FixeChannel#Release()} will be called automatically.
 * Otherwise, {@link FixedChannel#Release()} will be called automatically.
 *
 */
class ClassicFixedChannel {
 public:
  using OnCloseCallback = common::Callback<void()>;
  // Should only be constructed by modules that have access to ClassicLinkManager
  ClassicFixedChannel(std::shared_ptr<internal::ClassicFixedChannelImpl> impl, os::Handler* l2cap_handler)
      : impl_(std::move(impl)), l2cap_handler_(l2cap_handler) {
    ASSERT(impl_ != nullptr);
    ASSERT(l2cap_handler_ != nullptr);
  }

  hci::Address GetDevice() const;

  /**
   * Register close callback. If close callback is registered, when a channel is closed, the channel's resource will
   * only be freed after on_close callback is invoked. Otherwise, if no on_close callback is registered, the channel's
   * resource will be freed immediately after closing.
   *
   * @param on_close The callback invoked upon channel closing.
   * @param user_handler The handler used to invoke the callback on
   * @param on_close_callback The callback invoked upon channel closing.
   */
  void RegisterOnCloseCallback(os::Handler* handler, OnCloseCallback on_close);
  using OnCloseCallback = common::OnceCallback<void(hci::ErrorCode)>;
  void RegisterOnCloseCallback(os::Handler* user_handler, OnCloseCallback on_close_callback);

  /**
   * Indicate that this Fixed Channel is being used. This will prevent ACL
   * connection from being disconnected.
   * Indicate that this Fixed Channel is being used. This will prevent ACL connection from being disconnected.
   */
  void Acquire();

  /**
   * Indicate that this Fixed Channel is no longer being used. ACL connection
   * will be disconnected after X seconds if no other DynamicChannel is connected
   * or no other Fixed Channel is using this ACL connection. However a module can
   * still receive data on this channel as long as it remains open.
   * Indicate that this Fixed Channel is no longer being used. ACL connection will be disconnected after
   * kClassicLinkIdleDisconnectTimeout if no other DynamicChannel is connected or no other Fixed Channel is  using this
   * ACL connection. However a module can still receive data on this channel as long as it remains open.
   */
  void Release();

@@ -70,14 +79,9 @@ class ClassicFixedChannel {
   */
  common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>* GetQueueUpEnd() const;

  friend class internal::ClassicFixedChannelImpl;

 private:
  ClassicFixedChannel(os::Handler* l2cap_handler, internal::ClassicFixedChannelImpl* classic_fixed_channel_impl)
      : l2cap_handler_(l2cap_handler), classic_fixed_channel_impl_(classic_fixed_channel_impl) {}
  std::shared_ptr<internal::ClassicFixedChannelImpl> impl_;
  os::Handler* l2cap_handler_;
  internal::ClassicFixedChannelImpl* classic_fixed_channel_impl_;
  DISALLOW_COPY_AND_ASSIGN(ClassicFixedChannel);
};

}  // namespace l2cap
+36 −11
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "classic_fixed_channel_allocator.h"
#include "l2cap/cid.h"
#include "l2cap/internal/classic_fixed_channel_allocator.h"
#include "l2cap/internal/classic_link.h"
#include "l2cap/security_policy.h"
#include "os/handler.h"
#include "os/log.h"
@@ -27,30 +28,54 @@ namespace bluetooth {
namespace l2cap {
namespace internal {

ClassicFixedChannelImpl* ClassicFixedChannelAllocator::AllocateChannel(Cid cid, SecurityPolicy security_policy) {
  ASSERT_LOG(!IsChannelInUse((cid)), "Cid %d is already in use", cid);
std::shared_ptr<ClassicFixedChannelImpl> ClassicFixedChannelAllocator::AllocateChannel(Cid cid,
                                                                                       SecurityPolicy security_policy) {
  ASSERT_LOG(!IsChannelAllocated((cid)), "Cid 0x%x for device %s is already in use", cid,
             link_->GetDevice().ToString().c_str());
  ASSERT_LOG(cid >= kFirstFixedChannel && cid <= kLastFixedChannel, "Cid %d out of bound", cid);
  channels_.try_emplace(cid, cid, handler_);
  return &channels_.find(cid)->second;
  auto elem = channels_.try_emplace(cid, std::make_shared<ClassicFixedChannelImpl>(cid, link_, l2cap_handler_));
  ASSERT_LOG(elem.second, "Failed to create channel for cid 0x%x device %s", cid,
             link_->GetDevice().ToString().c_str());
  ASSERT(elem.first->second != nullptr);
  return elem.first->second;
}

bool ClassicFixedChannelAllocator::FreeChannel(Cid cid) {
  ASSERT_LOG(IsChannelInUse(cid), "Channel is not in use: cid %d", cid);
void ClassicFixedChannelAllocator::FreeChannel(Cid cid) {
  ASSERT_LOG(IsChannelAllocated(cid), "Channel is not in use: cid %d, device %s", cid,
             link_->GetDevice().ToString().c_str());
  channels_.erase(cid);
  return true;
}

bool ClassicFixedChannelAllocator::IsChannelInUse(Cid cid) const {
bool ClassicFixedChannelAllocator::IsChannelAllocated(Cid cid) const {
  return channels_.find(cid) != channels_.end();
}

ClassicFixedChannelImpl* ClassicFixedChannelAllocator::FindChannel(Cid cid) {
  ASSERT_LOG(IsChannelInUse(cid), "Channel is not in use: cid %d", cid);
  return &channels_.find(cid)->second;
std::shared_ptr<ClassicFixedChannelImpl> ClassicFixedChannelAllocator::FindChannel(Cid cid) {
  ASSERT_LOG(IsChannelAllocated(cid), "Channel is not in use: cid %d, device %s", cid,
             link_->GetDevice().ToString().c_str());
  return channels_.find(cid)->second;
}

size_t ClassicFixedChannelAllocator::NumberOfChannels() const {
  return channels_.size();
}

void ClassicFixedChannelAllocator::OnAclDisconnected(hci::ErrorCode reason) {
  for (auto& elem : channels_) {
    elem.second->OnClosed(reason);
  }
}

int ClassicFixedChannelAllocator::GetRefCount() {
  int ref_count = 0;
  for (auto& elem : channels_) {
    if (elem.second->IsAcquired()) {
      ref_count++;
    }
  }
  return ref_count;
}

}  // namespace internal
}  // namespace l2cap
}  // namespace bluetooth
+20 −10
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#pragma once

#include <hci/hci_packets.h>
#include <unordered_map>

#include "l2cap/cid.h"
@@ -28,30 +29,39 @@ namespace bluetooth {
namespace l2cap {
namespace internal {

class ClassicLink;

// Helper class for keeping channels in a Link. It allocates and frees Channel object, and supports querying whether a
// channel is in use
class ClassicFixedChannelAllocator {
 public:
  explicit ClassicFixedChannelAllocator(os::Handler* handler) : handler_(handler) {
    ASSERT(handler_ != nullptr);
  ClassicFixedChannelAllocator(ClassicLink* link, os::Handler* l2cap_handler)
      : link_(link), l2cap_handler_(l2cap_handler) {
    ASSERT(link_ != nullptr);
    ASSERT(l2cap_handler_ != nullptr);
  }

  // Allocates a channel. If cid is used, return nullptr. NOTE: The returned ClassicFixedChannelImpl object is still
  // owned by the channel cllocator, NOT the client.
  ClassicFixedChannelImpl* AllocateChannel(Cid cid, SecurityPolicy security_policy);
  // owned by the channel allocator, NOT the client.
  std::shared_ptr<ClassicFixedChannelImpl> AllocateChannel(Cid cid, SecurityPolicy security_policy);

  // Frees a channel. If cid doesn't exist, return false
  bool FreeChannel(Cid cid);
  // Frees a channel. If cid doesn't exist, it will crash
  void FreeChannel(Cid cid);

  bool IsChannelInUse(Cid cid) const;
  bool IsChannelAllocated(Cid cid) const;

  ClassicFixedChannelImpl* FindChannel(Cid cid);
  std::shared_ptr<ClassicFixedChannelImpl> FindChannel(Cid cid);

  size_t NumberOfChannels() const;

  void OnAclDisconnected(hci::ErrorCode hci_status);

  int GetRefCount();

 private:
  os::Handler* handler_ = nullptr;
  std::unordered_map<Cid, ClassicFixedChannelImpl> channels_;
  ClassicLink* link_;
  os::Handler* l2cap_handler_;
  std::unordered_map<Cid, std::shared_ptr<ClassicFixedChannelImpl>> channels_;
};

}  // namespace internal
Loading