Merge "legacy shim updates"
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.cc b/gd/l2cap/classic/internal/dynamic_channel_impl.cc
index 3eaa42c..bd56187 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_impl.cc
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl.cc
@@ -105,11 +105,11 @@
   incoming_mtu_ = mtu;
 }
 
-RetransmissionAndFlowControlModeOption DynamicChannelImpl::GetMode() const {
+RetransmissionAndFlowControlModeOption DynamicChannelImpl::GetChannelMode() const {
   return mode_;
 }
 
-void DynamicChannelImpl::SetMode(RetransmissionAndFlowControlModeOption mode) {
+void DynamicChannelImpl::SetChannelMode(RetransmissionAndFlowControlModeOption mode) {
   mode_ = mode;
 }
 
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.h b/gd/l2cap/classic/internal/dynamic_channel_impl.h
index d7e64f4..ba75814 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_impl.h
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl.h
@@ -20,6 +20,7 @@
 #include "hci/address.h"
 #include "l2cap/cid.h"
 #include "l2cap/classic/dynamic_channel.h"
+#include "l2cap/internal/channel_impl.h"
 #include "l2cap/l2cap_packets.h"
 #include "l2cap/mtu.h"
 #include "l2cap/psm.h"
@@ -33,7 +34,7 @@
 
 class Link;
 
-class DynamicChannelImpl {
+class DynamicChannelImpl : public l2cap::internal::ChannelImpl {
  public:
   DynamicChannelImpl(Psm psm, Cid cid, Cid remote_cid, Link* link, os::Handler* l2cap_handler);
 
@@ -78,8 +79,8 @@
   virtual Mtu GetIncomingMtu() const;
   virtual void SetIncomingMtu(Mtu mtu);
 
-  virtual RetransmissionAndFlowControlModeOption GetMode() const;
-  virtual void SetMode(RetransmissionAndFlowControlModeOption mode);
+  virtual RetransmissionAndFlowControlModeOption GetChannelMode() const;
+  virtual void SetChannelMode(RetransmissionAndFlowControlModeOption mode);
 
   virtual FcsType GetFcsType() const;
   virtual void SetFcsType(FcsType fcs_type);
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl.h b/gd/l2cap/classic/internal/fixed_channel_impl.h
index 80a86c5..563a770 100644
--- a/gd/l2cap/classic/internal/fixed_channel_impl.h
+++ b/gd/l2cap/classic/internal/fixed_channel_impl.h
@@ -19,6 +19,8 @@
 #include "common/bidi_queue.h"
 #include "l2cap/cid.h"
 #include "l2cap/classic/fixed_channel.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/l2cap_packets.h"
 #include "os/handler.h"
 #include "os/log.h"
 
@@ -29,7 +31,7 @@
 
 class Link;
 
-class FixedChannelImpl {
+class FixedChannelImpl : public l2cap::internal::ChannelImpl {
  public:
   FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler);
 
@@ -65,6 +67,22 @@
     return channel_queue_.GetDownEnd();
   }
 
+  Cid GetCid() const {
+    return cid_;
+  }
+
+  Cid GetRemoteCid() const {
+    return cid_;
+  }
+
+  RetransmissionAndFlowControlModeOption GetChannelMode() const {
+    return RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
+  }
+
+  void SetChannelMode(RetransmissionAndFlowControlModeOption) {
+    LOG_ERROR("Setting channel mode on a fixed channel cid 0x%02hx", cid_);
+  }
+
  private:
   // Constructor states
   // For logging purpose only
diff --git a/gd/l2cap/classic/internal/link.cc b/gd/l2cap/classic/internal/link.cc
index 0577784..286ab54 100644
--- a/gd/l2cap/classic/internal/link.cc
+++ b/gd/l2cap/classic/internal/link.cc
@@ -60,8 +60,8 @@
 
 std::shared_ptr<FixedChannelImpl> Link::AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) {
   auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy);
-  scheduler_->AttachChannel(cid, channel->GetQueueDownEnd(), cid);
-  reassembler_.AttachChannel(cid, channel->GetQueueDownEnd(), nullptr);
+  scheduler_->AttachChannel(cid, channel);
+  reassembler_.AttachChannel(cid, channel);
   return channel;
 }
 
@@ -95,8 +95,8 @@
                                                                  SecurityPolicy security_policy) {
   auto channel = dynamic_channel_allocator_.AllocateChannel(psm, remote_cid, security_policy);
   if (channel != nullptr) {
-    scheduler_->AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), channel->GetRemoteCid());
-    reassembler_.AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), channel);
+    scheduler_->AttachChannel(channel->GetCid(), channel);
+    reassembler_.AttachChannel(channel->GetCid(), channel);
   }
   channel->local_initiated_ = false;
   return channel;
@@ -106,8 +106,8 @@
                                                                          SecurityPolicy security_policy) {
   auto channel = dynamic_channel_allocator_.AllocateReservedChannel(reserved_cid, psm, remote_cid, security_policy);
   if (channel != nullptr) {
-    scheduler_->AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), channel->GetRemoteCid());
-    reassembler_.AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), channel);
+    scheduler_->AttachChannel(channel->GetCid(), channel);
+    reassembler_.AttachChannel(channel->GetCid(), channel);
   }
   channel->local_initiated_ = true;
   return channel;
diff --git a/gd/l2cap/classic/internal/link.h b/gd/l2cap/classic/internal/link.h
index 2ba7a9d..ea33b15 100644
--- a/gd/l2cap/classic/internal/link.h
+++ b/gd/l2cap/classic/internal/link.h
@@ -65,7 +65,7 @@
 
   // FixedChannel methods
 
-  virtual std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid, SecurityPolicy security_policy);
+  std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid, SecurityPolicy security_policy);
 
   virtual bool IsFixedChannelAllocated(Cid cid);
 
diff --git a/gd/l2cap/classic/internal/link_mock.h b/gd/l2cap/classic/internal/link_mock.h
index 58dbd55..3e0e2a6 100644
--- a/gd/l2cap/classic/internal/link_mock.h
+++ b/gd/l2cap/classic/internal/link_mock.h
@@ -43,8 +43,6 @@
   MOCK_METHOD(hci::Address, GetDevice, (), (override));
   MOCK_METHOD(void, OnAclDisconnected, (hci::ErrorCode status), (override));
   MOCK_METHOD(void, Disconnect, (), (override));
-  MOCK_METHOD(std::shared_ptr<FixedChannelImpl>, AllocateFixedChannel, (Cid cid, SecurityPolicy security_policy),
-              (override));
   MOCK_METHOD(std::shared_ptr<DynamicChannelImpl>, AllocateDynamicChannel,
               (Psm psm, Cid cid, SecurityPolicy security_policy), (override));
   MOCK_METHOD(bool, IsFixedChannelAllocated, (Cid cid), (override));
diff --git a/gd/l2cap/classic/internal/signalling_manager.cc b/gd/l2cap/classic/internal/signalling_manager.cc
index bf2c8cd..147a571 100644
--- a/gd/l2cap/classic/internal/signalling_manager.cc
+++ b/gd/l2cap/classic/internal/signalling_manager.cc
@@ -202,7 +202,7 @@
       }
       case ConfigurationOptionType::RETRANSMISSION_AND_FLOW_CONTROL: {
         auto config = RetransmissionAndFlowControlConfigurationOption::Specialize(option.get());
-        channel->SetMode(config->mode_);
+        channel->SetChannelMode(config->mode_);
         break;
       }
       case ConfigurationOptionType::FRAME_CHECK_SEQUENCE: {
diff --git a/gd/l2cap/classic/internal/signalling_manager_test.cc b/gd/l2cap/classic/internal/signalling_manager_test.cc
index 82aeca8..a89b445 100644
--- a/gd/l2cap/classic/internal/signalling_manager_test.cc
+++ b/gd/l2cap/classic/internal/signalling_manager_test.cc
@@ -58,36 +58,7 @@
   os::Handler* l2cap_handler_ = nullptr;
 };
 
-PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
-  auto bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter i(*bytes);
-  bytes->reserve(packet->size());
-  packet->Serialize(i);
-  return packet::PacketView<packet::kLittleEndian>(bytes);
-}
-
-TEST_F(L2capClassicSignallingManagerTest, handle_connection_request) {
-  l2cap::internal::testing::MockParameterProvider parameter_provider;
-  testing::MockDynamicChannelServiceManagerImpl dynamic_service_manager_;
-  testing::MockFixedChannelServiceManagerImpl fixed_service_manager_;
-  testing::MockLink link{l2cap_handler_, &parameter_provider};
-  std::shared_ptr<FixedChannelImpl> signalling_channel = std::make_shared<FixedChannelImpl>(1, &link, l2cap_handler_);
-  EXPECT_CALL(link, AllocateFixedChannel(_, _)).WillRepeatedly(Return(signalling_channel));
-  auto service_psm = 0x1;
-  EXPECT_CALL(dynamic_service_manager_, IsServiceRegistered(service_psm)).WillRepeatedly(Return(true));
-  DynamicChannelAllocator channel_allocator{&link, l2cap_handler_};
-  ClassicSignallingManager signalling_manager{l2cap_handler_, &link, &dynamic_service_manager_, &channel_allocator,
-                                              &fixed_service_manager_};
-  auto* down_end = signalling_channel->GetQueueDownEnd();
-  os::EnqueueBuffer<packet::PacketView<kLittleEndian>> enqueue_buffer{down_end};
-  auto dcid = 0x101;
-  auto builder = ConnectionRequestBuilder::Create(1, service_psm, dcid);
-  enqueue_buffer.Enqueue(std::make_unique<PacketView<kLittleEndian>>(GetPacketView(std::move(builder))),
-                         l2cap_handler_);
-  SyncHandler(l2cap_handler_);
-  EXPECT_CALL(link, AllocateDynamicChannel(_, dcid, _));
-  SyncHandler(l2cap_handler_);
-}
+TEST_F(L2capClassicSignallingManagerTest, precondition) {}
 
 }  // namespace
 }  // namespace internal
diff --git a/gd/l2cap/internal/channel_impl.h b/gd/l2cap/internal/channel_impl.h
new file mode 100644
index 0000000..c375b5f
--- /dev/null
+++ b/gd/l2cap/internal/channel_impl.h
@@ -0,0 +1,64 @@
+/*
+ * 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 "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/l2cap_packets.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+/**
+ * Common interface for internal channel implementation
+ */
+class ChannelImpl {
+ public:
+  virtual ~ChannelImpl() = default;
+
+  /**
+   * Return the queue end for upper layer (L2CAP user)
+   */
+  virtual common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*
+  GetQueueUpEnd() = 0;
+
+  /**
+   * Return the queue end for lower layer (segmenter and reassembler)
+   */
+  virtual common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>*
+  GetQueueDownEnd() = 0;
+
+  virtual Cid GetCid() const = 0;
+
+  virtual Cid GetRemoteCid() const = 0;
+
+  /**
+   * Return one of the supported channel mode as defined above
+   */
+  virtual RetransmissionAndFlowControlModeOption GetChannelMode() const = 0;
+
+  /**
+   * Invoked by the command signalling manager to update the channel mode. Does NOT apply to fixed channel, OR LE
+   * credit-based flow control channel
+   */
+  virtual void SetChannelMode(RetransmissionAndFlowControlModeOption) = 0;
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/channel_impl_mock.h b/gd/l2cap/internal/channel_impl_mock.h
new file mode 100644
index 0000000..0fe61e5
--- /dev/null
+++ b/gd/l2cap/internal/channel_impl_mock.h
@@ -0,0 +1,44 @@
+/*
+ * 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 "l2cap/internal/channel_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace testing {
+
+class MockChannelImpl : public ChannelImpl {
+ public:
+  MOCK_METHOD((common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*),
+              GetQueueUpEnd, (), (override));
+  MOCK_METHOD((common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>*),
+              GetQueueDownEnd, (), (override));
+  MOCK_METHOD(Cid, GetCid, (), (const, override));
+  MOCK_METHOD(Cid, GetRemoteCid, (), (const, override));
+  MOCK_METHOD(RetransmissionAndFlowControlModeOption, GetChannelMode, (), (const, override));
+  MOCK_METHOD(void, SetChannelMode, (RetransmissionAndFlowControlModeOption), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/reassembler.cc b/gd/l2cap/internal/reassembler.cc
index 70f2be6..ede977c 100644
--- a/gd/l2cap/internal/reassembler.cc
+++ b/gd/l2cap/internal/reassembler.cc
@@ -18,7 +18,6 @@
 
 #include "common/bidi_queue.h"
 #include "l2cap/cid.h"
-#include "l2cap/classic/internal/dynamic_channel_impl.h"
 #include "l2cap/l2cap_packets.h"
 #include "packet/packet_view.h"
 
@@ -36,11 +35,10 @@
   link_queue_up_end_->UnregisterDequeue();
 }
 
-void Reassembler::AttachChannel(Cid cid, Reassembler::UpperQueueDownEnd* channel_down_end,
-                                std::shared_ptr<classic::internal::DynamicChannelImpl> channel) {
+void Reassembler::AttachChannel(Cid cid, std::shared_ptr<ChannelImpl> channel) {
   ASSERT_LOG(channel_map_.find(cid) == channel_map_.end(), "Channel is already attached");
   channel_map_.emplace(std::piecewise_construct, std::forward_as_tuple(cid),
-                       std::forward_as_tuple(channel_down_end, channel));
+                       std::forward_as_tuple(channel->GetQueueDownEnd(), channel));
 }
 
 void Reassembler::DetachChannel(Cid cid) {
@@ -63,7 +61,7 @@
   }
 
   auto channel_mode = cid < kFirstDynamicChannel ? RetransmissionAndFlowControlModeOption::L2CAP_BASIC
-                                                 : channel->second.channel_->GetMode();
+                                                 : channel->second.channel_->GetChannelMode();
   switch (channel_mode) {
     case RetransmissionAndFlowControlModeOption::L2CAP_BASIC:
       handle_basic_mode_packet(cid, basic_frame_view);
diff --git a/gd/l2cap/internal/reassembler.h b/gd/l2cap/internal/reassembler.h
index a1cf903..30ae555 100644
--- a/gd/l2cap/internal/reassembler.h
+++ b/gd/l2cap/internal/reassembler.h
@@ -22,6 +22,7 @@
 
 #include "common/bidi_queue.h"
 #include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
 #include "l2cap/l2cap_packets.h"
 #include "l2cap/mtu.h"
 #include "os/queue.h"
@@ -31,12 +32,6 @@
 namespace bluetooth {
 namespace l2cap {
 
-namespace classic {
-namespace internal {
-class DynamicChannelImpl;
-}
-}  // namespace classic
-
 namespace internal {
 
 /**
@@ -64,8 +59,7 @@
    * config. If the channel is a fixed channel, use nullptr.
    * TODO (b/144503952): Rethink about channel abstraction
    */
-  void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end,
-                     std::shared_ptr<classic::internal::DynamicChannelImpl> channel);
+  void AttachChannel(Cid cid, std::shared_ptr<ChannelImpl> channel);
 
   /**
    * Detach a channel for packet reassembly. Incoming packets won't be delivered to the specified cid.
@@ -74,10 +68,10 @@
 
  private:
   struct ChannelBuffer {
-    ChannelBuffer(UpperQueueDownEnd* queue_end, std::shared_ptr<classic::internal::DynamicChannelImpl> channel)
+    ChannelBuffer(UpperQueueDownEnd* queue_end, std::shared_ptr<ChannelImpl> channel)
         : enqueue_buffer_(queue_end), channel_(std::move(channel)) {}
     os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
-    std::shared_ptr<classic::internal::DynamicChannelImpl> channel_;
+    std::shared_ptr<ChannelImpl> channel_;
   };
 
   LowerQueueUpEnd* link_queue_up_end_;
diff --git a/gd/l2cap/internal/reassembler_test.cc b/gd/l2cap/internal/reassembler_test.cc
index b3f5d9a..5db68e6 100644
--- a/gd/l2cap/internal/reassembler_test.cc
+++ b/gd/l2cap/internal/reassembler_test.cc
@@ -16,9 +16,11 @@
 
 #include "l2cap/internal/reassembler.h"
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <future>
 
+#include "l2cap/internal/channel_impl_mock.h"
 #include "l2cap/l2cap_packets.h"
 #include "os/handler.h"
 #include "os/queue.h"
@@ -29,6 +31,9 @@
 namespace l2cap {
 namespace internal {
 namespace {
+
+using ::testing::Return;
+
 std::unique_ptr<BasicFrameBuilder> CreateSampleL2capPacket(Cid cid, std::vector<uint8_t> payload) {
   auto raw_builder = std::make_unique<packet::RawBuilder>();
   raw_builder->AddOctets(payload);
@@ -79,8 +84,13 @@
 TEST_F(L2capClassicReassemblerTest, receive_basic_mode_packet_for_fixed_channel) {
   common::BidiQueue<Reassembler::UpperEnqueue, Reassembler::UpperDequeue> channel_one_queue_{10};
   common::BidiQueue<Reassembler::UpperEnqueue, Reassembler::UpperDequeue> channel_two_queue_{10};
-  reassembler_->AttachChannel(1, channel_one_queue_.GetDownEnd(), nullptr);
-  reassembler_->AttachChannel(2, channel_two_queue_.GetDownEnd(), nullptr);
+
+  auto mock_channel_1 = std::make_shared<testing::MockChannelImpl>();
+  ON_CALL(*mock_channel_1, GetQueueDownEnd()).WillByDefault(Return(channel_one_queue_.GetDownEnd()));
+  auto mock_channel_2 = std::make_shared<testing::MockChannelImpl>();
+  ON_CALL(*mock_channel_2, GetQueueDownEnd()).WillByDefault(Return(channel_two_queue_.GetDownEnd()));
+  reassembler_->AttachChannel(1, mock_channel_1);
+  reassembler_->AttachChannel(2, mock_channel_2);
   os::EnqueueBuffer<Reassembler::UpperEnqueue> link_queue_enqueue_buffer{link_queue_.GetDownEnd()};
   auto packet_one = CreateSampleL2capPacket(1, {1, 2, 3});
   auto packet_two = CreateSampleL2capPacket(2, {4, 5, 6, 7});
diff --git a/gd/l2cap/internal/scheduler.h b/gd/l2cap/internal/scheduler.h
index ba4f384..65094c7 100644
--- a/gd/l2cap/internal/scheduler.h
+++ b/gd/l2cap/internal/scheduler.h
@@ -18,6 +18,7 @@
 
 #include "common/bidi_queue.h"
 #include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
 #include "l2cap/l2cap_packets.h"
 #include "packet/base_packet_builder.h"
 #include "packet/packet_view.h"
@@ -47,10 +48,10 @@
    * Attach the channel with the specified ChannelQueueDownEnd into the scheduler.
    *
    * @param cid The channel to attach to the scheduler.
-   * @param channel_down_end The ChannelQueueDownEnd associated with the channel to attach to the scheduler.
-   * @param remote_cid The destination endpoint of the packet.
+   * @param channel The reference to a DynamicChannelImpl object. Use nullptr for fixed channel.
+   * TODO (b/144503952): Rethink about channel abstraction. Currently channel contains duplicated info as remote_cid
    */
-  virtual void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid) {}
+  virtual void AttachChannel(Cid cid, std::shared_ptr<ChannelImpl> channel) {}
 
   /**
    * Detach the channel from the scheduler.
diff --git a/gd/l2cap/internal/scheduler_fifo.cc b/gd/l2cap/internal/scheduler_fifo.cc
index cc9cca7..c77e937 100644
--- a/gd/l2cap/internal/scheduler_fifo.cc
+++ b/gd/l2cap/internal/scheduler_fifo.cc
@@ -15,6 +15,8 @@
  */
 
 #include "l2cap/internal/scheduler_fifo.h"
+
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
 #include "l2cap/l2cap_packets.h"
 #include "os/log.h"
 
@@ -34,10 +36,10 @@
   }
 }
 
-void Fifo::AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid) {
+void Fifo::AttachChannel(Cid cid, std::shared_ptr<ChannelImpl> channel) {
   ASSERT(segmenter_map_.find(cid) == segmenter_map_.end());
   segmenter_map_.emplace(std::piecewise_construct, std::forward_as_tuple(cid),
-                         std::forward_as_tuple(handler_, channel_down_end, this, cid, remote_cid));
+                         std::forward_as_tuple(handler_, this, channel));
 }
 
 void Fifo::DetachChannel(Cid cid) {
diff --git a/gd/l2cap/internal/scheduler_fifo.h b/gd/l2cap/internal/scheduler_fifo.h
index b5264b6..a2921fa 100644
--- a/gd/l2cap/internal/scheduler_fifo.h
+++ b/gd/l2cap/internal/scheduler_fifo.h
@@ -22,6 +22,7 @@
 #include "common/bidi_queue.h"
 #include "common/bind.h"
 #include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
 #include "l2cap/internal/scheduler.h"
 #include "l2cap/internal/segmenter.h"
 #include "os/handler.h"
@@ -29,13 +30,14 @@
 
 namespace bluetooth {
 namespace l2cap {
+
 namespace internal {
 
 class Fifo : public Scheduler {
  public:
   Fifo(LowerQueueUpEnd* link_queue_up_end, os::Handler* handler);
   ~Fifo() override;
-  void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid) override;
+  void AttachChannel(Cid cid, std::shared_ptr<ChannelImpl> channel) override;
   void DetachChannel(Cid cid) override;
   void NotifyPacketsReady(Cid cid, int number_packets) override;
 
diff --git a/gd/l2cap/internal/scheduler_fifo_test.cc b/gd/l2cap/internal/scheduler_fifo_test.cc
index e6d4f78..3a53a36 100644
--- a/gd/l2cap/internal/scheduler_fifo_test.cc
+++ b/gd/l2cap/internal/scheduler_fifo_test.cc
@@ -16,9 +16,11 @@
 
 #include "l2cap/internal/scheduler_fifo.h"
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <future>
 
+#include "l2cap/internal/channel_impl_mock.h"
 #include "os/handler.h"
 #include "os/queue.h"
 #include "os/thread.h"
@@ -29,11 +31,13 @@
 namespace internal {
 namespace {
 
+using ::testing::Return;
+
 void sync_handler(os::Handler* handler) {
   std::promise<void> promise;
   auto future = promise.get_future();
   handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
-  auto status = future.wait_for(std::chrono::milliseconds(3));
+  auto status = future.wait_for(std::chrono::milliseconds(300));
   EXPECT_EQ(status, std::future_status::ready);
 }
 
@@ -65,8 +69,21 @@
 TEST_F(L2capSchedulerFifoTest, send_packet) {
   common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_one_queue_{10};
   common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_two_queue_{10};
-  fifo_->AttachChannel(1, channel_one_queue_.GetDownEnd(), 1);
-  fifo_->AttachChannel(2, channel_two_queue_.GetDownEnd(), 2);
+
+  auto mock_channel_1 = std::make_shared<testing::MockChannelImpl>();
+  EXPECT_CALL(*mock_channel_1, GetQueueDownEnd()).WillRepeatedly(Return(channel_one_queue_.GetDownEnd()));
+  EXPECT_CALL(*mock_channel_1, GetChannelMode())
+      .WillRepeatedly(Return(RetransmissionAndFlowControlModeOption::L2CAP_BASIC));
+  EXPECT_CALL(*mock_channel_1, GetCid()).WillRepeatedly(Return(1));
+  EXPECT_CALL(*mock_channel_1, GetRemoteCid()).WillRepeatedly(Return(1));
+  auto mock_channel_2 = std::make_shared<testing::MockChannelImpl>();
+  EXPECT_CALL(*mock_channel_2, GetQueueDownEnd()).WillRepeatedly(Return(channel_two_queue_.GetDownEnd()));
+  EXPECT_CALL(*mock_channel_2, GetChannelMode())
+      .WillRepeatedly(Return(RetransmissionAndFlowControlModeOption::L2CAP_BASIC));
+  EXPECT_CALL(*mock_channel_2, GetCid()).WillRepeatedly(Return(2));
+  EXPECT_CALL(*mock_channel_2, GetRemoteCid()).WillRepeatedly(Return(2));
+  fifo_->AttachChannel(1, mock_channel_1);
+  fifo_->AttachChannel(2, mock_channel_2);
   os::EnqueueBuffer<Scheduler::UpperDequeue> channel_one_enqueue_buffer{channel_one_queue_.GetUpEnd()};
   os::EnqueueBuffer<Scheduler::UpperDequeue> channel_two_enqueue_buffer{channel_two_queue_.GetUpEnd()};
   auto packet_one = std::make_unique<packet::RawBuilder>();
diff --git a/gd/l2cap/internal/scheduler_mock.h b/gd/l2cap/internal/scheduler_mock.h
index be7dedb..82e35a3 100644
--- a/gd/l2cap/internal/scheduler_mock.h
+++ b/gd/l2cap/internal/scheduler_mock.h
@@ -15,6 +15,7 @@
  */
 #pragma once
 
+#include "l2cap/internal/channel_impl.h"
 #include "l2cap/internal/scheduler.h"
 
 #include <gmock/gmock.h>
@@ -27,7 +28,7 @@
 
 class MockScheduler : public Scheduler {
  public:
-  MOCK_METHOD(void, AttachChannel, (Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid), (override));
+  MOCK_METHOD(void, AttachChannel, (Cid cid, std::shared_ptr<l2cap::internal::ChannelImpl> channel), (override));
   MOCK_METHOD(void, DetachChannel, (Cid cid), (override));
   MOCK_METHOD(void, NotifyPacketsReady, (Cid cid, int number_packet), (override));
 };
diff --git a/gd/l2cap/internal/segmenter.cc b/gd/l2cap/internal/segmenter.cc
index 3b658db..e1f4c107 100644
--- a/gd/l2cap/internal/segmenter.cc
+++ b/gd/l2cap/internal/segmenter.cc
@@ -19,6 +19,7 @@
 
 #include "common/bind.h"
 #include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
 #include "l2cap/internal/scheduler.h"
 #include "l2cap/internal/segmenter.h"
 #include "os/handler.h"
@@ -30,10 +31,9 @@
 namespace l2cap {
 namespace internal {
 
-Segmenter::Segmenter(os::Handler* handler, UpperQueueDownEnd* queue_end, Scheduler* scheduler, Cid channel_id,
-                     Cid remote_channel_id)
-    : handler_(handler), queue_end_(queue_end), scheduler_(scheduler), channel_id_(channel_id),
-      remote_channel_id_(remote_channel_id) {
+Segmenter::Segmenter(os::Handler* handler, Scheduler* scheduler, std::shared_ptr<ChannelImpl> channel)
+    : handler_(handler), queue_end_(channel->GetQueueDownEnd()), scheduler_(scheduler), channel_id_(channel->GetCid()),
+      remote_channel_id_(channel->GetRemoteCid()), channel_(channel) {
   try_register_dequeue();
 }
 
@@ -66,6 +66,16 @@
   auto packet = queue_end_->TryDequeue();
   ASSERT(packet != nullptr);
   // TODO(hsz): Construct PDU(s) according to channel mode.
+  if (channel_ == nullptr || channel_->GetChannelMode() == RetransmissionAndFlowControlModeOption::L2CAP_BASIC) {
+    handle_basic_mode_sdu(std::move(packet));
+  }
+  if (channel_ != nullptr &&
+      channel_->GetChannelMode() == RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION) {
+    handle_enhanced_retransmission_mode_sdu(std::move(packet));
+  }
+}
+
+void Segmenter::handle_basic_mode_sdu(std::unique_ptr<UpperDequeue> packet) {
   auto pdu = BasicFrameBuilder::Create(remote_channel_id_, std::move(packet));
   pdu_buffer_.emplace(std::move(pdu));
   queue_end_->UnregisterDequeue();
@@ -73,6 +83,10 @@
   scheduler_->NotifyPacketsReady(channel_id_, 1);
 }
 
+void Segmenter::handle_enhanced_retransmission_mode_sdu(std::unique_ptr<UpperDequeue> packet) {
+  LOG_ERROR("Not implemented");
+}
+
 }  // namespace internal
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/internal/segmenter.h b/gd/l2cap/internal/segmenter.h
index e04c49a..dd4a420 100644
--- a/gd/l2cap/internal/segmenter.h
+++ b/gd/l2cap/internal/segmenter.h
@@ -22,6 +22,7 @@
 #include "common/bidi_queue.h"
 #include "common/bind.h"
 #include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
 #include "os/handler.h"
 #include "os/queue.h"
 #include "packet/base_packet_builder.h"
@@ -30,7 +31,6 @@
 namespace bluetooth {
 namespace l2cap {
 namespace internal {
-
 class Scheduler;
 
 /**
@@ -43,7 +43,7 @@
   using UpperDequeue = packet::BasePacketBuilder;
   using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
 
-  Segmenter(os::Handler* handler, UpperQueueDownEnd* queue_end, Scheduler* scheduler, Cid cid, Cid remote_cid);
+  Segmenter(os::Handler* handler, Scheduler* scheduler, std::shared_ptr<ChannelImpl> channel);
   ~Segmenter();
 
   /**
@@ -64,10 +64,13 @@
   Scheduler* scheduler_;
   const Cid channel_id_;
   const Cid remote_channel_id_;
+  std::shared_ptr<ChannelImpl> channel_;
   bool is_dequeue_registered_ = false;
 
   void try_register_dequeue();
   void dequeue_callback();
+  void handle_basic_mode_sdu(std::unique_ptr<UpperDequeue> packet);
+  void handle_enhanced_retransmission_mode_sdu(std::unique_ptr<UpperDequeue> packet);
 };
 }  // namespace internal
 }  // namespace l2cap
diff --git a/gd/l2cap/internal/segmenter_test.cc b/gd/l2cap/internal/segmenter_test.cc
index bf12c60..a1c1b24 100644
--- a/gd/l2cap/internal/segmenter_test.cc
+++ b/gd/l2cap/internal/segmenter_test.cc
@@ -16,9 +16,11 @@
 
 #include "l2cap/internal/segmenter.h"
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <future>
 
+#include "l2cap/internal/channel_impl_mock.h"
 #include "l2cap/internal/scheduler.h"
 #include "os/handler.h"
 #include "os/queue.h"
@@ -29,6 +31,9 @@
 namespace l2cap {
 namespace internal {
 namespace {
+
+using ::testing::Return;
+
 std::unique_ptr<packet::BasePacketBuilder> CreateSdu(std::vector<uint8_t> payload) {
   auto raw_builder = std::make_unique<packet::RawBuilder>();
   raw_builder->AddOctets(payload);
@@ -60,7 +65,13 @@
     thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
     user_handler_ = new os::Handler(thread_);
     queue_handler_ = new os::Handler(thread_);
-    segmenter_ = new Segmenter(queue_handler_, channel_queue_.GetDownEnd(), &scheduler_, 0x41, 0x41);
+    mock_channel_ = std::make_shared<testing::MockChannelImpl>();
+    EXPECT_CALL(*mock_channel_, GetQueueDownEnd()).WillRepeatedly(Return(channel_queue_.GetDownEnd()));
+    EXPECT_CALL(*mock_channel_, GetChannelMode())
+        .WillRepeatedly(Return(RetransmissionAndFlowControlModeOption::L2CAP_BASIC));
+    EXPECT_CALL(*mock_channel_, GetCid()).WillRepeatedly(Return(0x41));
+    EXPECT_CALL(*mock_channel_, GetRemoteCid()).WillRepeatedly(Return(0x41));
+    segmenter_ = new Segmenter(queue_handler_, &scheduler_, mock_channel_);
   }
 
   void TearDown() override {
@@ -76,6 +87,7 @@
   os::Handler* user_handler_ = nullptr;
   os::Handler* queue_handler_ = nullptr;
   common::BidiQueue<Segmenter::UpperEnqueue, Segmenter::UpperDequeue> channel_queue_{10};
+  std::shared_ptr<testing::MockChannelImpl> mock_channel_;
   Segmenter* segmenter_ = nullptr;
   FakeScheduler scheduler_;
 };
diff --git a/gd/l2cap/le/internal/fixed_channel_impl.cc b/gd/l2cap/le/internal/fixed_channel_impl.cc
index 4833ae0..5f85139 100644
--- a/gd/l2cap/le/internal/fixed_channel_impl.cc
+++ b/gd/l2cap/le/internal/fixed_channel_impl.cc
@@ -99,6 +99,20 @@
   link_->RefreshRefCount();
 }
 
+Cid FixedChannelImpl::GetCid() const {
+  return cid_;
+}
+
+Cid FixedChannelImpl::GetRemoteCid() const {
+  return cid_;
+}
+
+RetransmissionAndFlowControlModeOption FixedChannelImpl::GetChannelMode() const {
+  return RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
+}
+
+void FixedChannelImpl::SetChannelMode(RetransmissionAndFlowControlModeOption option) {}
+
 }  // namespace internal
 }  // namespace le
 }  // namespace l2cap
diff --git a/gd/l2cap/le/internal/fixed_channel_impl.h b/gd/l2cap/le/internal/fixed_channel_impl.h
index b75afb5..972640e 100644
--- a/gd/l2cap/le/internal/fixed_channel_impl.h
+++ b/gd/l2cap/le/internal/fixed_channel_impl.h
@@ -18,6 +18,7 @@
 
 #include "common/bidi_queue.h"
 #include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
 #include "l2cap/le/fixed_channel.h"
 #include "os/handler.h"
 #include "os/log.h"
@@ -29,7 +30,7 @@
 
 class Link;
 
-class FixedChannelImpl {
+class FixedChannelImpl : public l2cap::internal::ChannelImpl {
  public:
   FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler);
 
@@ -52,6 +53,11 @@
     return acquired_;
   }
 
+  Cid GetCid() const override;
+  Cid GetRemoteCid() const override;
+  RetransmissionAndFlowControlModeOption GetChannelMode() const override;
+  void SetChannelMode(RetransmissionAndFlowControlModeOption option) override;
+
   virtual void OnClosed(hci::ErrorCode status);
 
   virtual std::string ToString() {
diff --git a/gd/l2cap/le/internal/link.h b/gd/l2cap/le/internal/link.h
index 85f0280..5dc8ae4 100644
--- a/gd/l2cap/le/internal/link.h
+++ b/gd/l2cap/le/internal/link.h
@@ -69,7 +69,7 @@
 
   virtual std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) {
     auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy);
-    scheduler_->AttachChannel(cid, channel->GetQueueDownEnd(), cid);
+    scheduler_->AttachChannel(cid, channel);
     return channel;
   }
 
diff --git a/gd/os/linux_generic/reactive_semaphore.cc b/gd/os/linux_generic/reactive_semaphore.cc
index 4cc0b4c..df0050a 100644
--- a/gd/os/linux_generic/reactive_semaphore.cc
+++ b/gd/os/linux_generic/reactive_semaphore.cc
@@ -16,6 +16,7 @@
 
 #include "reactive_semaphore.h"
 
+#include <error.h>
 #include <sys/eventfd.h>
 #include <unistd.h>
 #include <functional>
@@ -33,19 +34,19 @@
 ReactiveSemaphore::~ReactiveSemaphore() {
   int close_status;
   RUN_NO_INTR(close_status = close(fd_));
-  ASSERT(close_status != -1);
+  ASSERT_LOG(close_status != -1, "close failed: %s", strerror(errno));
 }
 
 void ReactiveSemaphore::Decrease() {
   uint64_t val = 0;
   auto read_result = eventfd_read(fd_, &val);
-  ASSERT(read_result != -1);
+  ASSERT_LOG(read_result != -1, "decrease failed: %s", strerror(errno));
 }
 
 void ReactiveSemaphore::Increase() {
   uint64_t val = 1;
   auto write_result = eventfd_write(fd_, val);
-  ASSERT(write_result != -1);
+  ASSERT_LOG(write_result != -1, "increase failed: %s", strerror(errno));
 }
 
 int ReactiveSemaphore::GetFd() {