diff --git a/BUILD.gn b/BUILD.gn
index 56ed7d85d4aaee7f2af937548ec8b809be676bde..ca2855f4e6e6923090eb7fa6d69ac2b748ce125b 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -114,7 +114,6 @@ config("target_defaults") {
     "OS_GENERIC",
     "OS_LINUX_GENERIC",
     "TARGET_FLOSS",
-    "USE_LINUX_HCI_SOCKET",
     "EXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
     "FALLTHROUGH_INTENDED=[[clang::fallthrough]]",
   ]
diff --git a/system/gd/docs/architecture/style_guide.md b/system/gd/docs/architecture/style_guide.md
index bd2adb275c1fc821860a1c2bae2986534eab3c6d..65953ffe78229bc56fe5a7ec991379a4113991e3 100644
--- a/system/gd/docs/architecture/style_guide.md
+++ b/system/gd/docs/architecture/style_guide.md
@@ -113,8 +113,10 @@ Root directory under Android tree:
     *   hci_hal_android_hidl.cc: implementation of hci_hal.h using Android HIDL
     *   hci_hal_android_hidl_test.cc: unit tests for the Android HIDL
         implementation
-    *   hci_hal_host.cc: implementation of hci_hal.h using root-canal
-        emulator or linux Bluetooth HCI socket
+    *   hci_hal_host.cc: implementation of hci_hal.h using linux Bluetooth HCI
+        socket
+    *   hci_hal_host_rootcanal.cc: implementation of hci_hal.h using root-canal
+        emulator
     *   hci_hal_host_test.cc: unit tests for the socket based HAL (root-canal)
         emulator implementation
     *   facade.proto: gRPC automation interface definition for this layer
diff --git a/system/gd/hal/Android.bp b/system/gd/hal/Android.bp
index 1e7c18d9f1ce3226279ea38a61c4f08daedabce6..978b4cab79d2c8138b61859c7a709c4308fcabcc 100644
--- a/system/gd/hal/Android.bp
+++ b/system/gd/hal/Android.bp
@@ -24,7 +24,7 @@ filegroup {
 filegroup {
     name: "BluetoothHalSources_hci_host",
     srcs: [
-        "hci_hal_host.cc",
+        "hci_hal_host_rootcanal.cc",
     ],
 }
 
diff --git a/system/gd/hal/hci_hal_host.cc b/system/gd/hal/hci_hal_host.cc
index f5e436d8070dad59ec70a9bf3989ca679f019298..b41fbd452f572ca52406653b17a58bf3c61ce845 100644
--- a/system/gd/hal/hci_hal_host.cc
+++ b/system/gd/hal/hci_hal_host.cc
@@ -50,7 +50,6 @@ constexpr uint8_t kHciEvtHeaderSize = 2;
 constexpr uint8_t kHciIsoHeaderSize = 4;
 constexpr int kBufSize = 1024 + 4 + 1;  // DeviceProperties::acl_data_packet_size_ + ACL header + H4 header
 
-#ifdef USE_LINUX_HCI_SOCKET
 constexpr uint8_t BTPROTO_HCI = 1;
 constexpr uint16_t HCI_CHANNEL_USER = 1;
 constexpr uint16_t HCI_CHANNEL_CONTROL = 3;
@@ -197,51 +196,7 @@ int ConnectToSocket() {
   LOG_INFO("HCI device ready");
   return socket_fd;
 }
-#else
-// Connect to root canal socket
-int ConnectToSocket() {
-  auto* config = bluetooth::hal::HciHalHostRootcanalConfig::Get();
-  const std::string& server = config->GetServerAddress();
-  int port = config->GetPort();
-
-  int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
-  if (socket_fd < 1) {
-    LOG_ERROR("can't create socket: %s", strerror(errno));
-    return INVALID_FD;
-  }
-
-  struct hostent* host;
-  host = gethostbyname(server.c_str());
-  if (host == nullptr) {
-    LOG_ERROR("can't get server name");
-    return INVALID_FD;
-  }
-
-  struct sockaddr_in serv_addr;
-  memset((void*)&serv_addr, 0, sizeof(serv_addr));
-  serv_addr.sin_family = AF_INET;
-  serv_addr.sin_addr.s_addr = INADDR_ANY;
-  serv_addr.sin_port = htons(port);
-
-  int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
-  if (result < 0) {
-    LOG_ERROR("can't connect: %s", strerror(errno));
-    return INVALID_FD;
-  }
-
-  timeval socket_timeout{
-      .tv_sec = 3,
-      .tv_usec = 0,
-  };
-  int ret = setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &socket_timeout, sizeof(socket_timeout));
-  if (ret == -1) {
-    LOG_ERROR("can't control socket fd: %s", strerror(errno));
-    return INVALID_FD;
-  }
-  return socket_fd;
 }
-#endif
-}  // namespace
 
 namespace bluetooth {
 namespace hal {
@@ -396,7 +351,7 @@ class HciHalHost : public HciHal {
     uint8_t buf[kBufSize] = {};
 
     ssize_t received_size;
-    RUN_NO_INTR(received_size = recv(sock_fd_, buf, kH4HeaderSize, 0));
+    RUN_NO_INTR(received_size = read(sock_fd_, buf, kBufSize));
     ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
     if (received_size == 0) {
       LOG_WARN("Can't read H4 header. EOF received");
@@ -405,15 +360,10 @@ class HciHalHost : public HciHal {
     }
 
     if (buf[0] == kH4Event) {
-      RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciEvtHeaderSize, 0));
-      ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
-      ASSERT_LOG(received_size == kHciEvtHeaderSize, "malformed HCI event header received");
-
+      ASSERT_LOG(
+          received_size >= kH4HeaderSize + kHciEvtHeaderSize, "Received bad HCI_EVT packet size: %zu", received_size);
       uint8_t hci_evt_parameter_total_length = buf[2];
-      ssize_t payload_size;
-      RUN_NO_INTR(
-          payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciEvtHeaderSize, hci_evt_parameter_total_length, 0));
-      ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+      ssize_t payload_size = received_size - (kH4HeaderSize + kHciEvtHeaderSize);
       ASSERT_LOG(
           payload_size == hci_evt_parameter_total_length,
           "malformed HCI event total parameter size received: %zu != %d",
@@ -434,14 +384,10 @@ class HciHalHost : public HciHal {
     }
 
     if (buf[0] == kH4Acl) {
-      RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciAclHeaderSize, 0));
-      ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
-      ASSERT_LOG(received_size == kHciAclHeaderSize, "malformed ACL header received");
-
+      ASSERT_LOG(
+          received_size >= kH4HeaderSize + kHciAclHeaderSize, "Received bad HCI_ACL packet size: %zu", received_size);
+      int payload_size = received_size - (kH4HeaderSize + kHciAclHeaderSize);
       uint16_t hci_acl_data_total_length = (buf[4] << 8) + buf[3];
-      int payload_size;
-      RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciAclHeaderSize, hci_acl_data_total_length, 0));
-      ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
       ASSERT_LOG(
           payload_size == hci_acl_data_total_length,
           "malformed ACL length received: %d != %d",
@@ -463,15 +409,15 @@ class HciHalHost : public HciHal {
     }
 
     if (buf[0] == kH4Sco) {
-      RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciScoHeaderSize, 0));
-      ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
-      ASSERT_LOG(received_size == kHciScoHeaderSize, "malformed SCO header received");
-
+      ASSERT_LOG(
+          received_size >= kH4HeaderSize + kHciScoHeaderSize, "Received bad HCI_SCO packet size: %zu", received_size);
+      int payload_size = received_size - (kH4HeaderSize + kHciScoHeaderSize);
       uint8_t hci_sco_data_total_length = buf[3];
-      int payload_size;
-      RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciScoHeaderSize, hci_sco_data_total_length, 0));
-      ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
-      ASSERT_LOG(payload_size == hci_sco_data_total_length, "malformed SCO packet received: size mismatch");
+      ASSERT_LOG(
+          payload_size == hci_sco_data_total_length,
+          "malformed SCO length received: %d != %d",
+          payload_size,
+          hci_sco_data_total_length);
 
       HciPacket receivedHciPacket;
       receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciScoHeaderSize + payload_size);
@@ -487,15 +433,15 @@ class HciHalHost : public HciHal {
     }
 
     if (buf[0] == kH4Iso) {
-      RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciIsoHeaderSize, 0));
-      ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
-      ASSERT_LOG(received_size == kHciIsoHeaderSize, "malformed ISO header received");
-
+      ASSERT_LOG(
+          received_size >= kH4HeaderSize + kHciIsoHeaderSize, "Received bad HCI_ISO packet size: %zu", received_size);
+      int payload_size = received_size - (kH4HeaderSize + kHciIsoHeaderSize);
       uint16_t hci_iso_data_total_length = ((buf[4] & 0x3f) << 8) + buf[3];
-      int payload_size;
-      RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciIsoHeaderSize, hci_iso_data_total_length, 0));
-      ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
-      ASSERT_LOG(payload_size == hci_iso_data_total_length, "malformed ISO packet received: size mismatch");
+      ASSERT_LOG(
+          payload_size == hci_iso_data_total_length,
+          "malformed ISO length received: %d != %d",
+          payload_size,
+          hci_iso_data_total_length);
 
       HciPacket receivedHciPacket;
       receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciIsoHeaderSize + payload_size);
diff --git a/system/gd/hal/hci_hal_host_rootcanal.cc b/system/gd/hal/hci_hal_host_rootcanal.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b05ae61e8c23fd2f175d066594cd3da9c83ed84f
--- /dev/null
+++ b/system/gd/hal/hci_hal_host_rootcanal.cc
@@ -0,0 +1,369 @@
+/*
+ * 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 "hal/hci_hal_host.h"
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <csignal>
+#include <mutex>
+#include <queue>
+
+#include "hal/hci_hal.h"
+#include "hal/snoop_logger.h"
+#include "os/log.h"
+#include "os/reactor.h"
+#include "os/thread.h"
+
+namespace {
+constexpr int INVALID_FD = -1;
+
+constexpr uint8_t kH4Command = 0x01;
+constexpr uint8_t kH4Acl = 0x02;
+constexpr uint8_t kH4Sco = 0x03;
+constexpr uint8_t kH4Event = 0x04;
+constexpr uint8_t kH4Iso = 0x05;
+
+constexpr uint8_t kH4HeaderSize = 1;
+constexpr uint8_t kHciAclHeaderSize = 4;
+constexpr uint8_t kHciScoHeaderSize = 3;
+constexpr uint8_t kHciEvtHeaderSize = 2;
+constexpr uint8_t kHciIsoHeaderSize = 4;
+constexpr int kBufSize = 1024 + 4 + 1;  // DeviceProperties::acl_data_packet_size_ + ACL header + H4 header
+
+int ConnectToSocket() {
+  auto* config = bluetooth::hal::HciHalHostRootcanalConfig::Get();
+  const std::string& server = config->GetServerAddress();
+  int port = config->GetPort();
+
+  int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+  if (socket_fd < 1) {
+    LOG_ERROR("can't create socket: %s", strerror(errno));
+    return INVALID_FD;
+  }
+
+  struct hostent* host;
+  host = gethostbyname(server.c_str());
+  if (host == nullptr) {
+    LOG_ERROR("can't get server name");
+    return INVALID_FD;
+  }
+
+  struct sockaddr_in serv_addr;
+  memset((void*)&serv_addr, 0, sizeof(serv_addr));
+  serv_addr.sin_family = AF_INET;
+  serv_addr.sin_addr.s_addr = INADDR_ANY;
+  serv_addr.sin_port = htons(port);
+
+  int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+  if (result < 0) {
+    LOG_ERROR("can't connect: %s", strerror(errno));
+    return INVALID_FD;
+  }
+
+  timeval socket_timeout{
+      .tv_sec = 3,
+      .tv_usec = 0,
+  };
+  int ret = setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &socket_timeout, sizeof(socket_timeout));
+  if (ret == -1) {
+    LOG_ERROR("can't control socket fd: %s", strerror(errno));
+    return INVALID_FD;
+  }
+  return socket_fd;
+}
+}  // namespace
+
+namespace bluetooth {
+namespace hal {
+
+class HciHalHost : public HciHal {
+ public:
+  void registerIncomingPacketCallback(HciHalCallbacks* callback) override {
+    std::lock_guard<std::mutex> lock(api_mutex_);
+    LOG_INFO("%s before", __func__);
+    {
+      std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+      ASSERT(incoming_packet_callback_ == nullptr && callback != nullptr);
+      incoming_packet_callback_ = callback;
+    }
+    LOG_INFO("%s after", __func__);
+  }
+
+  void unregisterIncomingPacketCallback() override {
+    std::lock_guard<std::mutex> lock(api_mutex_);
+    LOG_INFO("%s before", __func__);
+    {
+      std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+      incoming_packet_callback_ = nullptr;
+    }
+    LOG_INFO("%s after", __func__);
+  }
+
+  void sendHciCommand(HciPacket command) override {
+    std::lock_guard<std::mutex> lock(api_mutex_);
+    ASSERT(sock_fd_ != INVALID_FD);
+    std::vector<uint8_t> packet = std::move(command);
+    btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::CMD);
+    packet.insert(packet.cbegin(), kH4Command);
+    write_to_fd(packet);
+  }
+
+  void sendAclData(HciPacket data) override {
+    std::lock_guard<std::mutex> lock(api_mutex_);
+    ASSERT(sock_fd_ != INVALID_FD);
+    std::vector<uint8_t> packet = std::move(data);
+    btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL);
+    packet.insert(packet.cbegin(), kH4Acl);
+    write_to_fd(packet);
+  }
+
+  void sendScoData(HciPacket data) override {
+    std::lock_guard<std::mutex> lock(api_mutex_);
+    ASSERT(sock_fd_ != INVALID_FD);
+    std::vector<uint8_t> packet = std::move(data);
+    btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::SCO);
+    packet.insert(packet.cbegin(), kH4Sco);
+    write_to_fd(packet);
+  }
+
+  void sendIsoData(HciPacket data) override {
+    std::lock_guard<std::mutex> lock(api_mutex_);
+    ASSERT(sock_fd_ != INVALID_FD);
+    std::vector<uint8_t> packet = std::move(data);
+    btsnoop_logger_->Capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ISO);
+    packet.insert(packet.cbegin(), kH4Iso);
+    write_to_fd(packet);
+  }
+
+ protected:
+  void ListDependencies(ModuleList* list) override {
+    list->add<SnoopLogger>();
+  }
+
+  void Start() override {
+    std::lock_guard<std::mutex> lock(api_mutex_);
+    ASSERT(sock_fd_ == INVALID_FD);
+    sock_fd_ = ConnectToSocket();
+    ASSERT(sock_fd_ != INVALID_FD);
+    reactable_ = hci_incoming_thread_.GetReactor()->Register(
+        sock_fd_, common::Bind(&HciHalHost::incoming_packet_received, common::Unretained(this)), common::Closure());
+    btsnoop_logger_ = GetDependency<SnoopLogger>();
+    LOG_INFO("HAL opened successfully");
+  }
+
+  void Stop() override {
+    std::lock_guard<std::mutex> lock(api_mutex_);
+    LOG_INFO("HAL is closing");
+    if (reactable_ != nullptr) {
+      hci_incoming_thread_.GetReactor()->Unregister(reactable_);
+      LOG_INFO("HAL is stopping, start waiting for last callback");
+      // Wait up to 1 second for the last incoming packet callback to finish
+      hci_incoming_thread_.GetReactor()->WaitForUnregisteredReactable(std::chrono::milliseconds(1000));
+      LOG_INFO("HAL is stopping, finished waiting for last callback");
+      ASSERT(sock_fd_ != INVALID_FD);
+    }
+    reactable_ = nullptr;
+    {
+      std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+      incoming_packet_callback_ = nullptr;
+    }
+    ::close(sock_fd_);
+    sock_fd_ = INVALID_FD;
+    LOG_INFO("HAL is closed");
+  }
+
+  std::string ToString() const override {
+    return std::string("HciHalHost");
+  }
+
+ private:
+  // Held when APIs are called, NOT to be held during callbacks
+  std::mutex api_mutex_;
+  HciHalCallbacks* incoming_packet_callback_ = nullptr;
+  std::mutex incoming_packet_callback_mutex_;
+  int sock_fd_ = INVALID_FD;
+  bluetooth::os::Thread hci_incoming_thread_ =
+      bluetooth::os::Thread("hci_incoming_thread", bluetooth::os::Thread::Priority::NORMAL);
+  bluetooth::os::Reactor::Reactable* reactable_ = nullptr;
+  std::queue<std::vector<uint8_t>> hci_outgoing_queue_;
+  SnoopLogger* btsnoop_logger_ = nullptr;
+
+  void write_to_fd(HciPacket packet) {
+    // TODO: replace this with new queue when it's ready
+    hci_outgoing_queue_.emplace(packet);
+    if (hci_outgoing_queue_.size() == 1) {
+      hci_incoming_thread_.GetReactor()->ModifyRegistration(
+          reactable_,
+          common::Bind(&HciHalHost::incoming_packet_received, common::Unretained(this)),
+          common::Bind(&HciHalHost::send_packet_ready, common::Unretained(this)));
+    }
+  }
+
+  void send_packet_ready() {
+    std::lock_guard<std::mutex> lock(this->api_mutex_);
+    auto packet_to_send = this->hci_outgoing_queue_.front();
+    auto bytes_written = write(this->sock_fd_, (void*)packet_to_send.data(), packet_to_send.size());
+    this->hci_outgoing_queue_.pop();
+    if (bytes_written == -1) {
+      abort();
+    }
+    if (hci_outgoing_queue_.empty()) {
+      this->hci_incoming_thread_.GetReactor()->ModifyRegistration(
+          this->reactable_,
+          common::Bind(&HciHalHost::incoming_packet_received, common::Unretained(this)),
+          common::Closure());
+    }
+  }
+
+  void incoming_packet_received() {
+    {
+      std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+      if (incoming_packet_callback_ == nullptr) {
+        LOG_INFO("Dropping a packet");
+        return;
+      }
+    }
+    uint8_t buf[kBufSize] = {};
+
+    ssize_t received_size;
+    RUN_NO_INTR(received_size = recv(sock_fd_, buf, kH4HeaderSize, 0));
+    ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+    if (received_size == 0) {
+      LOG_WARN("Can't read H4 header. EOF received");
+      raise(SIGINT);
+      return;
+    }
+
+    if (buf[0] == kH4Event) {
+      RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciEvtHeaderSize, 0));
+      ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+      ASSERT_LOG(received_size == kHciEvtHeaderSize, "malformed HCI event header received");
+
+      uint8_t hci_evt_parameter_total_length = buf[2];
+      ssize_t payload_size;
+      RUN_NO_INTR(
+          payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciEvtHeaderSize, hci_evt_parameter_total_length, 0));
+      ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+      ASSERT_LOG(
+          payload_size == hci_evt_parameter_total_length,
+          "malformed HCI event total parameter size received: %zu != %d",
+          payload_size,
+          hci_evt_parameter_total_length);
+
+      HciPacket receivedHciPacket;
+      receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciEvtHeaderSize + payload_size);
+      btsnoop_logger_->Capture(receivedHciPacket, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::EVT);
+      {
+        std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+        if (incoming_packet_callback_ == nullptr) {
+          LOG_INFO("Dropping an event after processing");
+          return;
+        }
+        incoming_packet_callback_->hciEventReceived(receivedHciPacket);
+      }
+    }
+
+    if (buf[0] == kH4Acl) {
+      RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciAclHeaderSize, 0));
+      ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+      ASSERT_LOG(received_size == kHciAclHeaderSize, "malformed ACL header received");
+
+      uint16_t hci_acl_data_total_length = (buf[4] << 8) + buf[3];
+      int payload_size;
+      RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciAclHeaderSize, hci_acl_data_total_length, 0));
+      ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+      ASSERT_LOG(
+          payload_size == hci_acl_data_total_length,
+          "malformed ACL length received: %d != %d",
+          payload_size,
+          hci_acl_data_total_length);
+      ASSERT_LOG(hci_acl_data_total_length <= kBufSize - kH4HeaderSize - kHciAclHeaderSize, "packet too long");
+
+      HciPacket receivedHciPacket;
+      receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciAclHeaderSize + payload_size);
+      btsnoop_logger_->Capture(receivedHciPacket, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::ACL);
+      {
+        std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+        if (incoming_packet_callback_ == nullptr) {
+          LOG_INFO("Dropping an ACL packet after processing");
+          return;
+        }
+        incoming_packet_callback_->aclDataReceived(receivedHciPacket);
+      }
+    }
+
+    if (buf[0] == kH4Sco) {
+      RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciScoHeaderSize, 0));
+      ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+      ASSERT_LOG(received_size == kHciScoHeaderSize, "malformed SCO header received");
+
+      uint8_t hci_sco_data_total_length = buf[3];
+      int payload_size;
+      RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciScoHeaderSize, hci_sco_data_total_length, 0));
+      ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+      ASSERT_LOG(payload_size == hci_sco_data_total_length, "malformed SCO packet received: size mismatch");
+
+      HciPacket receivedHciPacket;
+      receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciScoHeaderSize + payload_size);
+      btsnoop_logger_->Capture(receivedHciPacket, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::SCO);
+      {
+        std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+        if (incoming_packet_callback_ == nullptr) {
+          LOG_INFO("Dropping a SCO packet after processing");
+          return;
+        }
+        incoming_packet_callback_->scoDataReceived(receivedHciPacket);
+      }
+    }
+
+    if (buf[0] == kH4Iso) {
+      RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciIsoHeaderSize, 0));
+      ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+      ASSERT_LOG(received_size == kHciIsoHeaderSize, "malformed ISO header received");
+
+      uint16_t hci_iso_data_total_length = ((buf[4] & 0x3f) << 8) + buf[3];
+      int payload_size;
+      RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciIsoHeaderSize, hci_iso_data_total_length, 0));
+      ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+      ASSERT_LOG(payload_size == hci_iso_data_total_length, "malformed ISO packet received: size mismatch");
+
+      HciPacket receivedHciPacket;
+      receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciIsoHeaderSize + payload_size);
+      btsnoop_logger_->Capture(receivedHciPacket, SnoopLogger::Direction::INCOMING, SnoopLogger::PacketType::ISO);
+      {
+        std::lock_guard<std::mutex> incoming_packet_callback_lock(incoming_packet_callback_mutex_);
+        if (incoming_packet_callback_ == nullptr) {
+          LOG_INFO("Dropping a ISO packet after processing");
+          return;
+        }
+        incoming_packet_callback_->isoDataReceived(receivedHciPacket);
+      }
+    }
+    memset(buf, 0, kBufSize);
+  }
+};
+
+const ModuleFactory HciHal::Factory = ModuleFactory([]() { return new HciHalHost(); });
+
+}  // namespace hal
+}  // namespace bluetooth