OSDN Git Service

Generic Bluetooth HAL for standard Linux hci interface
authorSatish Patel <satish.patel@linaro.org>
Wed, 28 Jun 2017 01:35:19 +0000 (18:35 -0700)
committerMyles Watson <mylesgw@google.com>
Wed, 5 Jul 2017 21:03:07 +0000 (21:03 +0000)
This acts as common interface for bluetooth devices (including
USB ones) using the standard Linux bluetooth hci interface.

Much of this code is pulled from hardware/interface/bluetooth
and system/bt/vendor_libs/linux.

Original code used from "system/bt/vendor_libs/linux" was from:
Samuel Ortiz <sameo@linux.intel.com>
Cristian Iorga <cristian.iorga@intel.com>
Pavlin Radoslavov <pavlin@google.com>
Jakub Pawlowski <jpawlowski@google.com>
Myles Watson <mylesgw@google.com>

Orginal code taken from hardware/interface/bluetooth was
contributed by:
Myles Watson <mylesgw@google.com>
Zach Johnson <zachoverflow@google.com>
Treehugger Robot <treehugger-gerrit@google.com>

Tested:
Hikey + on board bluetooth and Hikey + USB bluetooth dongle

Change-Id: I03da10cadfae6ffb298cfccc98e3337ab7db1967
Signed-off-by: Satish Patel <satish.patel@linaro.org>
[jstultz: Migrated code back to system/bt/vendor_libs/linux/.
 Included required sepolicy changes. Reworded and simplified
 commit message. ]
Signed-off-by: John Stultz <john.stultz@linaro.org>
18 files changed:
vendor_libs/Android.bp
vendor_libs/linux/Android.bp [new file with mode: 0644]
vendor_libs/linux/Android.mk [deleted file]
vendor_libs/linux/bt_vendor_linux.cc [deleted file]
vendor_libs/linux/interface/Android.bp [new file with mode: 0644]
vendor_libs/linux/interface/android.hardware.bluetooth@1.0-service.btlinux.rc [new file with mode: 0644]
vendor_libs/linux/interface/async_fd_watcher.cc [new file with mode: 0644]
vendor_libs/linux/interface/async_fd_watcher.h [new file with mode: 0644]
vendor_libs/linux/interface/bluetooth_hci.cc [new file with mode: 0644]
vendor_libs/linux/interface/bluetooth_hci.h [new file with mode: 0644]
vendor_libs/linux/interface/h4_protocol.cc [new file with mode: 0644]
vendor_libs/linux/interface/h4_protocol.h [new file with mode: 0644]
vendor_libs/linux/interface/hci_internals.h [new file with mode: 0644]
vendor_libs/linux/interface/hci_packetizer.cc [new file with mode: 0644]
vendor_libs/linux/interface/hci_packetizer.h [new file with mode: 0644]
vendor_libs/linux/interface/service.cc [new file with mode: 0644]
vendor_libs/linux/sepolicy/file_contexts [new file with mode: 0644]
vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te [new file with mode: 0644]

index 07dde0f..a509209 100644 (file)
@@ -1,3 +1,4 @@
 subdirs = [
     "test_vendor_lib",
+    "linux",
 ]
diff --git a/vendor_libs/linux/Android.bp b/vendor_libs/linux/Android.bp
new file mode 100644 (file)
index 0000000..058140e
--- /dev/null
@@ -0,0 +1,3 @@
+subdirs = [
+    "interface",
+]
diff --git a/vendor_libs/linux/Android.mk b/vendor_libs/linux/Android.mk
deleted file mode 100644 (file)
index 30a7389..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-#  Copyright (C) 2015 Intel Corporation
-#
-#  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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-ifeq ($(BOARD_HAVE_BLUETOOTH_LINUX), true)
-
-# libbt-vendor shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_CPP_EXTENSION := .cc
-
-LOCAL_SRC_FILES := \
-        bt_vendor_linux.cc
-
-LOCAL_C_INCLUDES := \
-        $(LOCAL_PATH)/../../
-
-LOCAL_SHARED_LIBRARIES := \
-        liblog \
-        libcutils
-
-LOCAL_STATIC_LIBRARIES := libosi
-
-LOCAL_MODULE := libbt-vendor
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += $(test-vendor_CFLAGS)
-LOCAL_CONLYFLAGS += $(test-vendor_CONLYFLAGS)
-
-include $(BUILD_SHARED_LIBRARY)
-
-endif  # BOARD_HAVE_BLUETOOTH_LINUX
diff --git a/vendor_libs/linux/bt_vendor_linux.cc b/vendor_libs/linux/bt_vendor_linux.cc
deleted file mode 100644 (file)
index 5270eab..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-/**********************************************************************
- *
- *  Copyright (C) 2015 Intel Corporation
- *
- *  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_vendor"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include "hci/include/bt_vendor_lib.h"
-#include "osi/include/compat.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "osi/include/properties.h"
-
-#define BTPROTO_HCI 1
-#define HCI_CHANNEL_USER 1
-#define HCI_CHANNEL_CONTROL 3
-#define HCI_DEV_NONE 0xffff
-
-#define RFKILL_TYPE_BLUETOOTH 2
-#define RFKILL_OP_CHANGE_ALL 3
-
-#define MGMT_OP_INDEX_LIST 0x0003
-#define MGMT_EV_INDEX_ADDED 0x0004
-#define MGMT_EV_COMMAND_COMP 0x0001
-#define MGMT_EV_SIZE_MAX 1024
-#define MGMT_EV_POLL_TIMEOUT 3000 /* 3000ms */
-
-#define IOCTL_HCIDEVDOWN _IOW('H', 202, int)
-
-struct sockaddr_hci {
-  sa_family_t hci_family;
-  unsigned short hci_dev;
-  unsigned short hci_channel;
-};
-
-struct rfkill_event {
-  uint32_t idx;
-  uint8_t type;
-  uint8_t op;
-  uint8_t soft, hard;
-} __attribute__((packed));
-
-struct mgmt_pkt {
-  uint16_t opcode;
-  uint16_t index;
-  uint16_t len;
-  uint8_t data[MGMT_EV_SIZE_MAX];
-} __attribute__((packed));
-
-struct mgmt_event_read_index {
-  uint16_t cc_opcode;
-  uint8_t status;
-  uint16_t num_intf;
-  uint16_t index[0];
-} __attribute__((packed));
-
-static const bt_vendor_callbacks_t* bt_vendor_callbacks;
-static unsigned char bt_vendor_local_bdaddr[6];
-static int bt_vendor_fd = -1;
-static int hci_interface;
-static int rfkill_en;
-static int bt_hwcfg_en;
-
-static int bt_vendor_init(const bt_vendor_callbacks_t* p_cb,
-                          unsigned char* local_bdaddr) {
-  char prop_value[PROPERTY_VALUE_MAX];
-
-  LOG_INFO(LOG_TAG, "%s", __func__);
-
-  if (p_cb == NULL) {
-    LOG_ERROR(LOG_TAG, "init failed with no user callbacks!");
-    return -1;
-  }
-
-  bt_vendor_callbacks = p_cb;
-
-  memcpy(bt_vendor_local_bdaddr, local_bdaddr, sizeof(bt_vendor_local_bdaddr));
-
-  osi_property_get("bluetooth.interface", prop_value, "0");
-
-  errno = 0;
-  if (memcmp(prop_value, "hci", 3))
-    hci_interface = strtol(prop_value, NULL, 10);
-  else
-    hci_interface = strtol(prop_value + 3, NULL, 10);
-  if (errno) hci_interface = 0;
-
-  LOG_INFO(LOG_TAG, "Using interface hci%d", hci_interface);
-
-  osi_property_get("bluetooth.rfkill", prop_value, "0");
-
-  rfkill_en = atoi(prop_value);
-  if (rfkill_en) LOG_INFO(LOG_TAG, "RFKILL enabled");
-
-  bt_hwcfg_en =
-      osi_property_get("bluetooth.hwcfg", prop_value, NULL) > 0 ? 1 : 0;
-  if (bt_hwcfg_en) LOG_INFO(LOG_TAG, "HWCFG enabled");
-
-  return 0;
-}
-
-static int bt_vendor_hw_cfg(int stop) {
-  if (!bt_hwcfg_en) return 0;
-
-  if (stop) {
-    if (osi_property_set("bluetooth.hwcfg", "stop") < 0) {
-      LOG_ERROR(LOG_TAG, "%s cannot stop btcfg service via prop", __func__);
-      return 1;
-    }
-  } else {
-    if (osi_property_set("bluetooth.hwcfg", "start") < 0) {
-      LOG_ERROR(LOG_TAG, "%s cannot start btcfg service via prop", __func__);
-      return 1;
-    }
-  }
-  return 0;
-}
-
-static int bt_vendor_wait_hcidev(void) {
-  struct sockaddr_hci addr;
-  struct pollfd fds[1];
-  struct mgmt_pkt ev;
-  int fd;
-  int ret = 0;
-
-  LOG_INFO(LOG_TAG, "%s", __func__);
-
-  fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
-  if (fd < 0) {
-    LOG_ERROR(LOG_TAG, "Bluetooth socket error: %s", strerror(errno));
-    return -1;
-  }
-
-  memset(&addr, 0, sizeof(addr));
-  addr.hci_family = AF_BLUETOOTH;
-  addr.hci_dev = HCI_DEV_NONE;
-  addr.hci_channel = HCI_CHANNEL_CONTROL;
-
-  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
-    LOG_ERROR(LOG_TAG, "HCI Channel Control: %s", strerror(errno));
-    close(fd);
-    return -1;
-  }
-
-  fds[0].fd = fd;
-  fds[0].events = POLLIN;
-
-  /* Read Controller Index List Command */
-  ev.opcode = MGMT_OP_INDEX_LIST;
-  ev.index = HCI_DEV_NONE;
-  ev.len = 0;
-
-  ssize_t wrote;
-  OSI_NO_INTR(wrote = write(fd, &ev, 6));
-  if (wrote != 6) {
-    LOG_ERROR(LOG_TAG, "Unable to write mgmt command: %s", strerror(errno));
-    ret = -1;
-    goto end;
-  }
-
-  while (1) {
-    int n;
-    OSI_NO_INTR(n = poll(fds, 1, MGMT_EV_POLL_TIMEOUT));
-    if (n == -1) {
-      LOG_ERROR(LOG_TAG, "Poll error: %s", strerror(errno));
-      ret = -1;
-      break;
-    } else if (n == 0) {
-      LOG_ERROR(LOG_TAG, "Timeout, no HCI device detected");
-      ret = -1;
-      break;
-    }
-
-    if (fds[0].revents & POLLIN) {
-      OSI_NO_INTR(n = read(fd, &ev, sizeof(struct mgmt_pkt)));
-      if (n < 0) {
-        LOG_ERROR(LOG_TAG, "Error reading control channel: %s",
-                  strerror(errno));
-        ret = -1;
-        break;
-      }
-
-      if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
-        goto end;
-      } else if (ev.opcode == MGMT_EV_COMMAND_COMP) {
-        struct mgmt_event_read_index* cc;
-        int i;
-
-        cc = (struct mgmt_event_read_index*)ev.data;
-
-        if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0) continue;
-
-        for (i = 0; i < cc->num_intf; i++) {
-          if (cc->index[i] == hci_interface) goto end;
-        }
-      }
-    }
-  }
-
-end:
-  close(fd);
-  return ret;
-}
-
-static int bt_vendor_open(void* param) {
-  int(*fd_array)[] = (int(*)[])param;
-  int fd;
-
-  LOG_INFO(LOG_TAG, "%s", __func__);
-
-  fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
-  if (fd < 0) {
-    LOG_ERROR(LOG_TAG, "socket create error %s", strerror(errno));
-    return -1;
-  }
-
-  (*fd_array)[CH_CMD] = fd;
-  (*fd_array)[CH_EVT] = fd;
-  (*fd_array)[CH_ACL_OUT] = fd;
-  (*fd_array)[CH_ACL_IN] = fd;
-
-  bt_vendor_fd = fd;
-
-  LOG_INFO(LOG_TAG, "%s returning %d", __func__, bt_vendor_fd);
-
-  return 1;
-}
-
-static int bt_vendor_close(void* param) {
-  (void)(param);
-
-  LOG_INFO(LOG_TAG, "%s", __func__);
-
-  if (bt_vendor_fd != -1) {
-    close(bt_vendor_fd);
-    bt_vendor_fd = -1;
-  }
-
-  return 0;
-}
-
-static int bt_vendor_rfkill(int block) {
-  struct rfkill_event event;
-  int fd;
-
-  LOG_INFO(LOG_TAG, "%s", __func__);
-
-  fd = open("/dev/rfkill", O_WRONLY);
-  if (fd < 0) {
-    LOG_ERROR(LOG_TAG, "Unable to open /dev/rfkill");
-    return -1;
-  }
-
-  memset(&event, 0, sizeof(struct rfkill_event));
-  event.op = RFKILL_OP_CHANGE_ALL;
-  event.type = RFKILL_TYPE_BLUETOOTH;
-  event.hard = block;
-  event.soft = block;
-
-  ssize_t len;
-  OSI_NO_INTR(len = write(fd, &event, sizeof(event)));
-  if (len < 0) {
-    LOG_ERROR(LOG_TAG, "Failed to change rfkill state");
-    close(fd);
-    return 1;
-  }
-
-  close(fd);
-  return 0;
-}
-
-/* TODO: fw config should thread the device waiting and return immedialty */
-static void bt_vendor_fw_cfg(void) {
-  struct sockaddr_hci addr;
-  int fd = bt_vendor_fd;
-
-  LOG_INFO(LOG_TAG, "%s", __func__);
-
-  if (fd == -1) {
-    LOG_ERROR(LOG_TAG, "bt_vendor_fd: %s", strerror(EBADF));
-    goto failure;
-  }
-
-  memset(&addr, 0, sizeof(addr));
-  addr.hci_family = AF_BLUETOOTH;
-  addr.hci_dev = hci_interface;
-  addr.hci_channel = HCI_CHANNEL_USER;
-
-  if (bt_vendor_wait_hcidev()) {
-    LOG_ERROR(LOG_TAG, "HCI interface (%d) not found", hci_interface);
-    goto failure;
-  }
-
-  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
-    LOG_ERROR(LOG_TAG, "socket bind error %s", strerror(errno));
-    goto failure;
-  }
-
-  LOG_INFO(LOG_TAG, "HCI device ready");
-
-  bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
-
-  return;
-
-failure:
-  LOG_ERROR(LOG_TAG, "Hardware Config Error");
-  bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
-}
-
-static int bt_vendor_op(bt_vendor_opcode_t opcode, void* param) {
-  int retval = 0;
-
-  LOG_INFO(LOG_TAG, "%s op %d", __func__, opcode);
-
-  switch (opcode) {
-    case BT_VND_OP_POWER_CTRL:
-      if (!rfkill_en || !param) break;
-
-      if (*((int*)param) == BT_VND_PWR_ON) {
-        retval = bt_vendor_rfkill(0);
-        if (!retval) retval = bt_vendor_hw_cfg(0);
-      } else {
-        retval = bt_vendor_hw_cfg(1);
-        if (!retval) retval = bt_vendor_rfkill(1);
-      }
-
-      break;
-
-    case BT_VND_OP_FW_CFG:
-      bt_vendor_fw_cfg();
-      break;
-
-    case BT_VND_OP_SCO_CFG:
-      bt_vendor_callbacks->scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
-      break;
-
-    case BT_VND_OP_USERIAL_OPEN:
-      retval = bt_vendor_open(param);
-      break;
-
-    case BT_VND_OP_USERIAL_CLOSE:
-      retval = bt_vendor_close(param);
-      break;
-
-    case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
-      *((uint32_t*)param) = 3000;
-      retval = 0;
-      break;
-
-    case BT_VND_OP_LPM_SET_MODE:
-      bt_vendor_callbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS);
-      break;
-
-    case BT_VND_OP_LPM_WAKE_SET_STATE:
-      break;
-
-    case BT_VND_OP_SET_AUDIO_STATE:
-      bt_vendor_callbacks->audio_state_cb(BT_VND_OP_RESULT_SUCCESS);
-      break;
-
-    case BT_VND_OP_EPILOG:
-      bt_vendor_callbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
-      break;
-
-    case BT_VND_OP_A2DP_OFFLOAD_START:
-      break;
-
-    case BT_VND_OP_A2DP_OFFLOAD_STOP:
-      break;
-  }
-
-  LOG_INFO(LOG_TAG, "%s op %d retval %d", __func__, opcode, retval);
-
-  return retval;
-}
-
-static void bt_vendor_cleanup(void) {
-  LOG_INFO(LOG_TAG, "%s", __func__);
-
-  bt_vendor_callbacks = NULL;
-}
-
-EXPORT_SYMBOL const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
-    sizeof(bt_vendor_interface_t), bt_vendor_init, bt_vendor_op,
-    bt_vendor_cleanup,
-};
diff --git a/vendor_libs/linux/interface/Android.bp b/vendor_libs/linux/interface/Android.bp
new file mode 100644 (file)
index 0000000..56baf9e
--- /dev/null
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 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.
+
+cc_binary {
+    name: "android.hardware.bluetooth@1.0-service.btlinux",
+    proprietary: true,
+    relative_install_path: "hw",
+    srcs: [
+        "hci_packetizer.cc",
+        "h4_protocol.cc",
+        "bluetooth_hci.cc",
+        "async_fd_watcher.cc",
+        "service.cc"
+    ],
+    shared_libs: [
+        "android.hardware.bluetooth@1.0",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+    conlyflags: [
+        "-std=c99",
+    ],
+    init_rc: ["android.hardware.bluetooth@1.0-service.btlinux.rc"],
+}
+
diff --git a/vendor_libs/linux/interface/android.hardware.bluetooth@1.0-service.btlinux.rc b/vendor_libs/linux/interface/android.hardware.bluetooth@1.0-service.btlinux.rc
new file mode 100644 (file)
index 0000000..36fbc2c
--- /dev/null
@@ -0,0 +1,5 @@
+service btlinux-1.0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service.btlinux
+    class hal
+    user bluetooth
+    group bluetooth net_admin net_bt_admin
+    capabilities NET_ADMIN
diff --git a/vendor_libs/linux/interface/async_fd_watcher.cc b/vendor_libs/linux/interface/async_fd_watcher.cc
new file mode 100644 (file)
index 0000000..ef4a959
--- /dev/null
@@ -0,0 +1,188 @@
+//
+// 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 "async_fd_watcher.h"
+
+#include <algorithm>
+#include <atomic>
+#include <condition_variable>
+#include <log/log.h>
+#include <map>
+#include <mutex>
+#include <thread>
+#include <vector>
+#include "fcntl.h"
+#include "sys/select.h"
+#include "unistd.h"
+
+static const int INVALID_FD = -1;
+static const int BT_RT_PRIORITY = 1;
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace async {
+
+int AsyncFdWatcher::WatchFdForNonBlockingReads(
+    int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
+  // Add file descriptor and callback
+  {
+    std::unique_lock<std::mutex> guard(internal_mutex_);
+    watched_fds_[file_descriptor] = on_read_fd_ready_callback;
+  }
+
+  // Start the thread if not started yet
+  return tryStartThread();
+}
+
+int AsyncFdWatcher::ConfigureTimeout(
+    const std::chrono::milliseconds timeout,
+    const TimeoutCallback& on_timeout_callback) {
+  // Add timeout and callback
+  {
+    std::unique_lock<std::mutex> guard(timeout_mutex_);
+    timeout_cb_ = on_timeout_callback;
+    timeout_ms_ = timeout;
+  }
+
+  notifyThread();
+  return 0;
+}
+
+void AsyncFdWatcher::StopWatchingFileDescriptors() { stopThread(); }
+
+AsyncFdWatcher::~AsyncFdWatcher() {}
+
+// Make sure to call this with at least one file descriptor ready to be
+// watched upon or the thread routine will return immediately
+int AsyncFdWatcher::tryStartThread() {
+  if (std::atomic_exchange(&running_, true)) return 0;
+
+  // Set up the communication channel
+  int pipe_fds[2];
+  if (pipe2(pipe_fds, O_NONBLOCK)) return -1;
+
+  notification_listen_fd_ = pipe_fds[0];
+  notification_write_fd_ = pipe_fds[1];
+
+  thread_ = std::thread([this]() { ThreadRoutine(); });
+  if (!thread_.joinable()) return -1;
+
+  return 0;
+}
+
+int AsyncFdWatcher::stopThread() {
+  if (!std::atomic_exchange(&running_, false)) return 0;
+
+  notifyThread();
+  if (std::this_thread::get_id() != thread_.get_id()) {
+    thread_.join();
+  }
+
+  {
+    std::unique_lock<std::mutex> guard(internal_mutex_);
+    watched_fds_.clear();
+  }
+
+  {
+    std::unique_lock<std::mutex> guard(timeout_mutex_);
+    timeout_cb_ = nullptr;
+  }
+
+  return 0;
+}
+
+int AsyncFdWatcher::notifyThread() {
+  uint8_t buffer[] = {0};
+  if (TEMP_FAILURE_RETRY(write(notification_write_fd_, &buffer, 1)) < 0) {
+    return -1;
+  }
+  return 0;
+}
+
+void AsyncFdWatcher::ThreadRoutine() {
+
+  // Make watching thread RT.
+  struct sched_param rt_params;
+  rt_params.sched_priority = BT_RT_PRIORITY;
+  if (sched_setscheduler(gettid(), SCHED_FIFO, &rt_params)) {
+    ALOGE("%s unable to set SCHED_FIFO for pid %d, tid %d, error %s", __func__,
+          getpid(), gettid(), strerror(errno));
+  }
+
+  while (running_) {
+    fd_set read_fds;
+    FD_ZERO(&read_fds);
+    FD_SET(notification_listen_fd_, &read_fds);
+    int max_read_fd = INVALID_FD;
+    for (auto& it : watched_fds_) {
+      FD_SET(it.first, &read_fds);
+      max_read_fd = std::max(max_read_fd, it.first);
+    }
+
+    struct timeval timeout;
+    struct timeval* timeout_ptr = NULL;
+    if (timeout_ms_ > std::chrono::milliseconds(0)) {
+      timeout.tv_sec = timeout_ms_.count() / 1000;
+      timeout.tv_usec = (timeout_ms_.count() % 1000) * 1000;
+      timeout_ptr = &timeout;
+    }
+
+    // Wait until there is data available to read on some FD.
+    int nfds = std::max(notification_listen_fd_, max_read_fd);
+    int retval = select(nfds + 1, &read_fds, NULL, NULL, timeout_ptr);
+
+    // There was some error.
+    if (retval < 0) continue;
+
+    // Timeout.
+    if (retval == 0) {
+      // Allow the timeout callback to modify the timeout.
+      TimeoutCallback saved_cb;
+      {
+        std::unique_lock<std::mutex> guard(timeout_mutex_);
+        if (timeout_ms_ > std::chrono::milliseconds(0))
+          saved_cb = timeout_cb_;
+      }
+      if (saved_cb != nullptr)
+        saved_cb();
+      continue;
+    }
+
+    // Read data from the notification FD.
+    if (FD_ISSET(notification_listen_fd_, &read_fds)) {
+      char buffer[] = {0};
+      TEMP_FAILURE_RETRY(read(notification_listen_fd_, buffer, 1));
+      continue;
+    }
+
+    // Invoke the data ready callbacks if appropriate.
+    {
+      // Hold the mutex to make sure that the callbacks are still valid.
+      std::unique_lock<std::mutex> guard(internal_mutex_);
+      for (auto& it : watched_fds_) {
+        if (FD_ISSET(it.first, &read_fds)) {
+        it.second(it.first);
+        }
+      }
+    }
+  }
+}
+
+} // namespace async
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/vendor_libs/linux/interface/async_fd_watcher.h b/vendor_libs/linux/interface/async_fd_watcher.h
new file mode 100644 (file)
index 0000000..358cbc3
--- /dev/null
@@ -0,0 +1,67 @@
+//
+// 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 <map>
+#include <mutex>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace async {
+
+using ReadCallback = std::function<void(int)>;
+using TimeoutCallback = std::function<void(void)>;
+
+class AsyncFdWatcher {
+ public:
+  AsyncFdWatcher() = default;
+  ~AsyncFdWatcher();
+
+  int WatchFdForNonBlockingReads(int file_descriptor,
+                                 const ReadCallback& on_read_fd_ready_callback);
+  int ConfigureTimeout(const std::chrono::milliseconds timeout,
+                       const TimeoutCallback& on_timeout_callback);
+  void StopWatchingFileDescriptors();
+
+ private:
+  AsyncFdWatcher(const AsyncFdWatcher&) = delete;
+  AsyncFdWatcher& operator=(const AsyncFdWatcher&) = delete;
+
+  int tryStartThread();
+  int stopThread();
+  int notifyThread();
+  void ThreadRoutine();
+
+  std::atomic_bool running_{false};
+  std::thread thread_;
+  std::mutex internal_mutex_;
+  std::mutex timeout_mutex_;
+
+  std::map<int, ReadCallback> watched_fds_;
+  int notification_listen_fd_;
+  int notification_write_fd_;
+  TimeoutCallback timeout_cb_;
+  std::chrono::milliseconds timeout_ms_;
+};
+
+
+} // namespace async
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/vendor_libs/linux/interface/bluetooth_hci.cc b/vendor_libs/linux/interface/bluetooth_hci.cc
new file mode 100644 (file)
index 0000000..8507f7a
--- /dev/null
@@ -0,0 +1,344 @@
+//
+// 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-btlinux"
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/socket.h>
+
+#include <utils/Log.h>
+
+#include "bluetooth_hci.h"
+
+#define BTPROTO_HCI 1
+
+#define HCI_CHANNEL_USER 1
+#define HCI_CHANNEL_CONTROL 3
+#define HCI_DEV_NONE 0xffff
+
+/* reference from <kernel>/include/net/bluetooth/mgmt.h */
+#define MGMT_OP_INDEX_LIST 0x0003
+#define MGMT_EV_INDEX_ADDED 0x0004
+#define MGMT_EV_COMMAND_COMP 0x0001
+#define MGMT_EV_SIZE_MAX 1024
+#define MGMT_EV_POLL_TIMEOUT 3000 /* 3000ms */
+#define WRITE_NO_INTR(fn) \
+  do {                  \
+  } while ((fn) == -1 && errno == EINTR)
+
+struct sockaddr_hci {
+    sa_family_t hci_family;
+    unsigned short hci_dev;
+    unsigned short hci_channel;
+};
+
+struct mgmt_pkt {
+    uint16_t opcode;
+    uint16_t index;
+    uint16_t len;
+    uint8_t data[MGMT_EV_SIZE_MAX];
+} __attribute__((packed));
+
+struct mgmt_event_read_index {
+    uint16_t cc_opcode;
+    uint8_t status;
+    uint16_t num_intf;
+    uint16_t index[0];
+  } __attribute__((packed));
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace btlinux {
+
+int BluetoothHci::openBtHci() {
+
+  ALOGI( "%s", __func__);
+
+  int hci_interface = 0;
+  rfkill_state_ = NULL;
+  rfKill(1);
+
+  int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+  if (fd < 0) {
+    ALOGE( "Bluetooth socket error: %s", strerror(errno));
+    return -1;
+  }
+  bt_soc_fd_ = fd;
+
+  if (waitHciDev(hci_interface)) {
+    ALOGE( "HCI interface (%d) not found", hci_interface);
+    ::close(fd);
+    return -1;
+  }
+  struct sockaddr_hci addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.hci_family = AF_BLUETOOTH;
+  addr.hci_dev = hci_interface;
+  addr.hci_channel = HCI_CHANNEL_USER;
+  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+    ALOGE( "HCI Channel Control: %s", strerror(errno));
+    ::close(fd);
+    return -1;
+  }
+  ALOGI( "HCI device ready");
+  return fd;
+}
+
+void BluetoothHci::closeBtHci() {
+  if (bt_soc_fd_ != -1) {
+    ::close(bt_soc_fd_);
+    bt_soc_fd_ = -1;
+  }
+  rfKill(0);
+  free(rfkill_state_);
+}
+
+int BluetoothHci::waitHciDev(int hci_interface) {
+  struct sockaddr_hci addr;
+  struct pollfd fds[1];
+  struct mgmt_pkt ev;
+  int fd;
+  int ret = 0;
+
+  ALOGI( "%s", __func__);
+  fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+  if (fd < 0) {
+    ALOGE( "Bluetooth socket error: %s", strerror(errno));
+    return -1;
+  }
+  memset(&addr, 0, sizeof(addr));
+  addr.hci_family = AF_BLUETOOTH;
+  addr.hci_dev = HCI_DEV_NONE;
+  addr.hci_channel = HCI_CHANNEL_CONTROL;
+  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+    ALOGE( "HCI Channel Control: %s", strerror(errno));
+    ret = -1;
+    goto end;
+  }
+
+  fds[0].fd = fd;
+  fds[0].events = POLLIN;
+
+  /* Read Controller Index List Command */
+  ev.opcode = MGMT_OP_INDEX_LIST;
+  ev.index = HCI_DEV_NONE;
+  ev.len = 0;
+
+  ssize_t wrote;
+  WRITE_NO_INTR(wrote = write(fd, &ev, 6));
+  if (wrote != 6) {
+    ALOGE( "Unable to write mgmt command: %s", strerror(errno));
+    ret = -1;
+    goto end;
+  }
+  /* validate mentioned hci interface is present and registered with sock system */
+  while (1) {
+    int n;
+    WRITE_NO_INTR(n = poll(fds, 1, MGMT_EV_POLL_TIMEOUT));
+    if (n == -1) {
+      ALOGE( "Poll error: %s", strerror(errno));
+      ret = -1;
+      break;
+    } else if (n == 0) {
+      ALOGE( "Timeout, no HCI device detected");
+      ret = -1;
+      break;
+    }
+
+    if (fds[0].revents & POLLIN) {
+      WRITE_NO_INTR(n = read(fd, &ev, sizeof(struct mgmt_pkt)));
+      if (n < 0) {
+        ALOGE( "Error reading control channel: %s",
+                  strerror(errno));
+        ret = -1;
+        break;
+      }
+
+      if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
+        goto end;
+      } else if (ev.opcode == MGMT_EV_COMMAND_COMP) {
+        struct mgmt_event_read_index* cc;
+        int i;
+
+        cc = (struct mgmt_event_read_index*)ev.data;
+
+        if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0) continue;
+
+        for (i = 0; i < cc->num_intf; i++) {
+          if (cc->index[i] == hci_interface) goto end;
+        }
+      }
+    }
+  }
+
+end:
+  ::close(fd);
+  return ret;
+}
+
+int BluetoothHci::findRfKill() {
+    char rfkill_type[64];
+    char type[16];
+    int fd, size, i;
+    for(i = 0; rfkill_state_ == NULL; i++)
+    {
+        snprintf(rfkill_type, sizeof(rfkill_type), "/sys/class/rfkill/rfkill%d/type", i);
+        if ((fd = open(rfkill_type, O_RDONLY)) < 0)
+        {
+            ALOGE("open(%s) failed: %s (%d)\n", rfkill_type, strerror(errno), errno);
+            return -1;
+        }
+
+        size = read(fd, &type, sizeof(type));
+        ::close(fd);
+
+        if ((size >= 9) && !memcmp(type, "bluetooth", 9))
+        {
+            ::asprintf(&rfkill_state_, "/sys/class/rfkill/rfkill%d/state", i);
+            break;
+        }
+    }
+    return 0;
+}
+
+int BluetoothHci::rfKill(int block) {
+  int fd;
+  char on = (block)?'1':'0';
+  if (findRfKill() != 0) return 0;
+
+  fd = open(rfkill_state_, O_WRONLY);
+  if (fd < 0) {
+    ALOGE( "Unable to open /dev/rfkill");
+    return -1;
+  }
+  ssize_t len;
+  WRITE_NO_INTR(len = write(fd, &on, 1));
+  if (len < 0) {
+    ALOGE( "Failed to change rfkill state");
+    ::close(fd);
+    return -1;
+  }
+  ::close(fd);
+  return 0;
+}
+
+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);
+  int hci_fd = openBtHci();
+  auto hidl_status = cb->initializationComplete(
+          hci_fd > 0 ? Status::SUCCESS : Status::INITIALIZATION_ERROR);
+  if (!hidl_status.isOk()) {
+      ALOGE("VendorInterface -> Unable to call initializationComplete(ERR)");
+  }
+  hci::H4Protocol* h4_hci = new hci::H4Protocol(
+      hci_fd,
+      [cb](const hidl_vec<uint8_t>& packet) { cb->hciEventReceived(packet); },
+      [cb](const hidl_vec<uint8_t>& packet) { cb->aclDataReceived(packet); },
+      [cb](const hidl_vec<uint8_t>& packet) { cb->scoDataReceived(packet); });
+
+  fd_watcher_.WatchFdForNonBlockingReads(
+          hci_fd, [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
+  hci_handle_ = h4_hci;
+
+  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_);
+  fd_watcher_.StopWatchingFileDescriptors();
+
+  if (hci_handle_ != nullptr) {
+    delete hci_handle_;
+    hci_handle_ = nullptr;
+  }
+  closeBtHci();
+  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) {
+  hci_handle_->Send(type, data.data(), data.size());
+}
+
+IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* /* name */) {
+  return new BluetoothHci();
+}
+
+}  // namespace btlinux
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/vendor_libs/linux/interface/bluetooth_hci.h b/vendor_libs/linux/interface/bluetooth_hci.h
new file mode 100644 (file)
index 0000000..5dc1c0a
--- /dev/null
@@ -0,0 +1,78 @@
+//
+// 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 "async_fd_watcher.h"
+#include "h4_protocol.h"
+#include "hci_internals.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace btlinux {
+
+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:
+  async::AsyncFdWatcher fd_watcher_;
+  hci::H4Protocol* hci_handle_;
+  int bt_soc_fd_;
+  char *rfkill_state_;
+
+  const uint8_t HCI_DATA_TYPE_COMMAND = 1;
+  const uint8_t HCI_DATA_TYPE_ACL = 2;
+  const uint8_t HCI_DATA_TYPE_SCO = 3;
+
+  int waitHciDev(int hci_interface);
+  int findRfKill(void);
+  int rfKill(int block);
+  int openBtHci(void);
+  void closeBtHci(void);
+
+  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 btlinux
+}  // namespace V1_0
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_
diff --git a/vendor_libs/linux/interface/h4_protocol.cc b/vendor_libs/linux/interface/h4_protocol.cc
new file mode 100644 (file)
index 0000000..99aeb74
--- /dev/null
@@ -0,0 +1,105 @@
+//
+// 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>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+size_t H4Protocol::Send(uint8_t type, const uint8_t* data, size_t length) {
+    /* For HCI communication over USB dongle, multiple write results in
+     * response timeout as driver expect type + data at once to process
+     * the command, so using "writev"(for atomicity) here.
+     */
+    struct iovec iov[2];
+    ssize_t ret = 0;
+    iov[0].iov_base = &type;
+    iov[0].iov_len = sizeof(type);
+    iov[1].iov_base = (void *)data;
+    iov[1].iov_len = length;
+    while (1) {
+        ret = TEMP_FAILURE_RETRY(writev(uart_fd_, iov, 2));
+        if (ret == -1) {
+            if (errno == EAGAIN) {
+                ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+                continue;
+            }
+        } else if (ret == 0) {
+            // Nothing written :(
+            ALOGE("%s zero bytes written - something went wrong...", __func__);
+            break;
+        }
+        break;
+    }
+    return ret;
+}
+
+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) {
+        /**
+         * read full buffer. ACL max length is 2 bytes, and SCO max length is 2
+         * byte. so taking 64K as buffer length.
+         * Question : Why to read in single chunk rather than multiple reads,
+         * which can give parameter length arriving in response ?
+         * Answer: The multiple reads does not work with BT USB dongle. At least
+         * with Bluetooth 2.0 supported USB dongle. After first read, either
+         * firmware/kernel (do not know who is responsible - inputs ??) driver
+         * discard the whole message and successive read results in forever
+         * blocking loop. - Is there any other way to make it work with multiple
+         * reads, do not know yet (it can eliminate need of this function) ?
+         * Reading in single shot gives expected response.
+         */
+        const size_t max_plen = 64*1024;
+        hidl_vec<uint8_t> tpkt;
+        tpkt.resize(max_plen);
+        size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, tpkt.data(), max_plen));
+        hci_packet_type_ = static_cast<HciPacketType>(tpkt.data()[0]);
+        hci_packetizer_.CbHciPacket(tpkt.data()+1, bytes_read-1);
+    }
+}
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/vendor_libs/linux/interface/h4_protocol.h b/vendor_libs/linux/interface/h4_protocol.h
new file mode 100644 (file)
index 0000000..612b0db
--- /dev/null
@@ -0,0 +1,63 @@
+//
+// 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 "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>&)>;
+
+class H4Protocol {
+ 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};
+  HciPacketizer hci_packetizer_;
+};
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/vendor_libs/linux/interface/hci_internals.h b/vendor_libs/linux/interface/hci_internals.h
new file mode 100644 (file)
index 0000000..1e1f300
--- /dev/null
@@ -0,0 +1,49 @@
+//
+// 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 <stdlib.h>
+
+// HCI UART transport packet types (Volume 4, Part A, 2)
+enum HciPacketType {
+  HCI_PACKET_TYPE_UNKNOWN = 0,
+  HCI_PACKET_TYPE_COMMAND = 1,
+  HCI_PACKET_TYPE_ACL_DATA = 2,
+  HCI_PACKET_TYPE_SCO_DATA = 3,
+  HCI_PACKET_TYPE_EVENT = 4
+};
+
+// 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
+const size_t HCI_COMMAND_PREAMBLE_SIZE = 3;
+const size_t HCI_LENGTH_OFFSET_CMD = 2;
+
+// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2)
+const size_t HCI_ACL_PREAMBLE_SIZE = 4;
+const size_t HCI_LENGTH_OFFSET_ACL = 2;
+
+// 2 bytes for handle, 1 byte for data length (Volume 2, Part E, 5.4.3)
+const size_t HCI_SCO_PREAMBLE_SIZE = 3;
+const size_t HCI_LENGTH_OFFSET_SCO = 2;
+
+// 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4)
+const size_t HCI_EVENT_PREAMBLE_SIZE = 2;
+const size_t HCI_LENGTH_OFFSET_EVT = 1;
+
+const size_t HCI_PREAMBLE_SIZE_MAX = HCI_ACL_PREAMBLE_SIZE;
+
+// Event codes (Volume 2, Part E, 7.7.14)
+const uint8_t HCI_COMMAND_COMPLETE_EVENT = 0x0E;
diff --git a/vendor_libs/linux/interface/hci_packetizer.cc b/vendor_libs/linux/interface/hci_packetizer.cc
new file mode 100644 (file)
index 0000000..0c0a979
--- /dev/null
@@ -0,0 +1,96 @@
+//
+// 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_packetizer.h"
+
+#define LOG_TAG "android.hardware.bluetooth.hci_packetizer"
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+#include <dlfcn.h>
+#include <fcntl.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 {
+
+const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const { return packet_; }
+
+void HciPacketizer::CbHciPacket(uint8_t *data, size_t len) {
+    packet_.setToExternal(data, len);
+    packet_ready_cb_();
+}
+
+void HciPacketizer::OnDataReady(int fd, HciPacketType packet_type) {
+  switch (state_) {
+    case HCI_PREAMBLE: {
+      size_t bytes_read = TEMP_FAILURE_RETRY(
+          read(fd, preamble_ + bytes_read_,
+               preamble_size_for_type[packet_type] - bytes_read_));
+      CHECK(bytes_read > 0);
+      bytes_read_ += bytes_read;
+      if (bytes_read_ == preamble_size_for_type[packet_type]) {
+        size_t packet_length =
+            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,
+          packet_.data() + preamble_size_for_type[packet_type] + bytes_read_,
+          bytes_remaining_));
+      CHECK(bytes_read > 0);
+      bytes_remaining_ -= bytes_read;
+      bytes_read_ += bytes_read;
+      if (bytes_remaining_ == 0) {
+        packet_ready_cb_();
+        state_ = HCI_PREAMBLE;
+        bytes_read_ = 0;
+      }
+      break;
+    }
+  }
+}
+
+}  // namespace hci
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/vendor_libs/linux/interface/hci_packetizer.h b/vendor_libs/linux/interface/hci_packetizer.h
new file mode 100644 (file)
index 0000000..06de70f
--- /dev/null
@@ -0,0 +1,54 @@
+//
+// 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 <functional>
+
+#include <hidl/HidlSupport.h>
+
+#include "hci_internals.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace hci {
+
+using ::android::hardware::hidl_vec;
+using HciPacketReadyCallback = std::function<void(void)>;
+
+class HciPacketizer {
+ public:
+  HciPacketizer(HciPacketReadyCallback packet_cb)
+      : packet_ready_cb_(packet_cb){};
+  void OnDataReady(int fd, HciPacketType packet_type);
+  void CbHciPacket(uint8_t* data, size_t length);
+  const hidl_vec<uint8_t>& GetPacket() const;
+
+ protected:
+  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
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/vendor_libs/linux/interface/service.cc b/vendor_libs/linux/interface/service.cc
new file mode 100644 (file)
index 0000000..fac9ce0
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// 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 "android.hardware.bluetooth@1.0-service.btlinux"
+
+#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Log.h>
+
+#include "bluetooth_hci.h"
+
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_0::btlinux::BluetoothHci;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::sp;
+
+int main(int /* argc */, char** /* argv */) {
+  sp<IBluetoothHci> bluetooth = new BluetoothHci;
+  configureRpcThreadpool(1, true);
+  android::status_t status = bluetooth->registerAsService();
+  if (status == android::OK)
+    joinRpcThreadpool();
+  else
+    ALOGE("Could not register as a service!");
+}
diff --git a/vendor_libs/linux/sepolicy/file_contexts b/vendor_libs/linux/sepolicy/file_contexts
new file mode 100644 (file)
index 0000000..4300140
--- /dev/null
@@ -0,0 +1,2 @@
+/sys/class/rfkill/rfkill[0-9]/state    u:object_r:sysfs_bluetooth_writable:s0
+/system/vendor/bin/hw/android\.hardware\.bluetooth@1\.0-service\.btlinux    u:object_r:hal_bluetooth_btlinux_exec:s0
diff --git a/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te b/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te
new file mode 100644 (file)
index 0000000..32349b9
--- /dev/null
@@ -0,0 +1,8 @@
+type hal_bluetooth_btlinux, domain;
+type hal_bluetooth_btlinux_exec, exec_type, file_type;
+
+hal_server_domain(hal_bluetooth_btlinux, hal_bluetooth)
+init_daemon_domain(hal_bluetooth_btlinux)
+
+allow hal_bluetooth_btlinux self:socket { create bind read write };
+allow hal_bluetooth_btlinux self:bluetooth_socket { create bind read write };