From 73ad0310835f00d6c725091de990c271544c49a9 Mon Sep 17 00:00:00 2001 From: Myles Watson Date: Tue, 7 Mar 2017 04:28:51 -0800 Subject: [PATCH] test: Add a simulated Bluetooth HAL implementation Bug: 35672576 Test: Angler Bluetooth starts/stops with test HAL Android Cloud net_test_bluetooth tests pass Change-Id: I104e0dd3946f0efff9709e05c056bee3538394f7 --- test/Android.bp | 1 + test/rootcanal/Android.bp | 56 +++++++ .../android.hardware.bluetooth@1.0-service.sim.rc | 4 + test/rootcanal/bluetooth_hci.cc | 183 +++++++++++++++++++++ test/rootcanal/bluetooth_hci.h | 79 +++++++++ test/rootcanal/service.cc | 40 +++++ vendor_libs/test_vendor_lib/Android.bp | 40 +++++ 7 files changed, 403 insertions(+) create mode 100644 test/rootcanal/Android.bp create mode 100644 test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc create mode 100644 test/rootcanal/bluetooth_hci.cc create mode 100644 test/rootcanal/bluetooth_hci.h create mode 100644 test/rootcanal/service.cc diff --git a/test/Android.bp b/test/Android.bp index c873d78e5..8cf611e10 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -1,3 +1,4 @@ subdirs = [ + "rootcanal", "suite", ] diff --git a/test/rootcanal/Android.bp b/test/rootcanal/Android.bp new file mode 100644 index 000000000..d7438a0f6 --- /dev/null +++ b/test/rootcanal/Android.bp @@ -0,0 +1,56 @@ +// +// 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.sim", + proprietary: true, + relative_install_path: "hw", + srcs: [ + "bluetooth_hci.cc", + "service.cc", + ], + + shared_libs: [ + "android.hardware.bluetooth@1.0", + "libbase", + "libchrome", + "libcutils", + "libhardware", + "libhwbinder", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + cflags: [ + "-fvisibility=hidden", + "-Wall", + "-Wextra", + "-Werror", + "-DHAS_NO_BDROID_BUILDCFG", + ], + static_libs: [ + "android.hardware.bluetooth-async", + "android.hardware.bluetooth-hci", + "libbt-rootcanal", + ], + include_dirs: [ + "system/bt", + "system/bt/hci/include", + "system/bt/include", + "system/bt/stack/include", + ], + init_rc: ["android.hardware.bluetooth@1.0-service.sim.rc"], +} diff --git a/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc b/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc new file mode 100644 index 000000000..2f53e5dc6 --- /dev/null +++ b/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc @@ -0,0 +1,4 @@ +service bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service.sim + class hal + user bluetooth + group bluetooth diff --git a/test/rootcanal/bluetooth_hci.cc b/test/rootcanal/bluetooth_hci.cc new file mode 100644 index 000000000..413b31bf4 --- /dev/null +++ b/test/rootcanal/bluetooth_hci.cc @@ -0,0 +1,183 @@ +// +// 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.sim" + +#include "bluetooth_hci.h" + +#include +#include +#include + +#include "hci_internals.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace sim { + +using android::hardware::hidl_vec; +using test_vendor_lib::AsyncManager; +using test_vendor_lib::AsyncTaskId; +using test_vendor_lib::CommandPacket; +using test_vendor_lib::DualModeController; +using test_vendor_lib::EventPacket; +using test_vendor_lib::TaskCallback; +using test_vendor_lib::TestChannelTransport; + +class BluetoothDeathRecipient : public hidl_death_recipient { + public: + BluetoothDeathRecipient(const sp 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 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 BluetoothHci::initialize(const sp& cb) { + ALOGI("%s", __func__); + + if (cb == nullptr) { + ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)"); + return Void(); + } + + death_recipient_->setHasDied(false); + cb->linkToDeath(death_recipient_, 0); + + test_channel_transport_.RegisterCommandHandler( + [this](const std::string& name, const std::vector& args) { + async_manager_.ExecAsync( + std::chrono::milliseconds(0), [this, name, args]() { + controller_.HandleTestChannelCommand(name, args); + }); + }); + + controller_.RegisterEventChannel([cb](std::unique_ptr event) { + size_t header_bytes = event->GetHeaderSize(); + size_t payload_bytes = event->GetPayloadSize(); + hidl_vec hci_event; + hci_event.resize(header_bytes + payload_bytes); + memcpy(hci_event.data(), event->GetHeader().data(), header_bytes); + memcpy(hci_event.data() + header_bytes, event->GetPayload().data(), + payload_bytes); + + cb->hciEventReceived(hci_event); + }); + + /* RegisterAcl and RegisterSco + cb->aclDataReceived(hci_packet); + cb->scoDataReceived(hci_packet); + */ + + controller_.RegisterTaskScheduler( + [this](std::chrono::milliseconds delay, const TaskCallback& task) { + return async_manager_.ExecAsync(delay, task); + }); + + controller_.RegisterPeriodicTaskScheduler( + [this](std::chrono::milliseconds delay, std::chrono::milliseconds period, + const TaskCallback& task) { + return async_manager_.ExecAsyncPeriodically(delay, period, task); + }); + + controller_.RegisterTaskCancel( + [this](AsyncTaskId task) { async_manager_.CancelAsyncTask(task); }); + + SetUpTestChannel(6111); + + unlink_cb_ = [cb](sp& death_recipient) { + if (death_recipient->getHasDied()) + ALOGI("Skipping unlink call, service died."); + else + cb->unlinkToDeath(death_recipient); + }; + + cb->initializationComplete(Status::SUCCESS); + return Void(); +} + +Return BluetoothHci::close() { + ALOGI("%s", __func__); + return Void(); +} + +Return BluetoothHci::sendHciCommand(const hidl_vec& packet) { + async_manager_.ExecAsync(std::chrono::milliseconds(0), [this, packet]() { + uint16_t opcode = packet[0] | (packet[1] << 8); + std::unique_ptr command = + std::unique_ptr(new CommandPacket(opcode)); + for (size_t i = 3; i < packet.size(); i++) + command->AddPayloadOctets1(packet[i]); + + controller_.HandleCommand(std::move(command)); + }); + return Void(); +} + +Return BluetoothHci::sendAclData(const hidl_vec& /* packet */) { + CHECK(false) << __func__ << " not yet implemented"; + return Void(); +} + +Return BluetoothHci::sendScoData(const hidl_vec& /* packet */) { + CHECK(false) << __func__ << " not yet implemented"; + return Void(); +} + +void BluetoothHci::SetUpTestChannel(int port) { + int socket_fd = test_channel_transport_.SetUp(port); + + if (socket_fd == -1) { + ALOGE("Test channel SetUp(%d) failed.", port); + return; + } + + ALOGI("Test channel SetUp() successful"); + async_manager_.WatchFdForNonBlockingReads(socket_fd, [this](int socket_fd) { + int conn_fd = test_channel_transport_.Accept(socket_fd); + if (conn_fd < 0) { + ALOGE("Error watching test channel fd."); + return; + } + ALOGI("Test channel connection accepted."); + async_manager_.WatchFdForNonBlockingReads(conn_fd, [this](int conn_fd) { + test_channel_transport_.OnCommandReady(conn_fd, [this, conn_fd]() { + async_manager_.StopWatchingFileDescriptor(conn_fd); + }); + }); + }); +} + +} // namespace gce +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/test/rootcanal/bluetooth_hci.h b/test/rootcanal/bluetooth_hci.h new file mode 100644 index 000000000..2ddf8eea1 --- /dev/null +++ b/test/rootcanal/bluetooth_hci.h @@ -0,0 +1,79 @@ +// +// 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 + +#include + +#include "hci_packetizer.h" + +#include "async_manager.h" +#include "dual_mode_controller.h" +#include "test_channel_transport.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace sim { + +class BluetoothDeathRecipient; + +class BluetoothHci : public IBluetoothHci { + public: + BluetoothHci(); + + ::android::hardware::Return initialize( + const sp& cb) override; + + ::android::hardware::Return sendHciCommand( + const ::android::hardware::hidl_vec& packet) override; + + ::android::hardware::Return sendAclData( + const ::android::hardware::hidl_vec& packet) override; + + ::android::hardware::Return sendScoData( + const ::android::hardware::hidl_vec& packet) override; + + ::android::hardware::Return close() override; + + static void OnPacketReady(); + + static BluetoothHci* get(); + + private: + sp death_recipient_; + + std::function&)> unlink_cb_; + + void HandleIncomingPacket(); + + test_vendor_lib::AsyncManager async_manager_; + + void SetUpTestChannel(int port); + + test_vendor_lib::DualModeController controller_; + + test_vendor_lib::TestChannelTransport test_channel_transport_; +}; + +} // namespace sim +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/test/rootcanal/service.cc b/test/rootcanal/service.cc new file mode 100644 index 000000000..e08f73583 --- /dev/null +++ b/test/rootcanal/service.cc @@ -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.sim" + +#include +#include +#include +#include + +#include "bluetooth_hci.h" + +using ::android::hardware::configureRpcThreadpool; +using ::android::hardware::bluetooth::V1_0::IBluetoothHci; +using ::android::hardware::bluetooth::V1_0::sim::BluetoothHci; +using ::android::hardware::joinRpcThreadpool; +using ::android::sp; + +int main(int /* argc */, char** /* argv */) { + sp 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/test_vendor_lib/Android.bp b/vendor_libs/test_vendor_lib/Android.bp index 10f0a6434..5dd0bb43b 100644 --- a/vendor_libs/test_vendor_lib/Android.bp +++ b/vendor_libs/test_vendor_lib/Android.bp @@ -1,3 +1,43 @@ +// simulation library for testing virtual devices +// ======================================================== +cc_library_static { + name: "libbt-rootcanal", + proprietary: true, + srcs: [ + "src/async_manager.cc", + "src/bt_address.cc", + "src/command_packet.cc", + "src/dual_mode_controller.cc", + "src/event_packet.cc", + "src/packet.cc", + "src/packet_stream.cc", + "src/test_channel_transport.cc", + ], + cflags: [ + "-fvisibility=hidden", + "-Wall", + "-Wextra", + "-Werror", + "-DHAS_NO_BDROID_BUILDCFG", + ], + local_include_dirs: [ + "include", + ], + export_include_dirs: ["include"], + include_dirs: [ + "system/bt", + "system/bt/utils/include", + "system/bt/hci/include", + "system/bt/include", + "system/bt/stack/include", + ], + shared_libs: [ + "libbase", + "libchrome", + "liblog", + ], +} + // test-vendor unit tests for host // ======================================================== cc_test_host { -- 2.11.0