Bring multi-channel transport into the glorious new age

Some devices still use MCT as their UART protocol, so
we need to bring it forward to the fresh new HAL.

Also, adding tests for H4 while I'm here.

Test: new unit tests pass and a device using MCT now
boots BT again \o/
Fixes: 34992730
Change-Id: Idb8e536a2779929ad8a0d4bac492c3011995cd79
diff --git a/bluetooth/1.0/default/Android.bp b/bluetooth/1.0/default/Android.bp
index fb20195..e04c2f4 100644
--- a/bluetooth/1.0/default/Android.bp
+++ b/bluetooth/1.0/default/Android.bp
@@ -56,6 +56,9 @@
     name: "android.hardware.bluetooth-hci",
     srcs: [
         "hci_packetizer.cc",
+        "hci_protocol.cc",
+        "h4_protocol.cc",
+        "mct_protocol.cc",
     ],
     export_include_dirs: ["."],
     shared_libs: [
@@ -71,16 +74,21 @@
     name: "bluetooth-vendor-interface-unit-tests",
     srcs: [
         "test/async_fd_watcher_unittest.cc",
+        "test/h4_protocol_unittest.cc",
+        "test/mct_protocol_unittest.cc",
     ],
     local_include_dirs: [
         "test",
     ],
     shared_libs: [
         "libbase",
+        "libhidlbase",
         "liblog",
     ],
     static_libs: [
         "android.hardware.bluetooth-async",
+        "android.hardware.bluetooth-hci",
+        "libgmock",
     ],
 }
 
diff --git a/bluetooth/1.0/default/bluetooth_hci.cc b/bluetooth/1.0/default/bluetooth_hci.cc
index 1d6e600..5a282bf 100644
--- a/bluetooth/1.0/default/bluetooth_hci.cc
+++ b/bluetooth/1.0/default/bluetooth_hci.cc
@@ -44,21 +44,14 @@
         event_cb_->initializationComplete(
             status ? Status::SUCCESS : Status::INITIALIZATION_ERROR);
       },
-      [this](HciPacketType type, const hidl_vec<uint8_t>& packet) {
-        switch (type) {
-          case HCI_PACKET_TYPE_EVENT:
-            event_cb_->hciEventReceived(packet);
-            break;
-          case HCI_PACKET_TYPE_ACL_DATA:
-            event_cb_->aclDataReceived(packet);
-            break;
-          case HCI_PACKET_TYPE_SCO_DATA:
-            event_cb_->scoDataReceived(packet);
-            break;
-          default:
-            ALOGE("%s Unexpected event type %d", __func__, type);
-            break;
-        }
+      [this](const hidl_vec<uint8_t>& packet) {
+        event_cb_->hciEventReceived(packet);
+      },
+      [this](const hidl_vec<uint8_t>& packet) {
+        event_cb_->aclDataReceived(packet);
+      },
+      [this](const hidl_vec<uint8_t>& packet) {
+        event_cb_->scoDataReceived(packet);
       });
   if (!rc) event_cb_->initializationComplete(Status::INITIALIZATION_ERROR);
   return Void();
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
new file mode 100644
index 0000000..8f24b5e
--- /dev/null
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -0,0 +1,71 @@
+//
+// Copyright 2017 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 "h4_protocol.h"
+
+#define LOG_TAG "android.hardware.bluetooth-hci-h4"
+#include <android-base/logging.h>
+#include <assert.h>
+#include <fcntl.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+size_t H4Protocol::Send(uint8_t type, const uint8_t* data, size_t length) {
+  int rv = WriteSafely(uart_fd_, &type, sizeof(type));
+  if (rv == sizeof(type)) {
+    rv = WriteSafely(uart_fd_, data, length);
+  }
+  return rv;
+}
+
+void H4Protocol::OnPacketReady() {
+  switch (hci_packet_type_) {
+    case HCI_PACKET_TYPE_EVENT:
+      event_cb_(hci_packetizer_.GetPacket());
+      break;
+    case HCI_PACKET_TYPE_ACL_DATA:
+      acl_cb_(hci_packetizer_.GetPacket());
+      break;
+    case HCI_PACKET_TYPE_SCO_DATA:
+      sco_cb_(hci_packetizer_.GetPacket());
+      break;
+    default: {
+      bool bad_packet_type = true;
+      CHECK(!bad_packet_type);
+    }
+  }
+  // Get ready for the next type byte.
+  hci_packet_type_ = HCI_PACKET_TYPE_UNKNOWN;
+}
+
+void H4Protocol::OnDataReady(int fd) {
+  if (hci_packet_type_ == HCI_PACKET_TYPE_UNKNOWN) {
+    uint8_t buffer[1] = {0};
+    size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
+    CHECK(bytes_read == 1);
+    hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
+  } else {
+    hci_packetizer_.OnDataReady(fd, hci_packet_type_);
+  }
+}
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/h4_protocol.h b/bluetooth/1.0/default/h4_protocol.h
new file mode 100644
index 0000000..0d0a1ca
--- /dev/null
+++ b/bluetooth/1.0/default/h4_protocol.h
@@ -0,0 +1,61 @@
+//
+// Copyright 2017 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 <hidl/HidlSupport.h>
+
+#include "async_fd_watcher.h"
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_protocol.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+class H4Protocol : public HciProtocol {
+ public:
+  H4Protocol(int fd, PacketReadCallback event_cb, PacketReadCallback acl_cb,
+             PacketReadCallback sco_cb)
+      : uart_fd_(fd),
+        event_cb_(event_cb),
+        acl_cb_(acl_cb),
+        sco_cb_(sco_cb),
+        hci_packetizer_([this]() { OnPacketReady(); }) {}
+
+  size_t Send(uint8_t type, const uint8_t* data, size_t length);
+
+  void OnPacketReady();
+
+  void OnDataReady(int fd);
+
+ private:
+  int uart_fd_;
+
+  PacketReadCallback event_cb_;
+  PacketReadCallback acl_cb_;
+  PacketReadCallback sco_cb_;
+
+  HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
+  hci::HciPacketizer hci_packetizer_;
+};
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/hci_packetizer.cc b/bluetooth/1.0/default/hci_packetizer.cc
index 1a50196..9549858 100644
--- a/bluetooth/1.0/default/hci_packetizer.cc
+++ b/bluetooth/1.0/default/hci_packetizer.cc
@@ -18,7 +18,6 @@
 
 #define LOG_TAG "android.hardware.bluetooth.hci_packetizer"
 #include <android-base/logging.h>
-#include <cutils/properties.h>
 #include <utils/Log.h>
 
 #include <dlfcn.h>
@@ -46,63 +45,40 @@
 namespace bluetooth {
 namespace hci {
 
-HciPacketType HciPacketizer::GetPacketType() const {
-  return hci_packet_type_;
-}
+const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const { return packet_; }
 
-const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const {
-  return hci_packet_;
-}
-
-void HciPacketizer::OnDataReady(int fd) {
-  switch (hci_parser_state_) {
-    case HCI_IDLE: {
-      uint8_t buffer[1] = {0};
-      size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
-      CHECK(bytes_read == 1);
-      hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
-      CHECK(hci_packet_type_ >= HCI_PACKET_TYPE_ACL_DATA &&
-            hci_packet_type_ <= HCI_PACKET_TYPE_EVENT)
-          << "buffer[0] = " << static_cast<unsigned int>(buffer[0]);
-      hci_parser_state_ = HCI_TYPE_READY;
-      hci_packet_bytes_remaining_ = preamble_size_for_type[hci_packet_type_];
-      hci_packet_bytes_read_ = 0;
-      break;
-    }
-
-    case HCI_TYPE_READY: {
+void HciPacketizer::OnDataReady(int fd, HciPacketType packet_type) {
+  switch (state_) {
+    case HCI_PREAMBLE: {
       size_t bytes_read = TEMP_FAILURE_RETRY(
-          read(fd, hci_packet_preamble_ + hci_packet_bytes_read_,
-               hci_packet_bytes_remaining_));
+          read(fd, preamble_ + bytes_read_,
+               preamble_size_for_type[packet_type] - bytes_read_));
       CHECK(bytes_read > 0);
-      hci_packet_bytes_remaining_ -= bytes_read;
-      hci_packet_bytes_read_ += bytes_read;
-      if (hci_packet_bytes_remaining_ == 0) {
+      bytes_read_ += bytes_read;
+      if (bytes_read_ == preamble_size_for_type[packet_type]) {
         size_t packet_length =
-            HciGetPacketLengthForType(hci_packet_type_, hci_packet_preamble_);
-        hci_packet_.resize(preamble_size_for_type[hci_packet_type_] +
-                           packet_length);
-        memcpy(hci_packet_.data(), hci_packet_preamble_,
-               preamble_size_for_type[hci_packet_type_]);
-        hci_packet_bytes_remaining_ = packet_length;
-        hci_parser_state_ = HCI_PAYLOAD;
-        hci_packet_bytes_read_ = 0;
+            HciGetPacketLengthForType(packet_type, preamble_);
+        packet_.resize(preamble_size_for_type[packet_type] + packet_length);
+        memcpy(packet_.data(), preamble_, preamble_size_for_type[packet_type]);
+        bytes_remaining_ = packet_length;
+        state_ = HCI_PAYLOAD;
+        bytes_read_ = 0;
       }
       break;
     }
 
     case HCI_PAYLOAD: {
-      size_t bytes_read = TEMP_FAILURE_RETRY(
-          read(fd,
-               hci_packet_.data() + preamble_size_for_type[hci_packet_type_] +
-                   hci_packet_bytes_read_,
-               hci_packet_bytes_remaining_));
+      size_t bytes_read = TEMP_FAILURE_RETRY(read(
+          fd,
+          packet_.data() + preamble_size_for_type[packet_type] + bytes_read_,
+          bytes_remaining_));
       CHECK(bytes_read > 0);
-      hci_packet_bytes_remaining_ -= bytes_read;
-      hci_packet_bytes_read_ += bytes_read;
-      if (hci_packet_bytes_remaining_ == 0) {
-        hci_packet_ready_cb_();
-        hci_parser_state_ = HCI_IDLE;
+      bytes_remaining_ -= bytes_read;
+      bytes_read_ += bytes_read;
+      if (bytes_remaining_ == 0) {
+        packet_ready_cb_();
+        state_ = HCI_PREAMBLE;
+        bytes_read_ = 0;
       }
       break;
     }
diff --git a/bluetooth/1.0/default/hci_packetizer.h b/bluetooth/1.0/default/hci_packetizer.h
index e9c01dc..90579bd 100644
--- a/bluetooth/1.0/default/hci_packetizer.h
+++ b/bluetooth/1.0/default/hci_packetizer.h
@@ -32,20 +32,19 @@
 
 class HciPacketizer {
  public:
-  HciPacketizer(HciPacketReadyCallback packet_cb) : hci_packet_ready_cb_(packet_cb) {};
-  void OnDataReady(int fd);
+  HciPacketizer(HciPacketReadyCallback packet_cb)
+      : packet_ready_cb_(packet_cb){};
+  void OnDataReady(int fd, HciPacketType packet_type);
   const hidl_vec<uint8_t>& GetPacket() const;
-  HciPacketType GetPacketType() const;
 
  protected:
-  enum HciParserState { HCI_IDLE, HCI_TYPE_READY, HCI_PAYLOAD };
-  HciParserState hci_parser_state_{HCI_IDLE};
-  HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
-  uint8_t hci_packet_preamble_[HCI_PREAMBLE_SIZE_MAX];
-  hidl_vec<uint8_t> hci_packet_;
-  size_t hci_packet_bytes_remaining_;
-  size_t hci_packet_bytes_read_;
-  HciPacketReadyCallback hci_packet_ready_cb_;
+  enum State { HCI_PREAMBLE, HCI_PAYLOAD };
+  State state_{HCI_PREAMBLE};
+  uint8_t preamble_[HCI_PREAMBLE_SIZE_MAX];
+  hidl_vec<uint8_t> packet_;
+  size_t bytes_remaining_{0};
+  size_t bytes_read_{0};
+  HciPacketReadyCallback packet_ready_cb_;
 };
 
 }  // namespace hci
diff --git a/bluetooth/1.0/default/hci_protocol.cc b/bluetooth/1.0/default/hci_protocol.cc
new file mode 100644
index 0000000..cd709b4
--- /dev/null
+++ b/bluetooth/1.0/default/hci_protocol.cc
@@ -0,0 +1,74 @@
+//
+// Copyright 2017 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 "hci_protocol.h"
+
+#define LOG_TAG "android.hardware.bluetooth-hci-hci_protocol"
+#include <android-base/logging.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+
+namespace {
+
+const size_t preamble_size_for_type[] = {
+    0, HCI_COMMAND_PREAMBLE_SIZE, HCI_ACL_PREAMBLE_SIZE, HCI_SCO_PREAMBLE_SIZE,
+    HCI_EVENT_PREAMBLE_SIZE};
+const size_t packet_length_offset_for_type[] = {
+    0, HCI_LENGTH_OFFSET_CMD, HCI_LENGTH_OFFSET_ACL, HCI_LENGTH_OFFSET_SCO,
+    HCI_LENGTH_OFFSET_EVT};
+
+size_t HciGetPacketLengthForType(HciPacketType type, const uint8_t* preamble) {
+  size_t offset = packet_length_offset_for_type[type];
+  if (type != HCI_PACKET_TYPE_ACL_DATA) return preamble[offset];
+  return (((preamble[offset + 1]) << 8) | preamble[offset]);
+}
+
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+size_t HciProtocol::WriteSafely(int fd, const uint8_t* data, size_t length) {
+  size_t transmitted_length = 0;
+  while (length > 0) {
+    ssize_t ret =
+        TEMP_FAILURE_RETRY(write(fd, data + transmitted_length, length));
+
+    if (ret == -1) {
+      if (errno == EAGAIN) continue;
+      ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+      break;
+
+    } else if (ret == 0) {
+      // Nothing written :(
+      ALOGE("%s zero bytes written - something went wrong...", __func__);
+      break;
+    }
+
+    transmitted_length += ret;
+    length -= ret;
+  }
+
+  return transmitted_length;
+}
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/hci_protocol.h b/bluetooth/1.0/default/hci_protocol.h
new file mode 100644
index 0000000..6821107
--- /dev/null
+++ b/bluetooth/1.0/default/hci_protocol.h
@@ -0,0 +1,49 @@
+//
+// Copyright 2017 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 <hidl/HidlSupport.h>
+
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_packetizer.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+using ::android::hardware::hidl_vec;
+using PacketReadCallback = std::function<void(const hidl_vec<uint8_t>&)>;
+
+// Implementation of HCI protocol bits common to different transports
+class HciProtocol {
+ public:
+  HciProtocol() = default;
+  virtual ~HciProtocol(){};
+
+  // Protocol-specific implementation of sending packets.
+  virtual size_t Send(uint8_t type, const uint8_t* data, size_t length) = 0;
+
+ protected:
+  static size_t WriteSafely(int fd, const uint8_t* data, size_t length);
+};
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/mct_protocol.cc b/bluetooth/1.0/default/mct_protocol.cc
new file mode 100644
index 0000000..813cebd
--- /dev/null
+++ b/bluetooth/1.0/default/mct_protocol.cc
@@ -0,0 +1,71 @@
+//
+// Copyright 2017 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 "mct_protocol.h"
+
+#include <assert.h>
+
+#define LOG_TAG "android.hardware.bluetooth-hci-mct"
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+#include <fcntl.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+MctProtocol::MctProtocol(int* fds, PacketReadCallback event_cb,
+                         PacketReadCallback acl_cb)
+    : event_cb_(event_cb),
+      acl_cb_(acl_cb),
+      event_packetizer_([this]() { OnEventPacketReady(); }),
+      acl_packetizer_([this]() { OnAclDataPacketReady(); }) {
+  for (int i = 0; i < CH_MAX; i++) {
+    uart_fds_[i] = fds[i];
+  }
+}
+
+size_t MctProtocol::Send(uint8_t type, const uint8_t* data, size_t length) {
+  if (type == HCI_PACKET_TYPE_COMMAND)
+    return WriteSafely(uart_fds_[CH_CMD], data, length);
+  if (type == HCI_PACKET_TYPE_ACL_DATA)
+    return WriteSafely(uart_fds_[CH_ACL_OUT], data, length);
+  CHECK(type == HCI_PACKET_TYPE_COMMAND || type == HCI_PACKET_TYPE_ACL_DATA);
+  return 0;
+}
+
+void MctProtocol::OnEventPacketReady() {
+  event_cb_(event_packetizer_.GetPacket());
+}
+
+void MctProtocol::OnAclDataPacketReady() {
+  acl_cb_(acl_packetizer_.GetPacket());
+}
+
+void MctProtocol::OnEventDataReady(int fd) {
+  event_packetizer_.OnDataReady(fd, HCI_PACKET_TYPE_EVENT);
+}
+
+void MctProtocol::OnAclDataReady(int fd) {
+  acl_packetizer_.OnDataReady(fd, HCI_PACKET_TYPE_ACL_DATA);
+}
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/mct_protocol.h b/bluetooth/1.0/default/mct_protocol.h
new file mode 100644
index 0000000..6991746
--- /dev/null
+++ b/bluetooth/1.0/default/mct_protocol.h
@@ -0,0 +1,56 @@
+//
+// Copyright 2017 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 <hidl/HidlSupport.h>
+
+#include "async_fd_watcher.h"
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_protocol.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+class MctProtocol : public HciProtocol {
+ public:
+  MctProtocol(int* fds, PacketReadCallback event_cb, PacketReadCallback acl_cb);
+
+  size_t Send(uint8_t type, const uint8_t* data, size_t length);
+
+  void OnEventPacketReady();
+  void OnAclDataPacketReady();
+
+  void OnEventDataReady(int fd);
+  void OnAclDataReady(int fd);
+
+ private:
+  int uart_fds_[CH_MAX];
+
+  PacketReadCallback event_cb_;
+  PacketReadCallback acl_cb_;
+
+  hci::HciPacketizer event_packetizer_;
+  hci::HciPacketizer acl_packetizer_;
+};
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/test/h4_protocol_unittest.cc b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
new file mode 100644
index 0000000..d53aaa9
--- /dev/null
+++ b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
@@ -0,0 +1,213 @@
+//
+// Copyright 2017 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.
+//
+
+#define LOG_TAG "bt_h4_unittest"
+
+#include "h4_protocol.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <mutex>
+#include <vector>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+using ::testing::Eq;
+using hci::H4Protocol;
+
+static char sample_data1[100] = "A point is that which has no part.";
+static char sample_data2[100] = "A line is breadthless length.";
+static char sample_data3[100] = "The ends of a line are points.";
+static char acl_data[100] =
+    "A straight line is a line which lies evenly with the points on itself.";
+static char sco_data[100] =
+    "A surface is that which has length and breadth only.";
+static char event_data[100] = "The edges of a surface are lines.";
+
+MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
+  size_t length = strlen(payload) + preamble_length;
+  if (length != arg.size()) {
+    return false;
+  }
+
+  if (memcmp(preamble, arg.data(), preamble_length) != 0) {
+    return false;
+  }
+
+  return memcmp(payload, arg.data() + preamble_length,
+                length - preamble_length) == 0;
+};
+
+ACTION_P2(Notify, mutex, condition) {
+  ALOGD("%s", __func__);
+  std::unique_lock<std::mutex> lock(*mutex);
+  condition->notify_one();
+}
+
+class H4ProtocolTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    ALOGD("%s", __func__);
+
+    int sockfd[2];
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+    H4Protocol* h4_hci =
+        new H4Protocol(sockfd[0], event_cb_.AsStdFunction(),
+                       acl_cb_.AsStdFunction(), sco_cb_.AsStdFunction());
+    fd_watcher_.WatchFdForNonBlockingReads(
+        sockfd[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
+    protocol_ = h4_hci;
+
+    fake_uart_ = sockfd[1];
+  }
+
+  void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
+
+  void SendAndReadUartOutbound(uint8_t type, char* data) {
+    ALOGD("%s sending", __func__);
+    int data_length = strlen(data);
+    protocol_->Send(type, (uint8_t*)data, data_length);
+
+    int uart_length = data_length + 1;  // + 1 for data type code
+    int i;
+
+    ALOGD("%s reading", __func__);
+    for (i = 0; i < uart_length; i++) {
+      fd_set read_fds;
+      FD_ZERO(&read_fds);
+      FD_SET(fake_uart_, &read_fds);
+      TEMP_FAILURE_RETRY(select(fake_uart_ + 1, &read_fds, NULL, NULL, NULL));
+
+      char byte;
+      TEMP_FAILURE_RETRY(read(fake_uart_, &byte, 1));
+
+      EXPECT_EQ(i == 0 ? type : data[i - 1], byte);
+    }
+
+    EXPECT_EQ(i, uart_length);
+  }
+
+  void WriteAndExpectInboundAclData(char* payload) {
+    // h4 type[1] + handle[2] + size[2]
+    char preamble[5] = {HCI_PACKET_TYPE_ACL_DATA, 19, 92, 0, 0};
+    int length = strlen(payload);
+    preamble[3] = length & 0xFF;
+    preamble[4] = (length >> 8) & 0xFF;
+
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(acl_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
+                                             payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    // Fail if it takes longer than 100 ms.
+    auto timeout_time =
+        std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait_until(lock, timeout_time);
+    }
+  }
+
+  void WriteAndExpectInboundScoData(char* payload) {
+    // h4 type[1] + handle[2] + size[1]
+    char preamble[4] = {HCI_PACKET_TYPE_SCO_DATA, 20, 17, 0};
+    preamble[3] = strlen(payload) & 0xFF;
+
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(sco_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
+                                             payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    // Fail if it takes longer than 100 ms.
+    auto timeout_time =
+        std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait_until(lock, timeout_time);
+    }
+  }
+
+  void WriteAndExpectInboundEvent(char* payload) {
+    // h4 type[1] + event_code[1] + size[1]
+    char preamble[3] = {HCI_PACKET_TYPE_EVENT, 9, 0};
+    preamble[2] = strlen(payload) & 0xFF;
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(event_cb_, Call(HidlVecMatches(preamble + 1,
+                                               sizeof(preamble) - 1, payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait(lock);
+    }
+  }
+
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> sco_cb_;
+  async::AsyncFdWatcher fd_watcher_;
+  H4Protocol* protocol_;
+  int fake_uart_;
+};
+
+// Test sending data sends correct data onto the UART
+TEST_F(H4ProtocolTest, TestSends) {
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1);
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2);
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_SCO_DATA, sample_data3);
+}
+
+// Ensure we properly parse data coming from the UART
+TEST_F(H4ProtocolTest, TestReads) {
+  WriteAndExpectInboundAclData(acl_data);
+  WriteAndExpectInboundScoData(sco_data);
+  WriteAndExpectInboundEvent(event_data);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/test/mct_protocol_unittest.cc b/bluetooth/1.0/default/test/mct_protocol_unittest.cc
new file mode 100644
index 0000000..5751a5e
--- /dev/null
+++ b/bluetooth/1.0/default/test/mct_protocol_unittest.cc
@@ -0,0 +1,200 @@
+//
+// Copyright 2017 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.
+//
+
+#define LOG_TAG "bt_h4_unittest"
+
+#include "mct_protocol.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <condition_variable>
+#include <cstdint>
+#include <cstring>
+#include <mutex>
+#include <vector>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+using ::testing::Eq;
+using hci::MctProtocol;
+
+static char sample_data1[100] = "A point is that which has no part.";
+static char sample_data2[100] = "A line is breadthless length.";
+static char sample_data3[100] = "The ends of a line are points.";
+static char acl_data[100] =
+    "A straight line is a line which lies evenly with the points on itself.";
+static char sco_data[100] =
+    "A surface is that which has length and breadth only.";
+static char event_data[100] = "The edges of a surface are lines.";
+
+MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
+  size_t length = strlen(payload) + preamble_length;
+  if (length != arg.size()) {
+    return false;
+  }
+
+  if (memcmp(preamble, arg.data(), preamble_length) != 0) {
+    return false;
+  }
+
+  return memcmp(payload, arg.data() + preamble_length,
+                length - preamble_length) == 0;
+};
+
+ACTION_P2(Notify, mutex, condition) {
+  ALOGD("%s", __func__);
+  std::unique_lock<std::mutex> lock(*mutex);
+  condition->notify_one();
+}
+
+class MctProtocolTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    ALOGD("%s", __func__);
+
+    int mct_fds[CH_MAX];
+    MakeFakeUartFd(CH_CMD, mct_fds, fake_uart_);
+    MakeFakeUartFd(CH_EVT, mct_fds, fake_uart_);
+    MakeFakeUartFd(CH_ACL_IN, mct_fds, fake_uart_);
+    MakeFakeUartFd(CH_ACL_OUT, mct_fds, fake_uart_);
+
+    MctProtocol* mct_hci = new MctProtocol(mct_fds, event_cb_.AsStdFunction(),
+                                           acl_cb_.AsStdFunction());
+    fd_watcher_.WatchFdForNonBlockingReads(
+        mct_fds[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
+    fd_watcher_.WatchFdForNonBlockingReads(
+        mct_fds[CH_ACL_IN], [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+    protocol_ = mct_hci;
+  }
+
+  void MakeFakeUartFd(int index, int* host_side, int* controller_side) {
+    int sockfd[2];
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+    host_side[index] = sockfd[0];
+    controller_side[index] = sockfd[1];
+  }
+
+  void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
+
+  void SendAndReadUartOutbound(uint8_t type, char* data, int outbound_fd) {
+    ALOGD("%s sending", __func__);
+    int data_length = strlen(data);
+    protocol_->Send(type, (uint8_t*)data, data_length);
+
+    ALOGD("%s reading", __func__);
+    int i;
+    for (i = 0; i < data_length; i++) {
+      fd_set read_fds;
+      FD_ZERO(&read_fds);
+      FD_SET(outbound_fd, &read_fds);
+      TEMP_FAILURE_RETRY(select(outbound_fd + 1, &read_fds, NULL, NULL, NULL));
+
+      char byte;
+      TEMP_FAILURE_RETRY(read(outbound_fd, &byte, 1));
+
+      EXPECT_EQ(data[i], byte);
+    }
+
+    EXPECT_EQ(i, data_length);
+  }
+
+  void WriteAndExpectInboundAclData(char* payload) {
+    // handle[2] + size[2]
+    char preamble[4] = {19, 92, 0, 0};
+    int length = strlen(payload);
+    preamble[2] = length & 0xFF;
+    preamble[3] = (length >> 8) & 0xFF;
+
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(
+        write(fake_uart_[CH_ACL_IN], preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_[CH_ACL_IN], payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(acl_cb_,
+                Call(HidlVecMatches(preamble, sizeof(preamble), payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    // Fail if it takes longer than 100 ms.
+    auto timeout_time =
+        std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait_until(lock, timeout_time);
+    }
+  }
+
+  void WriteAndExpectInboundEvent(char* payload) {
+    // event_code[1] + size[1]
+    char preamble[2] = {9, 0};
+    preamble[1] = strlen(payload) & 0xFF;
+
+    ALOGD("%s writing", __func__);
+    TEMP_FAILURE_RETRY(write(fake_uart_[CH_EVT], preamble, sizeof(preamble)));
+    TEMP_FAILURE_RETRY(write(fake_uart_[CH_EVT], payload, strlen(payload)));
+
+    ALOGD("%s waiting", __func__);
+    std::mutex mutex;
+    std::condition_variable done;
+    EXPECT_CALL(event_cb_,
+                Call(HidlVecMatches(preamble, sizeof(preamble), payload)))
+        .WillOnce(Notify(&mutex, &done));
+
+    // Fail if it takes longer than 100 ms.
+    auto timeout_time =
+        std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+    {
+      std::unique_lock<std::mutex> lock(mutex);
+      done.wait_until(lock, timeout_time);
+    }
+  }
+
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
+  testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
+  async::AsyncFdWatcher fd_watcher_;
+  MctProtocol* protocol_;
+  int fake_uart_[CH_MAX];
+};
+
+// Test sending data sends correct data onto the UART
+TEST_F(MctProtocolTest, TestSends) {
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1,
+                          fake_uart_[CH_CMD]);
+  SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2,
+                          fake_uart_[CH_ACL_OUT]);
+}
+
+// Ensure we properly parse data coming from the UART
+TEST_F(MctProtocolTest, TestReads) {
+  WriteAndExpectInboundAclData(acl_data);
+  WriteAndExpectInboundEvent(event_data);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index 2c55d1c..6d3b56f 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -27,6 +27,8 @@
 #include <fcntl.h>
 
 #include "bluetooth_address.h"
+#include "h4_protocol.h"
+#include "mct_protocol.h"
 
 static const char* VENDOR_LIBRARY_NAME = "libbt-vendor.so";
 static const char* VENDOR_LIBRARY_SYMBOL_NAME =
@@ -64,30 +66,6 @@
   return packet;
 }
 
-size_t write_safely(int fd, const uint8_t* data, size_t length) {
-  size_t transmitted_length = 0;
-  while (length > 0) {
-    ssize_t ret =
-        TEMP_FAILURE_RETRY(write(fd, data + transmitted_length, length));
-
-    if (ret == -1) {
-      if (errno == EAGAIN) continue;
-      ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
-      break;
-
-    } else if (ret == 0) {
-      // Nothing written :(
-      ALOGE("%s zero bytes written - something went wrong...", __func__);
-      break;
-    }
-
-    transmitted_length += ret;
-    length -= ret;
-  }
-
-  return transmitted_length;
-}
-
 bool internal_command_event_match(const hidl_vec<uint8_t>& packet) {
   uint8_t event_code = packet[0];
   if (event_code != HCI_COMMAND_COMPLETE_EVENT) {
@@ -185,10 +163,12 @@
 
 bool VendorInterface::Initialize(
     InitializeCompleteCallback initialize_complete_cb,
-    PacketReadCallback packet_read_cb) {
+    PacketReadCallback event_cb, PacketReadCallback acl_cb,
+    PacketReadCallback sco_cb) {
   assert(!g_vendor_interface);
   g_vendor_interface = new VendorInterface();
-  return g_vendor_interface->Open(initialize_complete_cb, packet_read_cb);
+  return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
+                                  sco_cb);
 }
 
 void VendorInterface::Shutdown() {
@@ -201,9 +181,10 @@
 VendorInterface* VendorInterface::get() { return g_vendor_interface; }
 
 bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
-                           PacketReadCallback packet_read_cb) {
+                           PacketReadCallback event_cb,
+                           PacketReadCallback acl_cb,
+                           PacketReadCallback sco_cb) {
   initialize_complete_cb_ = initialize_complete_cb;
-  packet_read_cb_ = packet_read_cb;
 
   // Initialize vendor interface
 
@@ -241,28 +222,41 @@
   power_state = BT_VND_PWR_ON;
   lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
 
-  // Get the UART socket
+  // Get the UART socket(s)
 
   int fd_list[CH_MAX] = {0};
   int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
 
-  if (fd_count != 1) {
-    ALOGE("%s fd count %d != 1; we can't handle this currently...", __func__,
-          fd_count);
-    return false;
+  for (int i = 0; i < fd_count; i++) {
+    if (fd_list[i] == INVALID_FD) {
+      ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
+      return false;
+    }
   }
 
-  uart_fd_ = fd_list[0];
-  if (uart_fd_ == INVALID_FD) {
-    ALOGE("%s unable to determine UART fd", __func__);
-    return false;
+  event_cb_ = event_cb;
+  PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
+    HandleIncomingEvent(event);
+  };
+
+  if (fd_count == 1) {
+    hci::H4Protocol* h4_hci =
+        new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb);
+    fd_watcher_.WatchFdForNonBlockingReads(
+        fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
+    hci_ = h4_hci;
+  } else {
+    hci::MctProtocol* mct_hci =
+        new hci::MctProtocol(fd_list, intercept_events, acl_cb);
+    fd_watcher_.WatchFdForNonBlockingReads(
+        fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
+    if (fd_count >= CH_ACL_IN)
+      fd_watcher_.WatchFdForNonBlockingReads(
+          fd_list[CH_ACL_IN],
+          [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+    hci_ = mct_hci;
   }
 
-  ALOGI("%s UART fd: %d", __func__, uart_fd_);
-
-  fd_watcher_.WatchFdForNonBlockingReads(uart_fd_,
-                                         [this](int fd) { hci_packetizer_.OnDataReady(fd); });
-
   // Initially, the power management is off.
   lpm_wake_deasserted = true;
 
@@ -276,12 +270,16 @@
 void VendorInterface::Close() {
   fd_watcher_.StopWatchingFileDescriptors();
 
+  if (hci_ != nullptr) {
+    delete hci_;
+    hci_ = nullptr;
+  }
+
   if (lib_interface_ != nullptr) {
     bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;
     lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
 
     lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
-    uart_fd_ = INVALID_FD;
     int power_state = BT_VND_PWR_OFF;
     lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
   }
@@ -298,8 +296,6 @@
 }
 
 size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) {
-  if (uart_fd_ == INVALID_FD) return 0;
-
   recent_activity_flag = true;
 
   if (lpm_wake_deasserted == true) {
@@ -313,11 +309,7 @@
     ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
   }
 
-  int rv = write_safely(uart_fd_, &type, sizeof(type));
-  if (rv == sizeof(type))
-    rv = write_safely(uart_fd_, data, length);
-
-  return rv;
+  return hci_->Send(type, data, length);
 }
 
 void VendorInterface::OnFirmwareConfigured(uint8_t result) {
@@ -357,26 +349,18 @@
   recent_activity_flag = false;
 }
 
-void VendorInterface::OnPacketReady() {
-  VendorInterface::get()->HandleIncomingPacket();
-}
+void VendorInterface::HandleIncomingEvent(const hidl_vec<uint8_t>& hci_packet) {
+  if (internal_command.cb != nullptr &&
+      internal_command_event_match(hci_packet)) {
+    HC_BT_HDR* bt_hdr = WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet);
 
-void VendorInterface::HandleIncomingPacket() {
-  HciPacketType hci_packet_type = hci_packetizer_.GetPacketType();
-  hidl_vec<uint8_t> hci_packet = hci_packetizer_.GetPacket();
-        if (internal_command.cb != nullptr &&
-            hci_packet_type == HCI_PACKET_TYPE_EVENT &&
-            internal_command_event_match(hci_packet)) {
-          HC_BT_HDR* bt_hdr =
-              WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet);
-
-          // The callbacks can send new commands, so don't zero after calling.
-          tINT_CMD_CBACK saved_cb = internal_command.cb;
-          internal_command.cb = nullptr;
-          saved_cb(bt_hdr);
-        } else {
-          packet_read_cb_(hci_packet_type, hci_packet);
-        }
+    // The callbacks can send new commands, so don't zero after calling.
+    tINT_CMD_CBACK saved_cb = internal_command.cb;
+    internal_command.cb = nullptr;
+    saved_cb(bt_hdr);
+  } else {
+    event_cb_(hci_packet);
+  }
 }
 
 }  // namespace implementation
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index 8115640..a401ee6 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -20,7 +20,7 @@
 
 #include "async_fd_watcher.h"
 #include "bt_vendor_lib.h"
-#include "hci_packetizer.h"
+#include "hci_protocol.h"
 
 namespace android {
 namespace hardware {
@@ -30,15 +30,15 @@
 
 using ::android::hardware::hidl_vec;
 using InitializeCompleteCallback = std::function<void(bool success)>;
-using PacketReadCallback =
-    std::function<void(HciPacketType, const hidl_vec<uint8_t> &)>;
+using PacketReadCallback = std::function<void(const hidl_vec<uint8_t>&)>;
 
 class FirmwareStartupTimer;
 
 class VendorInterface {
  public:
   static bool Initialize(InitializeCompleteCallback initialize_complete_cb,
-                         PacketReadCallback packet_read_cb);
+                         PacketReadCallback event_cb, PacketReadCallback acl_cb,
+                         PacketReadCallback sco_cb);
   static void Shutdown();
   static VendorInterface *get();
 
@@ -46,27 +46,25 @@
 
   void OnFirmwareConfigured(uint8_t result);
 
-  static void OnPacketReady();
-
  private:
   virtual ~VendorInterface() = default;
 
   bool Open(InitializeCompleteCallback initialize_complete_cb,
-            PacketReadCallback packet_read_cb);
+            PacketReadCallback event_cb, PacketReadCallback acl_cb,
+            PacketReadCallback sco_cb);
   void Close();
 
   void OnTimeout();
 
-  void HandleIncomingPacket();
+  void HandleIncomingEvent(const hidl_vec<uint8_t>& hci_packet);
 
   void *lib_handle_;
   bt_vendor_interface_t *lib_interface_;
   async::AsyncFdWatcher fd_watcher_;
-  int uart_fd_;
-  PacketReadCallback packet_read_cb_;
   InitializeCompleteCallback initialize_complete_cb_;
+  hci::HciProtocol* hci_;
 
-  hci::HciPacketizer hci_packetizer_ {VendorInterface::OnPacketReady};
+  PacketReadCallback event_cb_;
 
   FirmwareStartupTimer *firmware_startup_timer_;
 };