universal7580: add device-specific bluetooth HIDL implementation
authorLukas0610 <mail@lukasberger.at>
Tue, 6 Nov 2018 14:17:59 +0000 (15:17 +0100)
committerJan Altensen <info@stricted.net>
Fri, 16 Aug 2019 21:18:39 +0000 (23:18 +0200)
Change-Id: I0a239cfd728fe3fcee4bbbb7f557becad666935a

Android.bp [new file with mode: 0644]
device-common.mk
hardware/Android.bp [new file with mode: 0644]
hardware/bluetooth/Android.bp [new file with mode: 0644]
hardware/bluetooth/OWNERS [new file with mode: 0644]
hardware/bluetooth/bluetooth_address.cc [new file with mode: 0644]
hardware/bluetooth/bluetooth_address.h [new file with mode: 0644]
hardware/bluetooth/bluetooth_hci.cc [new file with mode: 0644]
hardware/bluetooth/bluetooth_hci.h [new file with mode: 0644]
hardware/bluetooth/vendor_interface.cc [new file with mode: 0644]
hardware/bluetooth/vendor_interface.h [new file with mode: 0644]

diff --git a/Android.bp b/Android.bp
new file mode 100644 (file)
index 0000000..80a7ca9
--- /dev/null
@@ -0,0 +1,3 @@
+subdirs = [
+    "hardware",
+]
index 73fd8e8a333e5db6791d694d5a42028278db93e0..78aae93cb504b66c332b1d000195c7f333a33d09 100644 (file)
@@ -34,7 +34,7 @@ PRODUCT_COPY_FILES += \
 
 # Bluetooth
 PRODUCT_PACKAGES += \
-    android.hardware.bluetooth@1.0-impl \
+    android.hardware.bluetooth@1.0-impl.7580 \
     libbt-vendor
 
 # Camera
diff --git a/hardware/Android.bp b/hardware/Android.bp
new file mode 100644 (file)
index 0000000..0d0122b
--- /dev/null
@@ -0,0 +1,3 @@
+subdirs = [\r
+    "bluetooth",\r
+]\r
diff --git a/hardware/bluetooth/Android.bp b/hardware/bluetooth/Android.bp
new file mode 100644 (file)
index 0000000..feb2ce2
--- /dev/null
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2016 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.
+
+cc_library_shared {
+    name: "android.hardware.bluetooth@1.0-impl.7580",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "bluetooth_hci.cc",
+        "bluetooth_address.cc",
+        "vendor_interface.cc",
+    ],
+    shared_libs: [
+        "android.hardware.bluetooth@1.0",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth-async",
+        "android.hardware.bluetooth-hci",
+    ],
+}
+
diff --git a/hardware/bluetooth/OWNERS b/hardware/bluetooth/OWNERS
new file mode 100644 (file)
index 0000000..5df5bfe
--- /dev/null
@@ -0,0 +1,3 @@
+eisenbach@google.com
+mylesgw@google.com
+pavlin@google.com
diff --git a/hardware/bluetooth/bluetooth_address.cc b/hardware/bluetooth/bluetooth_address.cc
new file mode 100644 (file)
index 0000000..93a5469
--- /dev/null
@@ -0,0 +1,97 @@
+//
+// Copyright 2016 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 "bluetooth_address.h"
+
+#include <cutils/properties.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+void BluetoothAddress::bytes_to_string(const uint8_t* addr, char* addr_str) {
+  sprintf(addr_str, "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2],
+          addr[3], addr[4], addr[5]);
+}
+
+bool BluetoothAddress::string_to_bytes(const char* addr_str, uint8_t* addr) {
+  if (addr_str == NULL) return false;
+  if (strnlen(addr_str, kStringLength) != kStringLength) return false;
+  unsigned char trailing_char = '\0';
+
+  return (sscanf(addr_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx%1c",
+                 &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5],
+                 &trailing_char) == kBytes);
+}
+
+bool BluetoothAddress::get_local_address(uint8_t* local_addr) {
+  char property[PROPERTY_VALUE_MAX] = {0};
+
+  // Get local bdaddr storage path from a system property.
+  if (property_get(PROPERTY_BT_BDADDR_PATH, property, NULL)) {
+    ALOGD("%s: Trying %s", __func__, property);
+
+    int addr_fd = open(property, O_RDONLY);
+    if (addr_fd != -1) {
+      char address[kStringLength + 1] = {0};
+      int bytes_read = read(addr_fd, address, kStringLength);
+      if (bytes_read == -1) {
+        ALOGE("%s: Error reading address from %s: %s", __func__, property,
+              strerror(errno));
+      }
+      close(addr_fd);
+
+      // Null terminate the string.
+      address[kStringLength] = '\0';
+
+      // If the address is not all zeros, then use it.
+      const uint8_t zero_bdaddr[kBytes] = {0, 0, 0, 0, 0, 0};
+      if ((string_to_bytes(address, local_addr)) &&
+          (memcmp(local_addr, zero_bdaddr, kBytes) != 0)) {
+        ALOGD("%s: Got Factory BDA %s", __func__, address);
+        return true;
+      } else {
+        ALOGE("%s: Got Invalid BDA '%s' from %s", __func__, address, property);
+      }
+    }
+  }
+
+  // No BDADDR found in the file. Look for BDA in a factory property.
+  if (property_get(FACTORY_BDADDR_PROPERTY, property, NULL) &&
+      string_to_bytes(property, local_addr)) {
+    return true;
+  }
+
+  // No factory BDADDR found. Look for a previously stored BDA.
+  if (property_get(PERSIST_BDADDR_PROPERTY, property, NULL) &&
+      string_to_bytes(property, local_addr)) {
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/hardware/bluetooth/bluetooth_address.h b/hardware/bluetooth/bluetooth_address.h
new file mode 100644 (file)
index 0000000..94bf616
--- /dev/null
@@ -0,0 +1,61 @@
+//
+// Copyright 2016 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 <fcntl.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+// The property key stores the storage location of Bluetooth Device Address
+static constexpr char PROPERTY_BT_BDADDR_PATH[] = "ro.bt.bdaddr_path";
+
+// Check for a legacy address stored as a property.
+static constexpr char PERSIST_BDADDR_PROPERTY[] =
+    "persist.service.bdroid.bdaddr";
+
+// If there is no valid bdaddr available from PROPERTY_BT_BDADDR_PATH and there
+// is no available persistent bdaddr available from PERSIST_BDADDR_PROPERTY,
+// use a factory set address.
+static constexpr char FACTORY_BDADDR_PROPERTY[] = "ro.boot.btmacaddr";
+
+// Encapsulate handling for Bluetooth Addresses:
+class BluetoothAddress {
+ public:
+  // Conversion constants
+  static constexpr size_t kStringLength = sizeof("XX:XX:XX:XX:XX:XX") - 1;
+  static constexpr size_t kBytes = (kStringLength + 1) / 3;
+
+  static void bytes_to_string(const uint8_t* addr, char* addr_str);
+
+  static bool string_to_bytes(const char* addr_str, uint8_t* addr);
+
+  static bool get_local_address(uint8_t* addr);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/hardware/bluetooth/bluetooth_hci.cc b/hardware/bluetooth/bluetooth_hci.cc
new file mode 100644 (file)
index 0000000..e14e3d7
--- /dev/null
@@ -0,0 +1,145 @@
+//
+// Copyright 2016 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 "android.hardware.bluetooth@1.0-impl"
+#include "bluetooth_hci.h"
+
+#include <log/log.h>
+
+#include "vendor_interface.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+static const uint8_t HCI_DATA_TYPE_COMMAND = 1;
+static const uint8_t HCI_DATA_TYPE_ACL = 2;
+static const uint8_t HCI_DATA_TYPE_SCO = 3;
+
+class BluetoothDeathRecipient : public hidl_death_recipient {
+ public:
+  BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
+
+  virtual void serviceDied(
+      uint64_t /*cookie*/,
+      const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+    ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
+    has_died_ = true;
+    mHci->close();
+  }
+  sp<IBluetoothHci> mHci;
+  bool getHasDied() const { return has_died_; }
+  void setHasDied(bool has_died) { has_died_ = has_died; }
+
+ private:
+  bool has_died_;
+};
+
+BluetoothHci::BluetoothHci()
+    : death_recipient_(new BluetoothDeathRecipient(this)) {}
+
+Return<void> BluetoothHci::initialize(
+    const ::android::sp<IBluetoothHciCallbacks>& cb) {
+  ALOGI("BluetoothHci::initialize()");
+  if (cb == nullptr) {
+    ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
+    return Void();
+  }
+
+  death_recipient_->setHasDied(false);
+  cb->linkToDeath(death_recipient_, 0);
+
+  bool rc = VendorInterface::Initialize(
+      [cb](bool status) {
+        auto hidl_status = cb->initializationComplete(
+            status ? Status::SUCCESS : Status::INITIALIZATION_ERROR);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call initializationComplete()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->hciEventReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call hciEventReceived()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->aclDataReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call aclDataReceived()");
+        }
+      },
+      [cb](const hidl_vec<uint8_t>& packet) {
+        auto hidl_status = cb->scoDataReceived(packet);
+        if (!hidl_status.isOk()) {
+          ALOGE("VendorInterface -> Unable to call scoDataReceived()");
+        }
+      });
+  if (!rc) {
+    auto hidl_status = cb->initializationComplete(Status::INITIALIZATION_ERROR);
+    if (!hidl_status.isOk()) {
+      ALOGE("VendorInterface -> Unable to call initializationComplete(ERR)");
+    }
+  }
+
+  unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
+    if (death_recipient->getHasDied())
+      ALOGI("Skipping unlink call, service died.");
+    else
+      cb->unlinkToDeath(death_recipient);
+  };
+
+  return Void();
+}
+
+Return<void> BluetoothHci::close() {
+  ALOGI("BluetoothHci::close()");
+  unlink_cb_(death_recipient_);
+  VendorInterface::Shutdown();
+  return Void();
+}
+
+Return<void> BluetoothHci::sendHciCommand(const hidl_vec<uint8_t>& command) {
+  sendDataToController(HCI_DATA_TYPE_COMMAND, command);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& data) {
+  sendDataToController(HCI_DATA_TYPE_ACL, data);
+  return Void();
+}
+
+Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& data) {
+  sendDataToController(HCI_DATA_TYPE_SCO, data);
+  return Void();
+}
+
+void BluetoothHci::sendDataToController(const uint8_t type,
+                                        const hidl_vec<uint8_t>& data) {
+  VendorInterface::get()->Send(type, data.data(), data.size());
+}
+
+IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* /* name */) {
+  return new BluetoothHci();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/hardware/bluetooth/bluetooth_hci.h b/hardware/bluetooth/bluetooth_hci.h
new file mode 100644 (file)
index 0000000..e2797b1
--- /dev/null
@@ -0,0 +1,61 @@
+//
+// Copyright 2016 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.
+//
+
+#ifndef HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_
+#define HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_
+
+#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include <functional>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::hidl_vec;
+
+class BluetoothDeathRecipient;
+
+class BluetoothHci : public IBluetoothHci {
+ public:
+  BluetoothHci();
+  Return<void> initialize(
+      const ::android::sp<IBluetoothHciCallbacks>& cb) override;
+  Return<void> sendHciCommand(const hidl_vec<uint8_t>& packet) override;
+  Return<void> sendAclData(const hidl_vec<uint8_t>& data) override;
+  Return<void> sendScoData(const hidl_vec<uint8_t>& data) override;
+  Return<void> close() override;
+
+ private:
+  void sendDataToController(const uint8_t type, const hidl_vec<uint8_t>& data);
+  ::android::sp<BluetoothDeathRecipient> death_recipient_;
+  std::function<void(sp<BluetoothDeathRecipient>&)> unlink_cb_;
+};
+
+extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_
diff --git a/hardware/bluetooth/vendor_interface.cc b/hardware/bluetooth/vendor_interface.cc
new file mode 100644 (file)
index 0000000..a8f5bb4
--- /dev/null
@@ -0,0 +1,385 @@
+//
+// Copyright 2016 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 "vendor_interface.h"
+
+#define LOG_TAG "android.hardware.bluetooth@1.0-impl"
+#include <cutils/properties.h>
+#include <utils/Log.h>
+
+#include <dlfcn.h>
+#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 =
+    "BLUETOOTH_VENDOR_LIB_INTERFACE";
+
+static const int INVALID_FD = -1;
+
+namespace {
+
+using android::hardware::bluetooth::V1_0::implementation::VendorInterface;
+using android::hardware::hidl_vec;
+
+struct {
+  tINT_CMD_CBACK cb;
+  uint16_t opcode;
+} internal_command;
+
+// True when LPM is not enabled yet or wake is not asserted.
+bool lpm_wake_deasserted;
+uint32_t lpm_timeout_ms;
+bool recent_activity_flag;
+
+VendorInterface* g_vendor_interface = nullptr;
+std::mutex wakeup_mutex_;
+
+HC_BT_HDR* WrapPacketAndCopy(uint16_t event, const hidl_vec<uint8_t>& data) {
+  size_t packet_size = data.size() + sizeof(HC_BT_HDR);
+  HC_BT_HDR* packet = reinterpret_cast<HC_BT_HDR*>(new uint8_t[packet_size]);
+  packet->offset = 0;
+  packet->len = data.size();
+  packet->layer_specific = 0;
+  packet->event = event;
+  // TODO(eisenbach): Avoid copy here; if BT_HDR->data can be ensured to
+  // be the only way the data is accessed, a pointer could be passed here...
+  memcpy(packet->data, data.data(), data.size());
+  return packet;
+}
+
+bool internal_command_event_match(const hidl_vec<uint8_t>& packet) {
+  uint8_t event_code = packet[0];
+  if (event_code != HCI_COMMAND_COMPLETE_EVENT) {
+    ALOGE("%s: Unhandled event type %02X", __func__, event_code);
+    return false;
+  }
+
+  size_t opcode_offset = HCI_EVENT_PREAMBLE_SIZE + 1;  // Skip num packets.
+
+  uint16_t opcode = packet[opcode_offset] | (packet[opcode_offset + 1] << 8);
+
+  ALOGV("%s internal_command.opcode = %04X opcode = %04x", __func__,
+        internal_command.opcode, opcode);
+  return opcode == internal_command.opcode;
+}
+
+uint8_t transmit_cb(uint16_t opcode, void* buffer, tINT_CMD_CBACK callback) {
+  ALOGV("%s opcode: 0x%04x, ptr: %p, cb: %p", __func__, opcode, buffer,
+        callback);
+  internal_command.cb = callback;
+  internal_command.opcode = opcode;
+  uint8_t type = HCI_PACKET_TYPE_COMMAND;
+  HC_BT_HDR* bt_hdr = reinterpret_cast<HC_BT_HDR*>(buffer);
+  VendorInterface::get()->Send(type, bt_hdr->data, bt_hdr->len);
+  delete[] reinterpret_cast<uint8_t*>(buffer);
+  return true;
+}
+
+void firmware_config_cb(bt_vendor_op_result_t result) {
+  ALOGV("%s result: %d", __func__, result);
+  VendorInterface::get()->OnFirmwareConfigured(result);
+}
+
+void sco_config_cb(bt_vendor_op_result_t result) {
+  ALOGD("%s result: %d", __func__, result);
+}
+
+void low_power_mode_cb(bt_vendor_op_result_t result) {
+  ALOGD("%s result: %d", __func__, result);
+}
+
+void sco_audiostate_cb(bt_vendor_op_result_t result) {
+  ALOGD("%s result: %d", __func__, result);
+}
+
+void* buffer_alloc_cb(int size) {
+  void* p = new uint8_t[size];
+  ALOGV("%s pts: %p, size: %d", __func__, p, size);
+  return p;
+}
+
+void buffer_free_cb(void* buffer) {
+  ALOGV("%s ptr: %p", __func__, buffer);
+  delete[] reinterpret_cast<uint8_t*>(buffer);
+}
+
+void epilog_cb(bt_vendor_op_result_t result) {
+  ALOGD("%s result: %d", __func__, result);
+}
+
+void a2dp_offload_cb(bt_vendor_op_result_t result, bt_vendor_opcode_t op,
+                     uint8_t av_handle) {
+  ALOGD("%s result: %d, op: %d, handle: %d", __func__, result, op, av_handle);
+}
+
+const bt_vendor_callbacks_t lib_callbacks = {
+    sizeof(lib_callbacks), firmware_config_cb, sco_config_cb,
+    low_power_mode_cb,     sco_audiostate_cb,  buffer_alloc_cb,
+    buffer_free_cb,        transmit_cb,        epilog_cb,
+    a2dp_offload_cb};
+
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+class FirmwareStartupTimer {
+ public:
+  FirmwareStartupTimer() : start_time_(std::chrono::steady_clock::now()) {}
+
+  ~FirmwareStartupTimer() {
+    std::chrono::duration<double> duration =
+        std::chrono::steady_clock::now() - start_time_;
+    double s = duration.count();
+    if (s == 0) return;
+    ALOGI("Firmware configured in %.3fs", s);
+  }
+
+ private:
+  std::chrono::steady_clock::time_point start_time_;
+};
+
+bool VendorInterface::Initialize(
+    InitializeCompleteCallback initialize_complete_cb,
+    PacketReadCallback event_cb, PacketReadCallback acl_cb,
+    PacketReadCallback sco_cb) {
+  if (g_vendor_interface) {
+    ALOGE("%s: No previous Shutdown()?", __func__);
+    return false;
+  }
+  g_vendor_interface = new VendorInterface();
+  return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
+                                  sco_cb);
+}
+
+void VendorInterface::Shutdown() {
+  LOG_ALWAYS_FATAL_IF(!g_vendor_interface, "%s: No Vendor interface!",
+                      __func__);
+  g_vendor_interface->Close();
+  delete g_vendor_interface;
+  g_vendor_interface = nullptr;
+}
+
+VendorInterface* VendorInterface::get() { return g_vendor_interface; }
+
+bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
+                           PacketReadCallback event_cb,
+                           PacketReadCallback acl_cb,
+                           PacketReadCallback sco_cb) {
+  initialize_complete_cb_ = initialize_complete_cb;
+
+  // Initialize vendor interface
+
+  lib_handle_ = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
+  if (!lib_handle_) {
+    ALOGE("%s unable to open %s (%s)", __func__, VENDOR_LIBRARY_NAME,
+          dlerror());
+    return false;
+  }
+
+  lib_interface_ = reinterpret_cast<bt_vendor_interface_t*>(
+      dlsym(lib_handle_, VENDOR_LIBRARY_SYMBOL_NAME));
+  if (!lib_interface_) {
+    ALOGE("%s unable to find symbol %s in %s (%s)", __func__,
+          VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
+    return false;
+  }
+
+  // Get the local BD address
+
+  uint8_t local_bda[BluetoothAddress::kBytes];
+  if (!BluetoothAddress::get_local_address(local_bda)) {
+    LOG_ALWAYS_FATAL("%s: No Bluetooth Address!", __func__);
+  }
+  int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda);
+  if (status) {
+    ALOGE("%s unable to initialize vendor library: %d", __func__, status);
+    return false;
+  }
+
+  ALOGD("%s vendor library loaded", __func__);
+
+  // Power on the controller
+
+  int power_state = BT_VND_PWR_ON;
+  lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
+
+  // 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 || fd_count > CH_MAX - 1) {
+    ALOGE("%s: fd_count %d is invalid!", __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;
+    }
+  }
+
+  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); });
+    fd_watcher_.WatchFdForNonBlockingReads(
+        fd_list[CH_ACL_IN],
+        [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+    hci_ = mct_hci;
+  }
+
+  // Initially, the power management is off.
+  lpm_wake_deasserted = true;
+
+  // Start configuring the firmware
+  firmware_startup_timer_ = new FirmwareStartupTimer();
+  lib_interface_->op(BT_VND_OP_FW_CFG, nullptr);
+
+  return true;
+}
+
+void VendorInterface::Close() {
+  // These callbacks may send HCI events (vendor-dependent), so make sure to
+  // StopWatching the file descriptor after this.
+  if (lib_interface_ != nullptr) {
+    bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;
+    lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
+  }
+
+  fd_watcher_.StopWatchingFileDescriptors();
+
+  if (hci_ != nullptr) {
+    delete hci_;
+    hci_ = nullptr;
+  }
+
+  if (lib_interface_ != nullptr) {
+    lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
+
+    int power_state = BT_VND_PWR_OFF;
+    lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
+
+    lib_interface_->cleanup();
+  }
+
+  if (lib_handle_ != nullptr) {
+    dlclose(lib_handle_);
+    lib_handle_ = nullptr;
+  }
+
+  if (firmware_startup_timer_ != nullptr) {
+    delete firmware_startup_timer_;
+    firmware_startup_timer_ = nullptr;
+  }
+}
+
+size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) {
+  std::unique_lock<std::mutex> lock(wakeup_mutex_);
+  recent_activity_flag = true;
+
+  if (lpm_wake_deasserted == true) {
+    // Restart the timer.
+    fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
+                                 [this]() { OnTimeout(); });
+    // Assert wake.
+    lpm_wake_deasserted = false;
+    bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_ASSERT;
+    lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
+    ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
+  }
+
+  return hci_->Send(type, data, length);
+}
+
+void VendorInterface::OnFirmwareConfigured(uint8_t result) {
+  ALOGD("%s result: %d", __func__, result);
+
+  if (firmware_startup_timer_ != nullptr) {
+    delete firmware_startup_timer_;
+    firmware_startup_timer_ = nullptr;
+  }
+
+  if (initialize_complete_cb_ != nullptr) {
+    initialize_complete_cb_(result == 0);
+    initialize_complete_cb_ = nullptr;
+  }
+
+  lib_interface_->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &lpm_timeout_ms);
+  ALOGI("%s: lpm_timeout_ms %d", __func__, lpm_timeout_ms);
+
+  bt_vendor_lpm_mode_t mode = BT_VND_LPM_ENABLE;
+  lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
+
+  ALOGD("%s Calling StartLowPowerWatchdog()", __func__);
+  fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
+                               [this]() { OnTimeout(); });
+}
+
+void VendorInterface::OnTimeout() {
+  ALOGV("%s", __func__);
+  std::unique_lock<std::mutex> lock(wakeup_mutex_);
+  if (recent_activity_flag == false) {
+    lpm_wake_deasserted = true;
+    bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_DEASSERT;
+    lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
+    fd_watcher_.ConfigureTimeout(std::chrono::seconds(0), []() {
+      ALOGE("Zero timeout! Should never happen.");
+    });
+  }
+  recent_activity_flag = false;
+}
+
+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);
+
+    // 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
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/hardware/bluetooth/vendor_interface.h b/hardware/bluetooth/vendor_interface.h
new file mode 100644 (file)
index 0000000..a401ee6
--- /dev/null
@@ -0,0 +1,76 @@
+//
+// Copyright 2016 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_protocol.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using InitializeCompleteCallback = std::function<void(bool success)>;
+using PacketReadCallback = std::function<void(const hidl_vec<uint8_t>&)>;
+
+class FirmwareStartupTimer;
+
+class VendorInterface {
+ public:
+  static bool Initialize(InitializeCompleteCallback initialize_complete_cb,
+                         PacketReadCallback event_cb, PacketReadCallback acl_cb,
+                         PacketReadCallback sco_cb);
+  static void Shutdown();
+  static VendorInterface *get();
+
+  size_t Send(uint8_t type, const uint8_t *data, size_t length);
+
+  void OnFirmwareConfigured(uint8_t result);
+
+ private:
+  virtual ~VendorInterface() = default;
+
+  bool Open(InitializeCompleteCallback initialize_complete_cb,
+            PacketReadCallback event_cb, PacketReadCallback acl_cb,
+            PacketReadCallback sco_cb);
+  void Close();
+
+  void OnTimeout();
+
+  void HandleIncomingEvent(const hidl_vec<uint8_t>& hci_packet);
+
+  void *lib_handle_;
+  bt_vendor_interface_t *lib_interface_;
+  async::AsyncFdWatcher fd_watcher_;
+  InitializeCompleteCallback initialize_complete_cb_;
+  hci::HciProtocol* hci_;
+
+  PacketReadCallback event_cb_;
+
+  FirmwareStartupTimer *firmware_startup_timer_;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android