Merge "Initial Target-side VTS tests for Short Message Service(SMS) Radio Hal Apis"
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_;
 };
diff --git a/tests/Android.bp b/tests/Android.bp
index 41043d9..9bb4bf5 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -15,6 +15,7 @@
     "memory/1.0",
     "memory/1.0/default",
     "msgq/1.0",
+    "msgq/1.0/default",
     "pointer/1.0",
     "pointer/1.0/default",
     "pointer/1.0/default/lib",
diff --git a/tests/msgq/1.0/default/Android.bp b/tests/msgq/1.0/default/Android.bp
new file mode 100644
index 0000000..b53fcd3
--- /dev/null
+++ b/tests/msgq/1.0/default/Android.bp
@@ -0,0 +1,19 @@
+cc_library_shared {
+    name: "android.hardware.tests.msgq@1.0-impl",
+    relative_install_path: "hw",
+    proprietary: true,
+    srcs: [
+        "TestMsgQ.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "android.hardware.tests.msgq@1.0",
+        "android.hidl.base@1.0",
+    ],
+}
diff --git a/tests/msgq/1.0/default/TestMsgQ.cpp b/tests/msgq/1.0/default/TestMsgQ.cpp
new file mode 100644
index 0000000..7cc4f5b
--- /dev/null
+++ b/tests/msgq/1.0/default/TestMsgQ.cpp
@@ -0,0 +1,135 @@
+#include "TestMsgQ.h"
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace msgq {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::tests::msgq::V1_0::ITestMsgQ follow.
+Return<void> TestMsgQ::configureFmqSyncReadWrite(configureFmqSyncReadWrite_cb _hidl_cb) {
+    static constexpr size_t kNumElementsInQueue = 1024;
+    mFmqSynchronized.reset(new (std::nothrow) MessageQueueSync(
+            kNumElementsInQueue, true /* configureEventFlagWord */));
+    if ((mFmqSynchronized == nullptr) || (mFmqSynchronized->isValid() == false)) {
+        _hidl_cb(false /* ret */, MessageQueueSync::Descriptor());
+    } else {
+        /*
+         * Initialize the EventFlag word with bit FMQ_NOT_FULL.
+         */
+        auto evFlagWordPtr = mFmqSynchronized->getEventFlagWord();
+        if (evFlagWordPtr != nullptr) {
+            std::atomic_init(evFlagWordPtr,
+                             static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL));
+        }
+        _hidl_cb(true /* ret */, *mFmqSynchronized->getDesc());
+    }
+    return Void();
+}
+
+Return<void> TestMsgQ::getFmqUnsyncWrite(bool configureFmq, getFmqUnsyncWrite_cb _hidl_cb) {
+    if (configureFmq) {
+        static constexpr size_t kNumElementsInQueue = 1024;
+        mFmqUnsynchronized.reset(new (std::nothrow) MessageQueueUnsync(kNumElementsInQueue));
+    }
+    if ((mFmqUnsynchronized == nullptr) ||
+        (mFmqUnsynchronized->isValid() == false)) {
+        _hidl_cb(false /* ret */, MessageQueueUnsync::Descriptor());
+    } else {
+        _hidl_cb(true /* ret */, *mFmqUnsynchronized->getDesc());
+    }
+    return Void();
+}
+
+Return<bool> TestMsgQ::requestWriteFmqSync(int32_t count) {
+    std::vector<uint16_t> data(count);
+    for (int i = 0; i < count; i++) {
+        data[i] = i;
+    }
+    bool result = mFmqSynchronized->write(&data[0], count);
+    return result;
+}
+
+Return<bool> TestMsgQ::requestReadFmqSync(int32_t count) {
+    std::vector<uint16_t> data(count);
+    bool result = mFmqSynchronized->read(&data[0], count)
+            && verifyData(&data[0], count);
+    return result;
+}
+
+Return<bool> TestMsgQ::requestWriteFmqUnsync(int32_t count) {
+    std::vector<uint16_t> data(count);
+    for (int i = 0; i < count; i++) {
+        data[i] = i;
+    }
+    bool result = mFmqUnsynchronized->write(&data[0], count);
+    return result;
+}
+
+Return<bool> TestMsgQ::requestReadFmqUnsync(int32_t count) {
+    std::vector<uint16_t> data(count);
+    bool result =
+            mFmqUnsynchronized->read(&data[0], count) && verifyData(&data[0], count);
+    return result;
+}
+
+Return<void> TestMsgQ::requestBlockingRead(int32_t count) {
+    std::vector<uint16_t> data(count);
+    bool result = mFmqSynchronized->readBlocking(
+            &data[0],
+            count,
+            static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+            static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+            5000000000 /* timeOutNanos */);
+
+    if (result == false) {
+        ALOGE("Blocking read fails");
+    }
+    return Void();
+}
+
+Return<void> TestMsgQ::requestBlockingReadDefaultEventFlagBits(int32_t count) {
+    std::vector<uint16_t> data(count);
+    bool result = mFmqSynchronized->readBlocking(
+            &data[0],
+            count);
+
+    if (result == false) {
+        ALOGE("Blocking read fails");
+    }
+
+    return Void();
+}
+
+Return<void> TestMsgQ::requestBlockingReadRepeat(int32_t count, int32_t numIter) {
+    std::vector<uint16_t> data(count);
+    for (int i = 0; i < numIter; i++) {
+        bool result = mFmqSynchronized->readBlocking(
+                &data[0],
+                count,
+                static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL),
+                static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY),
+                5000000000 /* timeOutNanos */);
+
+        if (result == false) {
+            ALOGE("Blocking read fails");
+            break;
+        }
+    }
+    return Void();
+}
+
+
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+
+ITestMsgQ* HIDL_FETCH_ITestMsgQ(const char* /* name */) {
+    return new TestMsgQ();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace msgq
+}  // namespace tests
+}  // namespace hardware
+}  // namespace android
diff --git a/tests/msgq/1.0/default/TestMsgQ.h b/tests/msgq/1.0/default/TestMsgQ.h
new file mode 100644
index 0000000..760d931
--- /dev/null
+++ b/tests/msgq/1.0/default/TestMsgQ.h
@@ -0,0 +1,77 @@
+#ifndef ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
+#define ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
+
+#include <android/hardware/tests/msgq/1.0/ITestMsgQ.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <fmq/MessageQueue.h>
+#include <fmq/EventFlag.h>
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace msgq {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tests::msgq::V1_0::ITestMsgQ;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::kUnsynchronizedWrite;
+using android::hardware::MQDescriptorSync;
+using android::hardware::MQDescriptorUnsync;
+
+using android::hardware::MessageQueue;
+
+struct TestMsgQ : public ITestMsgQ {
+    typedef MessageQueue<uint16_t, kSynchronizedReadWrite> MessageQueueSync;
+    typedef MessageQueue<uint16_t, kUnsynchronizedWrite> MessageQueueUnsync;
+
+    TestMsgQ() : mFmqSynchronized(nullptr), mFmqUnsynchronized(nullptr) {}
+
+    // Methods from ::android::hardware::tests::msgq::V1_0::ITestMsgQ follow.
+    Return<void> configureFmqSyncReadWrite(configureFmqSyncReadWrite_cb _hidl_cb) override;
+    Return<void> getFmqUnsyncWrite(bool configureFmq, getFmqUnsyncWrite_cb _hidl_cb) override;
+    Return<bool> requestWriteFmqSync(int32_t count) override;
+    Return<bool> requestReadFmqSync(int32_t count) override;
+    Return<bool> requestWriteFmqUnsync(int32_t count) override;
+    Return<bool> requestReadFmqUnsync(int32_t count) override;
+    Return<void> requestBlockingRead(int32_t count) override;
+    Return<void> requestBlockingReadDefaultEventFlagBits(int32_t count) override;
+    Return<void> requestBlockingReadRepeat(int32_t count, int32_t numIter) override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+private:
+    std::unique_ptr<MessageQueueSync> mFmqSynchronized;
+    std::unique_ptr<MessageQueueUnsync> mFmqUnsynchronized;
+
+    /*
+     * Utility function to verify data read from the fast message queue.
+     */
+    bool verifyData(uint16_t* data, int count) {
+        for (int i = 0; i < count; i++) {
+            if (data[i] != i) return false;
+        }
+        return true;
+    }
+};
+
+extern "C" ITestMsgQ* HIDL_FETCH_ITestMsgQ(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace msgq
+}  // namespace tests
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.0/default/hidl_struct_util.cpp
index 485ae7e..5917efc 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.0/default/hidl_struct_util.cpp
@@ -354,7 +354,10 @@
         hidl_scan_params.buckets[bucket_idx];
     legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
         legacy_scan_params->buckets[bucket_idx];
-    legacy_bucket_spec.bucket = bucket_idx;
+    if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
+      return false;
+    }
+    legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
     legacy_bucket_spec.band =
         convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
     legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
diff --git a/wifi/1.0/default/wifi.cpp b/wifi/1.0/default/wifi.cpp
index 3d482b4..b48844e 100644
--- a/wifi/1.0/default/wifi.cpp
+++ b/wifi/1.0/default/wifi.cpp
@@ -115,6 +115,7 @@
       }
     }
   }
+  LOG(INFO) << "Wifi HAL started";
   return wifi_status;
 }
 
@@ -139,6 +140,13 @@
       }
     }
   }
+  // Clear the chip object and its child objects since the HAL is now
+  // stopped.
+  if (chip_.get()) {
+    chip_->invalidate();
+    chip_.clear();
+  }
+  LOG(INFO) << "Wifi HAL stopped";
   return wifi_status;
 }
 
@@ -172,13 +180,7 @@
 
 WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController() {
   run_state_ = RunState::STOPPING;
-  const auto on_complete_callback_ = [&]() {
-    if (chip_.get()) {
-      chip_->invalidate();
-    }
-    chip_.clear();
-    run_state_ = RunState::STOPPED;
-  };
+  const auto on_complete_callback_ = [&]() { run_state_ = RunState::STOPPED; };
   legacy_hal::wifi_error legacy_status =
       legacy_hal_->stop(on_complete_callback_);
   if (legacy_status != legacy_hal::WIFI_SUCCESS) {
diff --git a/wifi/1.0/types.hal b/wifi/1.0/types.hal
index 83e6660..d90d5be 100644
--- a/wifi/1.0/types.hal
+++ b/wifi/1.0/types.hal
@@ -320,6 +320,11 @@
  */
 struct StaBackgroundScanBucketParameters {
   /**
+   * Bucket index. This index is used to report results in
+   * |StaScanData.bucketsScanned|.
+   */
+  uint32_t bucketIdx;
+  /**
    * Bands to scan or |BAND_UNSPECIFIED| if frequencies list must be used
    * instead.
    */
diff --git a/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal
index dd1d1c4..2223022 100644
--- a/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal
+++ b/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.hal
@@ -278,8 +278,10 @@
    *        reject.
    * @param statusCode 802.11 code to indicate the reject reason.
    *        Refer to section 8.4.1.9 of IEEE 802.11 spec.
+   * @param timedOut Whether failure is due to timeout rather
+   *        than explicit rejection response from the AP.
    */
-  oneway onAssociationRejected(Bssid bssid, uint32_t statusCode);
+  oneway onAssociationRejected(Bssid bssid, uint32_t statusCode, bool timedOut);
 
   /**
    * Used to indicate the timeout of authentication to an AP.
diff --git a/wifi/supplicant/1.0/ISupplicantStaNetwork.hal b/wifi/supplicant/1.0/ISupplicantStaNetwork.hal
index 37e8d3f..7d5159a 100644
--- a/wifi/supplicant/1.0/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.0/ISupplicantStaNetwork.hal
@@ -277,6 +277,20 @@
   setPskPassphrase(string psk) generates (SupplicantStatus status);
 
   /**
+   * Set raw psk for WPA_PSK network.
+   *
+   * @param psk value to set as specified in IEEE 802.11i-2004 standard.
+   *        This is the calculated using 'wpa_passphrase <ssid> [passphrase]'
+   * @return status Status of the operation.
+   *         Possible status codes:
+   *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+   *         |SupplicantStatusCode.SUCCESS|,
+   *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+   *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+   */
+  setPsk(uint8_t[32] psk) generates (SupplicantStatus status);
+
+  /**
    * Set WEP key for WEP network.
    *
    * @param keyIdx Index of wep key to set.
@@ -662,6 +676,8 @@
 
   /**
    * Get passphrase for WPA_PSK network.
+   * Must return a failure if network has no passphrase set (use |getPsk| if
+   * network was configured with raw psk instead).
    *
    * @return status Status of the operation.
    *         Possible status codes:
@@ -672,6 +688,19 @@
   getPskPassphrase() generates (SupplicantStatus status, string psk);
 
   /**
+   * Get raw psk for WPA_PSK network.
+   *
+   * @return status Status of the operation.
+   *         Possible status codes:
+   *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+   *         |SupplicantStatusCode.SUCCESS|,
+   *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+   *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+   * @param psk value set.
+   */
+  getPsk() generates (SupplicantStatus status, uint8_t[32] psk);
+
+  /**
    * Get WEP key for WEP network.
    *
    * @param keyIdx Index of wep key to be fetched.