diff --git a/bluetooth/1.0/default/Android.bp b/bluetooth/1.0/default/Android.bp new file mode 100644 index 0000000000..4c7017c26e --- /dev/null +++ b/bluetooth/1.0/default/Android.bp @@ -0,0 +1,36 @@ +// +// 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", + relative_install_path: "hw", + srcs: [ + "async_fd_watcher.cc", + "bluetooth_hci.cc", + "vendor_interface.cc", + ], + shared_libs: [ + "liblog", + "libcutils", + "libhardware", + "libhwbinder", + "libbase", + "libcutils", + "libutils", + "libhidlbase", + "libhidltransport", + "android.hardware.bluetooth@1.0", + ], +} diff --git a/bluetooth/1.0/default/Android.mk b/bluetooth/1.0/default/Android.mk new file mode 100644 index 0000000000..08bfb4e9a1 --- /dev/null +++ b/bluetooth/1.0/default/Android.mk @@ -0,0 +1,40 @@ +# +# 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE := android.hardware.bluetooth@1.0-service +LOCAL_INIT_RC := android.hardware.bluetooth@1.0-service.rc +LOCAL_SRC_FILES := \ + service.cpp + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhardware_legacy \ + libhardware \ + +LOCAL_SHARED_LIBRARIES += \ + libhwbinder \ + libhidlbase \ + libhidltransport \ + android.hardware.bluetooth@1.0 \ + +include $(BUILD_EXECUTABLE) diff --git a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc new file mode 100644 index 0000000000..8c5c02a15d --- /dev/null +++ b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc @@ -0,0 +1,4 @@ +service bluetooth-1-0 /system/bin/hw/android.hardware.bluetooth@1.0-service + class hal + user bluetooth + group bluetooth diff --git a/bluetooth/1.0/default/async_fd_watcher.cc b/bluetooth/1.0/default/async_fd_watcher.cc new file mode 100644 index 0000000000..636b4b6e11 --- /dev/null +++ b/bluetooth/1.0/default/async_fd_watcher.cc @@ -0,0 +1,133 @@ +// +// 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 +#include +#include +#include +#include +#include +#include "fcntl.h" +#include "sys/select.h" +#include "unistd.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace implementation { + +int AsyncFdWatcher::WatchFdForNonBlockingReads( + int file_descriptor, const ReadCallback& on_read_fd_ready_callback) { + // Add file descriptor and callback + { + std::unique_lock guard(internal_mutex_); + read_fd_ = file_descriptor; + cb_ = on_read_fd_ready_callback; + } + + // Start the thread if not started yet + int started = tryStartThread(); + if (started != 0) { + return started; + } + + return 0; +} + +void AsyncFdWatcher::StopWatchingFileDescriptor() { 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 guard(internal_mutex_); + cb_ = nullptr; + read_fd_ = -1; + } + + 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() { + while (running_) { + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(notification_listen_fd_, &read_fds); + FD_SET(read_fd_, &read_fds); + + // Wait until there is data available to read on some FD + int nfds = std::max(notification_listen_fd_, read_fd_); + int retval = select(nfds + 1, &read_fds, NULL, NULL, NULL); + if (retval <= 0) continue; // there was some error or a timeout + + // 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)); + } + + // Make sure we're still running + if (!running_) break; + + // Invoke the data ready callback if appropriate + if (FD_ISSET(read_fd_, &read_fds)) { + std::unique_lock guard(internal_mutex_); + if (cb_) cb_(read_fd_); + } + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/1.0/default/async_fd_watcher.h b/bluetooth/1.0/default/async_fd_watcher.h new file mode 100644 index 0000000000..1e4da8c8cd --- /dev/null +++ b/bluetooth/1.0/default/async_fd_watcher.h @@ -0,0 +1,63 @@ +// +// 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 +#include + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace implementation { + +using ReadCallback = std::function; + +class AsyncFdWatcher { + public: + AsyncFdWatcher() = default; + ~AsyncFdWatcher(); + + int WatchFdForNonBlockingReads(int file_descriptor, + const ReadCallback& on_read_fd_ready_callback); + void StopWatchingFileDescriptor(); + + 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_; + + int read_fd_; + int notification_listen_fd_; + int notification_write_fd_; + ReadCallback cb_; +}; + + +} // namespace implementation +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/1.0/default/bluetooth_hci.cc b/bluetooth/1.0/default/bluetooth_hci.cc new file mode 100644 index 0000000000..d12bfb9642 --- /dev/null +++ b/bluetooth/1.0/default/bluetooth_hci.cc @@ -0,0 +1,95 @@ +// +// 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 + +#include "bluetooth_hci.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; + +Return BluetoothHci::initialize( + const ::android::sp& cb) { + ALOGW("BluetoothHci::initialize()"); + event_cb_ = cb; + + bool rc = VendorInterface::Initialize( + [this](HciPacketType type, const hidl_vec& 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; + } + }); + if (!rc) return Status::INITIALIZATION_ERROR; + + return Status::SUCCESS; +} + +Return BluetoothHci::close() { + ALOGW("BluetoothHci::close()"); + VendorInterface::Shutdown(); + return Void(); +} + +Return BluetoothHci::sendHciCommand(const hidl_vec& command) { + sendDataToController(HCI_DATA_TYPE_COMMAND, command); + return Void(); +} + +Return BluetoothHci::sendAclData(const hidl_vec& data) { + sendDataToController(HCI_DATA_TYPE_ACL, data); + return Void(); +} + +Return BluetoothHci::sendScoData(const hidl_vec& data) { + sendDataToController(HCI_DATA_TYPE_SCO, data); + return Void(); +} + +void BluetoothHci::sendDataToController(const uint8_t type, + const hidl_vec& data) { + VendorInterface::get()->Send(&type, 1); + VendorInterface::get()->Send(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/bluetooth/1.0/default/bluetooth_hci.h b/bluetooth/1.0/default/bluetooth_hci.h new file mode 100644 index 0000000000..d297570a35 --- /dev/null +++ b/bluetooth/1.0/default/bluetooth_hci.h @@ -0,0 +1,55 @@ +// +// 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 + +#include + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::Return; +using ::android::hardware::hidl_vec; + +class BluetoothHci : public IBluetoothHci { + public: + Return initialize( + const ::android::sp& cb) override; + Return sendHciCommand(const hidl_vec& packet) override; + Return sendAclData(const hidl_vec& data) override; + Return sendScoData(const hidl_vec& data) override; + Return close() override; + + private: + void sendDataToController(const uint8_t type, const hidl_vec& data); + ::android::sp event_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/bluetooth/1.0/default/bt_vendor_lib.h b/bluetooth/1.0/default/bt_vendor_lib.h new file mode 100644 index 0000000000..c140e52245 --- /dev/null +++ b/bluetooth/1.0/default/bt_vendor_lib.h @@ -0,0 +1,435 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom 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. + * + ******************************************************************************/ + +#ifndef BT_VENDOR_LIB_H +#define BT_VENDOR_LIB_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Struct types */ + +/** Typedefs and defines */ + +/** Vendor specific operations OPCODE */ +typedef enum { + /* [operation] + * Power on or off the BT Controller. + * [input param] + * A pointer to int type with content of bt_vendor_power_state_t. + * Typecasting conversion: (int *) param. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_POWER_CTRL, + + /* [operation] + * Perform any vendor specific initialization or configuration + * on the BT Controller. This is called before stack initialization. + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * Must call fwcfg_cb to notify the stack of the completion of vendor + * specific initialization once it has been done. + */ + BT_VND_OP_FW_CFG, + + /* [operation] + * Perform any vendor specific SCO/PCM configuration on the BT + * Controller. + * This is called after stack initialization. + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * Must call scocfg_cb to notify the stack of the completion of vendor + * specific SCO configuration once it has been done. + */ + BT_VND_OP_SCO_CFG, + + /* [operation] + * Open UART port on where the BT Controller is attached. + * This is called before stack initialization. + * [input param] + * A pointer to int array type for open file descriptors. + * The mapping of HCI channel to fd slot in the int array is given in + * bt_vendor_hci_channels_t. + * And, it requires the vendor lib to fill up the content before + * returning + * the call. + * Typecasting conversion: (int (*)[]) param. + * [return] + * Numbers of opened file descriptors. + * Valid number: + * 1 - CMD/EVT/ACL-In/ACL-Out via the same fd (e.g. UART) + * 2 - CMD/EVT on one fd, and ACL-In/ACL-Out on the other fd + * 4 - CMD, EVT, ACL-In, ACL-Out are on their individual fd + * [callback] + * None. + */ + BT_VND_OP_USERIAL_OPEN, + + /* [operation] + * Close the previously opened UART port. + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_USERIAL_CLOSE, + + /* [operation] + * Get the LPM idle timeout in milliseconds. + * The stack uses this information to launch a timer delay before it + * attempts to de-assert LPM WAKE signal once downstream HCI packet + * has been delivered. + * [input param] + * A pointer to uint32_t type which is passed in by the stack. And, it + * requires the vendor lib to fill up the content before returning + * the call. + * Typecasting conversion: (uint32_t *) param. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_GET_LPM_IDLE_TIMEOUT, + + /* [operation] + * Enable or disable LPM mode on BT Controller. + * [input param] + * A pointer to uint8_t type with content of bt_vendor_lpm_mode_t. + * Typecasting conversion: (uint8_t *) param. + * [return] + * 0 - default, don't care. + * [callback] + * Must call lpm_cb to notify the stack of the completion of LPM + * disable/enable process once it has been done. + */ + BT_VND_OP_LPM_SET_MODE, + + /* [operation] + * Assert or Deassert LPM WAKE on BT Controller. + * [input param] + * A pointer to uint8_t type with content of bt_vendor_lpm_wake_state_t. + * Typecasting conversion: (uint8_t *) param. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_LPM_WAKE_SET_STATE, + + /* [operation] + * Perform any vendor specific commands related to audio state changes. + * [input param] + * a pointer to bt_vendor_op_audio_state_t indicating what audio state is + * set. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_SET_AUDIO_STATE, + + /* [operation] + * The epilog call to the vendor module so that it can perform any + * vendor-specific processes (e.g. send a HCI_RESET to BT Controller) + * before the caller calls for cleanup(). + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * Must call epilog_cb to notify the stack of the completion of vendor + * specific epilog process once it has been done. + */ + BT_VND_OP_EPILOG, + + /* [operation] + * Call to the vendor module so that it can perform all vendor-specific + * operations to start offloading a2dp media encode & tx. + * [input param] + * pointer to bt_vendor_op_a2dp_offload_start_t containing elements + * required for VND FW to setup a2dp offload. + * [return] + * 0 - default, dont care. + * [callback] + * Must call a2dp_offload_start_cb to notify the stack of the + * completion of vendor specific setup process once it has been done. + */ + BT_VND_OP_A2DP_OFFLOAD_START, + + /* [operation] + * Call to the vendor module so that it can perform all vendor-specific + * operations to suspend offloading a2dp media encode & tx. + * [input param] + * pointer to bt_vendor_op_a2dp_offload_t containing elements + * required for VND FW to setup a2dp offload. + * [return] + * 0 - default, dont care. + * [callback] + * Must call a2dp_offload_cb to notify the stack of the + * completion of vendor specific setup process once it has been done. + */ + BT_VND_OP_A2DP_OFFLOAD_STOP, + +} bt_vendor_opcode_t; + +/** Power on/off control states */ +typedef enum { + BT_VND_PWR_OFF, + BT_VND_PWR_ON, +} bt_vendor_power_state_t; + +/** Define HCI channel identifier in the file descriptors array + used in BT_VND_OP_USERIAL_OPEN operation. + */ +typedef enum { + CH_CMD, // HCI Command channel + CH_EVT, // HCI Event channel + CH_ACL_OUT, // HCI ACL downstream channel + CH_ACL_IN, // HCI ACL upstream channel + + CH_MAX // Total channels +} bt_vendor_hci_channels_t; + +/** LPM disable/enable request */ +typedef enum { + BT_VND_LPM_DISABLE, + BT_VND_LPM_ENABLE, +} bt_vendor_lpm_mode_t; + +/** LPM WAKE set state request */ +typedef enum { + BT_VND_LPM_WAKE_ASSERT, + BT_VND_LPM_WAKE_DEASSERT, +} bt_vendor_lpm_wake_state_t; + +/** Callback result values */ +typedef enum { + BT_VND_OP_RESULT_SUCCESS, + BT_VND_OP_RESULT_FAIL, +} bt_vendor_op_result_t; + +/** audio (SCO) state changes triggering VS commands for configuration */ +typedef struct { + uint16_t handle; + uint16_t peer_codec; + uint16_t state; +} bt_vendor_op_audio_state_t; + +/* + * Bluetooth Host/Controller Vendor callback structure. + */ + +/* vendor initialization/configuration callback */ +typedef void (*cfg_result_cb)(bt_vendor_op_result_t result); + +/* datapath buffer allocation callback (callout) + * + * Vendor lib needs to request a buffer through the alloc callout function + * from HCI lib if the buffer is for constructing a HCI Command packet which + * will be sent through xmit_cb to BT Controller. + * + * For each buffer allocation, the requested size needs to be big enough to + * accommodate the below header plus a complete HCI packet -- + * typedef struct + * { + * uint16_t event; + * uint16_t len; + * uint16_t offset; + * uint16_t layer_specific; + * } HC_BT_HDR; + * + * HCI lib returns a pointer to the buffer where Vendor lib should use to + * construct a HCI command packet as below format: + * + * -------------------------------------------- + * | HC_BT_HDR | HCI command | + * -------------------------------------------- + * where + * HC_BT_HDR.event = 0x2000; + * HC_BT_HDR.len = Length of HCI command; + * HC_BT_HDR.offset = 0; + * HC_BT_HDR.layer_specific = 0; + * + * For example, a HCI_RESET Command will be formed as + * ------------------------ + * | HC_BT_HDR |03|0c|00| + * ------------------------ + * with + * HC_BT_HDR.event = 0x2000; + * HC_BT_HDR.len = 3; + * HC_BT_HDR.offset = 0; + * HC_BT_HDR.layer_specific = 0; + */ +typedef void* (*malloc_cb)(int size); + +/* datapath buffer deallocation callback (callout) */ +typedef void (*mdealloc_cb)(void* p_buf); + +/* define callback of the cmd_xmit_cb + * + * The callback function which HCI lib will call with the return of command + * complete packet. Vendor lib is responsible for releasing the buffer passed + * in at the p_mem parameter by calling dealloc callout function. + */ +typedef void (*tINT_CMD_CBACK)(void* p_mem); + +/* hci command packet transmit callback (callout) + * + * Vendor lib calls xmit_cb callout function in order to send a HCI Command + * packet to BT Controller. The buffer carrying HCI Command packet content + * needs to be first allocated through the alloc callout function. + * HCI lib will release the buffer for Vendor lib once it has delivered the + * packet content to BT Controller. + * + * Vendor lib needs also provide a callback function (p_cback) which HCI lib + * will call with the return of command complete packet. + * + * The opcode parameter gives the HCI OpCode (combination of OGF and OCF) of + * HCI Command packet. For example, opcode = 0x0c03 for the HCI_RESET command + * packet. + */ +typedef uint8_t (*cmd_xmit_cb)(uint16_t opcode, void* p_buf, + tINT_CMD_CBACK p_cback); + +typedef void (*cfg_a2dp_cb)(bt_vendor_op_result_t result, bt_vendor_opcode_t op, + uint8_t bta_av_handle); + +typedef struct { + /** set to sizeof(bt_vendor_callbacks_t) */ + size_t size; + + /* + * Callback and callout functions have implemented in HCI libray + * (libbt-hci.so). + */ + + /* notifies caller result of firmware configuration request */ + cfg_result_cb fwcfg_cb; + + /* notifies caller result of sco configuration request */ + cfg_result_cb scocfg_cb; + + /* notifies caller result of lpm enable/disable */ + cfg_result_cb lpm_cb; + + /* notifies the result of codec setting */ + cfg_result_cb audio_state_cb; + + /* buffer allocation request */ + malloc_cb alloc; + + /* buffer deallocation request */ + mdealloc_cb dealloc; + + /* hci command packet transmit request */ + cmd_xmit_cb xmit_cb; + + /* notifies caller completion of epilog process */ + cfg_result_cb epilog_cb; + + /* notifies status of a2dp offload cmd's */ + cfg_a2dp_cb a2dp_offload_cb; +} bt_vendor_callbacks_t; + +/** A2DP offload request */ +typedef struct { + uint8_t bta_av_handle; /* BTA_AV Handle for callbacks */ + uint16_t xmit_quota; /* Total ACL quota for light stack */ + uint16_t acl_data_size; /* Max ACL data size across HCI transport */ + uint16_t stream_mtu; + uint16_t local_cid; + uint16_t remote_cid; + uint16_t lm_handle; + uint8_t is_flushable; /* true if flushable channel */ + uint32_t stream_source; + uint8_t codec_info[10]; /* Codec capabilities array */ +} bt_vendor_op_a2dp_offload_t; + +/* + * Bluetooth Host/Controller VENDOR Interface + */ +typedef struct { + /** Set to sizeof(bt_vndor_interface_t) */ + size_t size; + + /* + * Functions need to be implemented in Vendor libray (libbt-vendor.so). + */ + + /** + * Caller will open the interface and pass in the callback routines + * to the implemenation of this interface. + */ + int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char* local_bdaddr); + + /** Vendor specific operations */ + int (*op)(bt_vendor_opcode_t opcode, void* param); + + /** Closes the interface */ + void (*cleanup)(void); +} bt_vendor_interface_t; + +/* + * External shared lib functions/data + */ + +/* Entry point of DLib -- + * Vendor library needs to implement the body of bt_vendor_interface_t + * structure and uses the below name as the variable name. HCI library + * will use this symbol name to get address of the object through the + * dlsym call. + */ +extern const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE; + +// MODIFICATION FOR NEW HAL/HIDL IMPLEMENTATION: +// EXPOSE THE BT_HDR STRUCT HERE FOR THE VENDOR INTERFACE +// ONLY, WITHOUT REQUIRING INCLUDES FROM system/bt OR OTHER +// DIRECTORIES. +// ONLY USED INSIDE transmit_cb. +// DO NOT USE IN NEW HAL IMPLEMENTATIONS GOING FORWARD +typedef struct +{ + uint16_t event; + uint16_t len; + uint16_t offset; + uint16_t layer_specific; + uint8_t data[]; +} HC_BT_HDR; +// /MODIFICATION + +#ifdef __cplusplus +} +#endif + +#endif /* BT_VENDOR_LIB_H */ diff --git a/bluetooth/1.0/default/hci_internals.h b/bluetooth/1.0/default/hci_internals.h new file mode 100644 index 0000000000..d839590f6a --- /dev/null +++ b/bluetooth/1.0/default/hci_internals.h @@ -0,0 +1,44 @@ +// +// 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 + +// 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; diff --git a/bluetooth/1.0/default/service.cpp b/bluetooth/1.0/default/service.cpp new file mode 100644 index 0000000000..a3c3cad14a --- /dev/null +++ b/bluetooth/1.0/default/service.cpp @@ -0,0 +1,29 @@ +// +// 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-service" + +#include + +#include + +// Generated HIDL files +using android::hardware::bluetooth::V1_0::IBluetoothHci; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation("bluetooth"); +} diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc new file mode 100644 index 0000000000..7efd5bdad0 --- /dev/null +++ b/bluetooth/1.0/default/vendor_interface.cc @@ -0,0 +1,351 @@ +// +// 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 +#include + +#include + +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; + +tINT_CMD_CBACK internal_command_cb; +VendorInterface* g_vendor_interface = nullptr; + +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 android::hardware::hidl_vec& packet) { + size_t offset = packet_length_offset_for_type[type]; + if (type == HCI_PACKET_TYPE_ACL_DATA) { + return (((packet[offset + 1]) << 8) | packet[offset]); + } + return packet[offset]; +} + +HC_BT_HDR* WrapPacketAndCopy(uint16_t event, + const android::hardware::hidl_vec& data) { + size_t packet_size = data.size() + sizeof(HC_BT_HDR); + HC_BT_HDR* packet = reinterpret_cast(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 enusred to + // be the only way the data is accessed, a pointer could be passed here... + memcpy(packet->data, data.data(), data.size()); + return packet; +} + +uint8_t transmit_cb(uint16_t opcode, void* buffer, tINT_CMD_CBACK callback) { + ALOGV("%s opcode: 0x%04x, ptr: %p", __func__, opcode, buffer); + HC_BT_HDR* bt_hdr = reinterpret_cast(buffer); + + internal_command_cb = callback; + uint8_t type = HCI_PACKET_TYPE_COMMAND; + VendorInterface::get()->SendPrivate(&type, 1); + VendorInterface::get()->SendPrivate(bt_hdr->data, bt_hdr->len); + return true; +} + +void firmware_config_cb(bt_vendor_op_result_t result) { + ALOGD("%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(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 { + +bool VendorInterface::Initialize(PacketReadCallback packet_read_cb) { + assert(!g_vendor_interface); + g_vendor_interface = new VendorInterface(); + return g_vendor_interface->Open(packet_read_cb); +} + +void VendorInterface::Shutdown() { + CHECK(g_vendor_interface); + g_vendor_interface->Close(); + delete g_vendor_interface; + g_vendor_interface = nullptr; +} + +VendorInterface* VendorInterface::get() { return g_vendor_interface; } + +bool VendorInterface::Open(PacketReadCallback packet_read_cb) { + // TODO(eisenbach): P0 - get local BD address somehow + uint8_t local_bda[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; + + firmware_configured_ = false; + packet_read_cb_ = packet_read_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( + 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; + } + + 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 cycle chip + + int power_state = BT_VND_PWR_OFF; + lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state); + power_state = BT_VND_PWR_ON; + lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state); + + // Get the UART socket + + 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; + } + + uart_fd_ = fd_list[0]; + if (uart_fd_ == INVALID_FD) { + ALOGE("%s unable to determine UART fd", __func__); + return false; + } + + ALOGD("%s UART fd: %d", __func__, uart_fd_); + + fd_watcher_.WatchFdForNonBlockingReads(uart_fd_, + [this](int fd) { OnDataReady(fd); }); + + // Start configuring the firmware + lib_interface_->op(BT_VND_OP_FW_CFG, nullptr); + + return true; +} + +void VendorInterface::Close() { + fd_watcher_.StopWatchingFileDescriptor(); + + if (lib_interface_ != nullptr) { + 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); + } + + if (lib_handle_ != nullptr) { + dlclose(lib_handle_); + lib_handle_ = nullptr; + } + + firmware_configured_ = false; +} + +size_t VendorInterface::Send(const uint8_t* data, size_t length) { + if (firmware_configured_ && queued_data_.size() == 0) + return SendPrivate(data, length); + + if (!firmware_configured_) { + ALOGI("%s queueing command", __func__); + queued_data_.resize(queued_data_.size() + length); + uint8_t* append_ptr = &queued_data_[queued_data_.size() - length]; + memcpy(append_ptr, data, length); + return length; + } + + ALOGI("%s sending queued command", __func__); + SendPrivate(queued_data_.data(), queued_data_.size()); + queued_data_.resize(0); + + ALOGI("%s done sending queued command", __func__); + + return SendPrivate(data, length); +} + +size_t VendorInterface::SendPrivate(const uint8_t* data, size_t length) { + if (uart_fd_ == INVALID_FD) return 0; + + size_t transmitted_length = 0; + while (length > 0) { + ssize_t ret = + TEMP_FAILURE_RETRY(write(uart_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; +} + +void VendorInterface::OnFirmwareConfigured(uint8_t result) { + ALOGI("%s: result = %d", __func__, result); + firmware_configured_ = true; + VendorInterface::get()->Send(NULL, 0); +} + +void VendorInterface::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(buffer[0]); + // TODO(eisenbach): Check for workaround(s) + CHECK(hci_packet_type_ >= HCI_PACKET_TYPE_ACL_DATA && + hci_packet_type_ <= HCI_PACKET_TYPE_EVENT) + << "buffer[0] = " << buffer[0]; + hci_parser_state_ = HCI_TYPE_READY; + hci_packet_.resize(HCI_PREAMBLE_SIZE_MAX); + hci_packet_bytes_remaining_ = preamble_size_for_type[hci_packet_type_]; + hci_packet_bytes_read_ = 0; + break; + } + + case HCI_TYPE_READY: { + size_t bytes_read = TEMP_FAILURE_RETRY( + read(fd, hci_packet_.data() + hci_packet_bytes_read_, + hci_packet_bytes_remaining_)); + CHECK(bytes_read > 0); + hci_packet_bytes_remaining_ -= bytes_read; + hci_packet_bytes_read_ += bytes_read; + if (hci_packet_bytes_remaining_ == 0) { + size_t packet_length = + HciGetPacketLengthForType(hci_packet_type_, hci_packet_); + hci_packet_.resize(preamble_size_for_type[hci_packet_type_] + + packet_length); + hci_packet_bytes_remaining_ = packet_length; + hci_parser_state_ = HCI_PAYLOAD; + hci_packet_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_)); + hci_packet_bytes_remaining_ -= bytes_read; + hci_packet_bytes_read_ += bytes_read; + if (hci_packet_bytes_remaining_ == 0) { + if (firmware_configured_) { + if (packet_read_cb_ != nullptr) { + packet_read_cb_(hci_packet_type_, hci_packet_); + } + } else { + if (internal_command_cb != nullptr) { + HC_BT_HDR* bt_hdr = + WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet_); + internal_command_cb(bt_hdr); + } + } + hci_parser_state_ = HCI_IDLE; + } + break; + } + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h new file mode 100644 index 0000000000..133c51bff3 --- /dev/null +++ b/bluetooth/1.0/default/vendor_interface.h @@ -0,0 +1,82 @@ +// +// 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 + +#include "async_fd_watcher.h" +#include "bt_vendor_lib.h" +#include "hci_internals.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::hidl_vec; +using PacketReadCallback = std::function&)>; + +class VendorInterface { + public: + static bool Initialize(PacketReadCallback packet_read_cb); + static void Shutdown(); + static VendorInterface* get(); + + size_t Send(const uint8_t *data, size_t length); + + void OnFirmwareConfigured(uint8_t result); + + // Actually send the data. + size_t SendPrivate(const uint8_t *data, size_t length); + + private: + VendorInterface() { queued_data_.resize(0); } + virtual ~VendorInterface() = default; + + bool Open(PacketReadCallback packet_read_cb); + void Close(); + + void OnDataReady(int fd); + + // Queue data from Send() until the interface is ready. + hidl_vec queued_data_; + + void *lib_handle_; + bt_vendor_interface_t *lib_interface_; + AsyncFdWatcher fd_watcher_; + int uart_fd_; + PacketReadCallback packet_read_cb_; + bool firmware_configured_; + + enum HciParserState { + HCI_IDLE, + HCI_TYPE_READY, + HCI_PAYLOAD + }; + HciParserState hci_parser_state_{HCI_IDLE}; + HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN}; + hidl_vec hci_packet_; + size_t hci_packet_bytes_remaining_; + size_t hci_packet_bytes_read_; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/1.0/vts/functional/Android.bp b/bluetooth/1.0/vts/functional/Android.bp new file mode 100644 index 0000000000..7d0473648a --- /dev/null +++ b/bluetooth/1.0/vts/functional/Android.bp @@ -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_test { + name: "bluetooth_hidl_hal_test", + gtest: true, + srcs: ["bluetooth_hidl_hal_test.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libnativehelper", + "libutils", + "android.hardware.bluetooth@1.0", + ], + static_libs: ["libgtest"], + cflags: [ + "--coverage", + "-O0", + "-g", + ], + ldflags: [ + "--coverage", + ], +} diff --git a/bluetooth/1.0/vts/functional/bluetooth_hidl_hal_test.cpp b/bluetooth/1.0/vts/functional/bluetooth_hidl_hal_test.cpp new file mode 100644 index 0000000000..b05e22b477 --- /dev/null +++ b/bluetooth/1.0/vts/functional/bluetooth_hidl_hal_test.cpp @@ -0,0 +1,692 @@ +/* + * 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. + */ + +#define LOG_TAG "bluetooth_hidl_hal_test" +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using ::android::hardware::bluetooth::V1_0::IBluetoothHci; +using ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks; +using ::android::hardware::bluetooth::V1_0::Status; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +#define Bluetooth_HCI_SERVICE_NAME "bluetooth" + +#define HCI_MINIMUM_HCI_VERSION 5 // Bluetooth Core Specification 3.0 + HS +#define HCI_MINIMUM_LMP_VERSION 5 // Bluetooth Core Specification 3.0 + HS +#define NUM_HCI_COMMANDS_BANDWIDTH 1000 +#define NUM_SCO_PACKETS_BANDWIDTH 1000 +#define NUM_ACL_PACKETS_BANDWIDTH 1000 +#define WAIT_FOR_HCI_EVENT_TIMEOUT std::chrono::milliseconds(2000) +#define WAIT_FOR_SCO_DATA_TIMEOUT std::chrono::milliseconds(1000) +#define WAIT_FOR_ACL_DATA_TIMEOUT std::chrono::milliseconds(1000) + +#define COMMAND_HCI_SHOULD_BE_UNKNOWN \ + { 0xff, 0x3B, 0x08, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 } +#define COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION \ + { 0x01, 0x10, 0x00 } +#define COMMAND_HCI_READ_BUFFER_SIZE \ + { 0x05, 0x10, 0x00 } +#define COMMAND_HCI_WRITE_LOOPBACK_MODE_LOCAL \ + { 0x02, 0x18, 0x01, 0x01 } +#define COMMAND_HCI_RESET \ + { 0x03, 0x0c, 0x00 } +#define COMMAND_HCI_WRITE_LOCAL_NAME \ + { 0x13, 0x0c, 0xf8 } +#define HCI_STATUS_SUCCESS 0x00 +#define HCI_STATUS_UNKNOWN_HCI_COMMAND 0x01 + +#define EVENT_CONNECTION_COMPLETE 0x03 +#define EVENT_COMMAND_COMPLETE 0x0e +#define EVENT_COMMAND_STATUS 0x0f +#define EVENT_NUMBER_OF_COMPLETED_PACKETS 0x13 +#define EVENT_LOOPBACK_COMMAND 0x19 + +#define EVENT_CODE_BYTE 0 +#define EVENT_LENGTH_BYTE 1 +#define EVENT_FIRST_PAYLOAD_BYTE 2 +#define EVENT_COMMAND_STATUS_STATUS_BYTE 2 +#define EVENT_COMMAND_STATUS_ALLOWED_PACKETS_BYTE 3 +#define EVENT_COMMAND_STATUS_OPCODE_LSBYTE 4 // Bytes 4 and 5 +#define EVENT_COMMAND_COMPLETE_ALLOWED_PACKETS_BYTE 2 +#define EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE 3 // Bytes 3 and 4 +#define EVENT_COMMAND_COMPLETE_STATUS_BYTE 5 +#define EVENT_COMMAND_COMPLETE_FIRST_PARAM_BYTE 6 +#define EVENT_LOCAL_HCI_VERSION_BYTE EVENT_COMMAND_COMPLETE_FIRST_PARAM_BYTE +#define EVENT_LOCAL_LMP_VERSION_BYTE EVENT_LOCAL_HCI_VERSION_BYTE + 3 + +#define EVENT_CONNECTION_COMPLETE_PARAM_LENGTH 11 +#define EVENT_CONNECTION_COMPLETE_TYPE 11 +#define EVENT_CONNECTION_COMPLETE_TYPE_SCO 0 +#define EVENT_CONNECTION_COMPLETE_TYPE_ACL 1 +#define EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE 3 +#define EVENT_COMMAND_STATUS_LENGTH 4 + +#define EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES 2 + +#define ACL_BROADCAST_ACTIVE_SLAVE (0x1 << 4) +#define ACL_PACKET_BOUNDARY_COMPLETE (0x3 << 6) + +class ThroughputLogger { + public: + ThroughputLogger(std::string task) + : task_(task), start_time_(std::chrono::steady_clock::now()) {} + + ~ThroughputLogger() { + if (total_bytes_ == 0) return; + std::chrono::duration duration = + std::chrono::steady_clock::now() - start_time_; + double s = duration.count(); + if (s == 0) return; + double rate_kb = (static_cast(total_bytes_) / s) / 1024; + ALOGD("%s %.1f KB/s (%zu bytes in %.3fs)", task_.c_str(), rate_kb, + total_bytes_, s); + } + + void setTotalBytes(size_t total_bytes) { total_bytes_ = total_bytes; } + + private: + size_t total_bytes_; + std::string task_; + std::chrono::steady_clock::time_point start_time_; +}; + +// The main test class for Bluetooth HIDL HAL. +class BluetoothHidlTest : public ::testing::Test { + public: + virtual void SetUp() override { + // currently test passthrough mode only + bluetooth = IBluetoothHci::getService(Bluetooth_HCI_SERVICE_NAME); + ALOGW("%s: getService(%s) is %s", __func__, Bluetooth_HCI_SERVICE_NAME, + bluetooth->isRemote() ? "remote" : "local"); + ASSERT_NE(bluetooth, nullptr); + + // TODO(b/31748996) A client must be completely unaware of the + // implementation details of its HAL: whether the HAL is passthrough, or + // whether it uses HWbinder or some other transport. + if (bluetooth->isRemote()) { + ::android::hardware::ProcessState::self()->setThreadPoolMaxThreadCount(1); + ::android::hardware::ProcessState::self()->startThreadPool(); + } + + bluetooth_cb = new BluetoothHciCallbacks(*this); + ASSERT_NE(bluetooth_cb, nullptr); + + max_acl_data_packet_length = 0; + max_sco_data_packet_length = 0; + max_acl_data_packets = 0; + max_sco_data_packets = 0; + + event_count = 0; + acl_count = 0; + sco_count = 0; + event_cb_count = 0; + acl_cb_count = 0; + sco_cb_count = 0; + + // Collision with android::hardware::Status + EXPECT_EQ(android::hardware::bluetooth::V1_0::Status::SUCCESS, + bluetooth->initialize(bluetooth_cb)); + } + + virtual void TearDown() override { + bluetooth->close(); + EXPECT_EQ(static_cast(0), event_queue.size()); + EXPECT_EQ(static_cast(0), sco_queue.size()); + EXPECT_EQ(static_cast(0), acl_queue.size()); + } + + void setBufferSizes(); + + // Functions called from within tests in loopback mode + void sendAndCheckHCI(int num_packets); + void sendAndCheckSCO(int num_packets, size_t size, uint16_t handle); + void sendAndCheckACL(int num_packets, size_t size, uint16_t handle); + + // Helper functions to try to get a handle on verbosity + void enterLoopbackMode(std::vector& sco_handles, + std::vector& acl_handles); + void wait_for_command_complete_event(hidl_vec cmd); + int wait_for_completed_packets_event(uint16_t handle); + + // Inform the test about an event callback + inline void notify_event_received() { + std::unique_lock lock(event_mutex); + event_count++; + event_condition.notify_one(); + } + + // Test code calls this function to wait for an event callback + inline void wait_for_event() { + std::unique_lock lock(event_mutex); + + auto start_time = std::chrono::steady_clock::now(); + while (event_count == 0) + if (event_condition.wait_until(lock, + start_time + WAIT_FOR_HCI_EVENT_TIMEOUT) == + std::cv_status::timeout) + return; + event_count--; + } + + // Inform the test about an acl data callback + inline void notify_acl_data_received() { + std::unique_lock lock(acl_mutex); + acl_count++; + acl_condition.notify_one(); + } + + // Test code calls this function to wait for an acl data callback + inline void wait_for_acl() { + std::unique_lock lock(acl_mutex); + + while (acl_count == 0) + acl_condition.wait_until( + lock, std::chrono::steady_clock::now() + WAIT_FOR_ACL_DATA_TIMEOUT); + acl_count--; + } + + // Inform the test about a sco data callback + inline void notify_sco_data_received() { + std::unique_lock lock(sco_mutex); + sco_count++; + sco_condition.notify_one(); + } + + // Test code calls this function to wait for a sco data callback + inline void wait_for_sco() { + std::unique_lock lock(sco_mutex); + + while (sco_count == 0) + sco_condition.wait_until( + lock, std::chrono::steady_clock::now() + WAIT_FOR_SCO_DATA_TIMEOUT); + sco_count--; + } + + // A simple test implementation of BluetoothHciCallbacks. + class BluetoothHciCallbacks : public IBluetoothHciCallbacks { + BluetoothHidlTest& parent_; + + public: + BluetoothHciCallbacks(BluetoothHidlTest& parent) : parent_(parent){}; + + virtual ~BluetoothHciCallbacks() = default; + + Return hciEventReceived( + const ::android::hardware::hidl_vec& event) override { + parent_.event_cb_count++; + parent_.event_queue.push(event); + parent_.notify_event_received(); + ALOGV("Event received (length = %d)", static_cast(event.size())); + return Void(); + }; + + Return aclDataReceived( + const ::android::hardware::hidl_vec& data) override { + parent_.acl_cb_count++; + parent_.acl_queue.push(data); + parent_.notify_acl_data_received(); + return Void(); + }; + + Return scoDataReceived( + const ::android::hardware::hidl_vec& data) override { + parent_.sco_cb_count++; + parent_.sco_queue.push(data); + parent_.notify_sco_data_received(); + return Void(); + }; + }; + + sp bluetooth; + sp bluetooth_cb; + std::queue> event_queue; + std::queue> acl_queue; + std::queue> sco_queue; + + int event_cb_count; + int sco_cb_count; + int acl_cb_count; + + int max_acl_data_packet_length; + int max_sco_data_packet_length; + int max_acl_data_packets; + int max_sco_data_packets; + + private: + std::mutex event_mutex; + std::mutex sco_mutex; + std::mutex acl_mutex; + std::condition_variable event_condition; + std::condition_variable sco_condition; + std::condition_variable acl_condition; + int event_count; + int sco_count; + int acl_count; +}; + +// A class for test environment setup (kept since this file is a template). +class BluetoothHidlEnvironment : public ::testing::Environment { + public: + virtual void SetUp() {} + virtual void TearDown() {} + + private: +}; + +// Receive and check status events until a COMMAND_COMPLETE is received. +void BluetoothHidlTest::wait_for_command_complete_event(hidl_vec cmd) { + // Allow intermediate COMMAND_STATUS events + int status_event_count = 0; + hidl_vec event; + do { + wait_for_event(); + EXPECT_LT(static_cast(0), event_queue.size()); + if (event_queue.size() == 0) { + event.resize(0); + break; + } + event = event_queue.front(); + event_queue.pop(); + EXPECT_GT(event.size(), + static_cast(EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1)); + if (event[EVENT_CODE_BYTE] == EVENT_COMMAND_STATUS) { + EXPECT_EQ(EVENT_COMMAND_STATUS_LENGTH, event[EVENT_LENGTH_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1]); + EXPECT_EQ(event[EVENT_COMMAND_STATUS_STATUS_BYTE], HCI_STATUS_SUCCESS); + status_event_count++; + } + } while (event.size() > 0 && event[EVENT_CODE_BYTE] == EVENT_COMMAND_STATUS); + + EXPECT_GT(event.size(), + static_cast(EVENT_COMMAND_COMPLETE_STATUS_BYTE)); + EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]); +} + +// Send the command to read the controller's buffer sizes. +void BluetoothHidlTest::setBufferSizes() { + hidl_vec cmd = COMMAND_HCI_READ_BUFFER_SIZE; + bluetooth->sendHciCommand(cmd); + + wait_for_event(); + + EXPECT_LT(static_cast(0), event_queue.size()); + if (event_queue.size() == 0) return; + + hidl_vec event = event_queue.front(); + event_queue.pop(); + + EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]); + + max_acl_data_packet_length = + event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 1] + + (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 2] << 8); + max_sco_data_packet_length = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 3]; + max_acl_data_packets = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 4] + + (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 5] << 8); + max_sco_data_packets = event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 6] + + (event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 7] << 8); + + ALOGD("%s: ACL max %d num %d SCO max %d num %d", __func__, + static_cast(max_acl_data_packet_length), + static_cast(max_acl_data_packets), + static_cast(max_sco_data_packet_length), + static_cast(max_sco_data_packets)); +} + +// Send an HCI command (in Loopback mode) and check the response. +void BluetoothHidlTest::sendAndCheckHCI(int num_packets) { + ThroughputLogger logger = {__func__}; + for (int n = 0; n < num_packets; n++) { + // Send an HCI packet + std::vector write_name = COMMAND_HCI_WRITE_LOCAL_NAME; + // With a name + char new_name[] = "John Jacob Jingleheimer Schmidt ___________________0"; + size_t new_name_length = strlen(new_name); + for (size_t i = 0; i < new_name_length; i++) + write_name.push_back(static_cast(new_name[i])); + // And the packet number + { + size_t i = new_name_length - 1; + for (int digits = n; digits > 0; digits = digits / 10, i--) + write_name[i] = static_cast('0' + digits % 10); + } + // And padding + for (size_t i = 0; i < 248 - new_name_length; i++) + write_name.push_back(static_cast(0)); + + hidl_vec cmd = write_name; + bluetooth->sendHciCommand(cmd); + + // Check the loopback of the HCI packet + wait_for_event(); + hidl_vec event = event_queue.front(); + event_queue.pop(); + size_t compare_length = + (cmd.size() > static_cast(0xff) ? static_cast(0xff) + : cmd.size()); + EXPECT_GT(event.size(), compare_length + EVENT_FIRST_PAYLOAD_BYTE - 1); + + EXPECT_EQ(EVENT_LOOPBACK_COMMAND, event[EVENT_CODE_BYTE]); + EXPECT_EQ(compare_length, event[EVENT_LENGTH_BYTE]); + if (n == 0) logger.setTotalBytes(cmd.size() * num_packets * 2); + + for (size_t i = 0; i < compare_length; i++) + EXPECT_EQ(cmd[i], event[EVENT_FIRST_PAYLOAD_BYTE + i]); + } +} + +// Send a SCO data packet (in Loopback mode) and check the response. +void BluetoothHidlTest::sendAndCheckSCO(int num_packets, size_t size, + uint16_t handle) { + ThroughputLogger logger = {__func__}; + for (int n = 0; n < num_packets; n++) { + // Send a SCO packet + hidl_vec sco_packet; + std::vector sco_vector; + sco_vector.push_back(static_cast(handle & 0xff)); + sco_vector.push_back(static_cast((handle & 0x0f00) >> 8)); + sco_vector.push_back(static_cast(size & 0xff)); + sco_vector.push_back(static_cast((size & 0xff00) >> 8)); + for (size_t i = 0; i < size; i++) { + sco_vector.push_back(static_cast(i + n)); + } + sco_packet = sco_vector; + bluetooth->sendScoData(sco_vector); + + // Check the loopback of the SCO packet + wait_for_sco(); + hidl_vec sco_loopback = sco_queue.front(); + sco_queue.pop(); + + EXPECT_EQ(sco_packet.size(), sco_loopback.size()); + size_t successful_bytes = 0; + + if (n == 0) logger.setTotalBytes(num_packets * size * 2); + + for (size_t i = 0; i < sco_packet.size(); i++) { + if (sco_packet[i] == sco_loopback[i]) { + successful_bytes = i; + } else { + ALOGE("Miscompare at %d (expected %x, got %x)", static_cast(i), + sco_packet[i], sco_loopback[i]); + ALOGE("At %d (expected %x, got %x)", static_cast(i + 1), + sco_packet[i + 1], sco_loopback[i + 1]); + break; + } + } + EXPECT_EQ(sco_packet.size(), successful_bytes + 1); + } +} + +// Send an ACL data packet (in Loopback mode) and check the response. +void BluetoothHidlTest::sendAndCheckACL(int num_packets, size_t size, + uint16_t handle) { + ThroughputLogger logger = {__func__}; + for (int n = 0; n < num_packets; n++) { + // Send an ACL packet + hidl_vec acl_packet; + std::vector acl_vector; + acl_vector.push_back(static_cast(handle & 0xff)); + acl_vector.push_back(static_cast((handle & 0x0f00) >> 8) | + ACL_BROADCAST_ACTIVE_SLAVE | + ACL_PACKET_BOUNDARY_COMPLETE); + acl_vector.push_back(static_cast(size & 0xff)); + acl_vector.push_back(static_cast((size & 0xff00) >> 8)); + for (size_t i = 0; i < size; i++) { + acl_vector.push_back(static_cast(i + n)); + } + acl_packet = acl_vector; + bluetooth->sendAclData(acl_vector); + + // Check the loopback of the ACL packet + wait_for_acl(); + hidl_vec acl_loopback = acl_queue.front(); + acl_queue.pop(); + + EXPECT_EQ(acl_packet.size(), acl_loopback.size()); + size_t successful_bytes = 0; + + if (n == 0) logger.setTotalBytes(num_packets * size * 2); + + for (size_t i = 0; i < acl_packet.size(); i++) { + if (acl_packet[i] == acl_loopback[i]) { + successful_bytes = i; + } else { + ALOGE("Miscompare at %d (expected %x, got %x)", static_cast(i), + acl_packet[i], acl_loopback[i]); + ALOGE("At %d (expected %x, got %x)", static_cast(i + 1), + acl_packet[i + 1], acl_loopback[i + 1]); + break; + } + } + EXPECT_EQ(acl_packet.size(), successful_bytes + 1); + } +} + +// Return the number of completed packets reported by the controller. +int BluetoothHidlTest::wait_for_completed_packets_event(uint16_t handle) { + wait_for_event(); + int packets_processed = 0; + while (event_queue.size() > 0) { + hidl_vec event = event_queue.front(); + event_queue.pop(); + + EXPECT_EQ(EVENT_NUMBER_OF_COMPLETED_PACKETS, event[EVENT_CODE_BYTE]); + EXPECT_EQ(1, event[EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES]); + + uint16_t event_handle = event[3] + (event[4] << 8); + EXPECT_EQ(handle, event_handle); + + packets_processed += event[5] + (event[6] << 8); + } + return packets_processed; +} + +// Send local loopback command and initialize SCO and ACL handles. +void BluetoothHidlTest::enterLoopbackMode(std::vector& sco_handles, + std::vector& acl_handles) { + hidl_vec cmd = COMMAND_HCI_WRITE_LOOPBACK_MODE_LOCAL; + bluetooth->sendHciCommand(cmd); + + // Receive connection complete events with data channels + int connection_event_count = 0; + hidl_vec event; + do { + wait_for_event(); + event = event_queue.front(); + event_queue.pop(); + EXPECT_GT(event.size(), + static_cast(EVENT_COMMAND_COMPLETE_STATUS_BYTE)); + if (event[EVENT_CODE_BYTE] == EVENT_CONNECTION_COMPLETE) { + EXPECT_GT(event.size(), + static_cast(EVENT_CONNECTION_COMPLETE_TYPE)); + EXPECT_EQ(event[EVENT_LENGTH_BYTE], + EVENT_CONNECTION_COMPLETE_PARAM_LENGTH); + uint8_t connection_type = event[EVENT_CONNECTION_COMPLETE_TYPE]; + + EXPECT_TRUE(connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO || + connection_type == EVENT_CONNECTION_COMPLETE_TYPE_ACL); + + // Save handles + uint16_t handle = event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE] | + event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE + 1] << 8; + if (connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO) + sco_handles.push_back(handle); + else + acl_handles.push_back(handle); + + ALOGD("Connect complete type = %d handle = %d", + event[EVENT_CONNECTION_COMPLETE_TYPE], handle); + connection_event_count++; + } + } while (event[EVENT_CODE_BYTE] == EVENT_CONNECTION_COMPLETE); + + EXPECT_GT(connection_event_count, 0); + + EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]); +} + +// Empty test: Initialize()/Close() are called in SetUp()/TearDown(). +TEST_F(BluetoothHidlTest, InitializeAndClose) { } + +// Send an HCI Reset with sendHciCommand and wait for a command complete event. +TEST_F(BluetoothHidlTest, HciReset) { + hidl_vec cmd = COMMAND_HCI_RESET; + bluetooth->sendHciCommand(cmd); + + wait_for_command_complete_event(cmd); +} + +// Read and check the HCI version of the controller. +TEST_F(BluetoothHidlTest, HciVersionTest) { + hidl_vec cmd = COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION; + bluetooth->sendHciCommand(cmd); + + wait_for_event(); + + hidl_vec event = event_queue.front(); + event_queue.pop(); + EXPECT_GT(event.size(), static_cast(EVENT_LOCAL_LMP_VERSION_BYTE)); + + EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]); + + EXPECT_LE(HCI_MINIMUM_HCI_VERSION, event[EVENT_LOCAL_HCI_VERSION_BYTE]); + EXPECT_LE(HCI_MINIMUM_LMP_VERSION, event[EVENT_LOCAL_LMP_VERSION_BYTE]); +} + +// Send an unknown HCI command and wait for the error message. +TEST_F(BluetoothHidlTest, HciUnknownCommand) { + hidl_vec cmd = COMMAND_HCI_SHOULD_BE_UNKNOWN; + bluetooth->sendHciCommand(cmd); + + wait_for_event(); + + hidl_vec event = event_queue.front(); + event_queue.pop(); + EXPECT_GT(event.size(), + static_cast(EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1)); + + EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]); + EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]); + EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]); + EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND, + event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]); +} + +// Enter loopback mode, but don't send any packets. +TEST_F(BluetoothHidlTest, WriteLoopbackMode) { + std::vector sco_connection_handles; + std::vector acl_connection_handles; + enterLoopbackMode(sco_connection_handles, acl_connection_handles); +} + +// Enter loopback mode and send single packets. +TEST_F(BluetoothHidlTest, LoopbackModeSinglePackets) { + setBufferSizes(); + EXPECT_LT(0, max_sco_data_packet_length); + EXPECT_LT(0, max_acl_data_packet_length); + + std::vector sco_connection_handles; + std::vector acl_connection_handles; + enterLoopbackMode(sco_connection_handles, acl_connection_handles); + + sendAndCheckHCI(1); + + // This should work, but breaks on some current platforms. Figure out how to + // grandfather older devices but test new ones. + int sco_packets_sent = 0; + if (0 && sco_connection_handles.size() > 0) { + sendAndCheckSCO(1, max_sco_data_packet_length, sco_connection_handles[0]); + sco_packets_sent = 1; + EXPECT_EQ(sco_packets_sent, + wait_for_completed_packets_event(sco_connection_handles[0])); + } + + int acl_packets_sent = 0; + if (acl_connection_handles.size() > 0) { + sendAndCheckACL(1, max_acl_data_packet_length, acl_connection_handles[0]); + acl_packets_sent = 1; + EXPECT_EQ(acl_packets_sent, + wait_for_completed_packets_event(acl_connection_handles[0])); + } +} + +// Enter loopback mode and send packets for bandwidth measurements. +TEST_F(BluetoothHidlTest, LoopbackModeBandwidth) { + setBufferSizes(); + + std::vector sco_connection_handles; + std::vector acl_connection_handles; + enterLoopbackMode(sco_connection_handles, acl_connection_handles); + + sendAndCheckHCI(NUM_HCI_COMMANDS_BANDWIDTH); + + // This should work, but breaks on some current platforms. Figure out how to + // grandfather older devices but test new ones. + int sco_packets_sent = 0; + if (0 && sco_connection_handles.size() > 0) { + sendAndCheckSCO(NUM_SCO_PACKETS_BANDWIDTH, max_sco_data_packet_length, + sco_connection_handles[0]); + sco_packets_sent = NUM_SCO_PACKETS_BANDWIDTH; + EXPECT_EQ(sco_packets_sent, + wait_for_completed_packets_event(sco_connection_handles[0])); + } + + int acl_packets_sent = 0; + if (acl_connection_handles.size() > 0) { + sendAndCheckACL(NUM_ACL_PACKETS_BANDWIDTH, max_acl_data_packet_length, + acl_connection_handles[0]); + acl_packets_sent = NUM_ACL_PACKETS_BANDWIDTH; + EXPECT_EQ(acl_packets_sent, + wait_for_completed_packets_event(acl_connection_handles[0])); + } +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(new BluetoothHidlEnvironment); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} diff --git a/bluetooth/Android.bp b/bluetooth/Android.bp index bbb3e4bac0..ed19a37034 100644 --- a/bluetooth/Android.bp +++ b/bluetooth/Android.bp @@ -1,4 +1,6 @@ // This is an autogenerated file, do not edit. subdirs = [ "1.0", + "1.0/default", + "1.0/vts/functional", ]