Merge "Implement Queue"
diff --git a/binder/android/bluetooth/IBluetooth.aidl b/binder/android/bluetooth/IBluetooth.aidl
index cc4c9cf..6bda14b 100644
--- a/binder/android/bluetooth/IBluetooth.aidl
+++ b/binder/android/bluetooth/IBluetooth.aidl
@@ -126,8 +126,8 @@
// For Metadata
boolean registerMetadataListener(in IBluetoothMetadataListener listener, in BluetoothDevice device);
boolean unregisterMetadataListener(in BluetoothDevice device);
- boolean setMetadata(in BluetoothDevice device, in int key, in String value);
- String getMetadata(in BluetoothDevice device, in int key);
+ boolean setMetadata(in BluetoothDevice device, in int key, in byte[] value);
+ byte[] getMetadata(in BluetoothDevice device, in int key);
/**
diff --git a/binder/android/bluetooth/IBluetoothMetadataListener.aidl b/binder/android/bluetooth/IBluetoothMetadataListener.aidl
index 13b5799..765b128 100644
--- a/binder/android/bluetooth/IBluetoothMetadataListener.aidl
+++ b/binder/android/bluetooth/IBluetoothMetadataListener.aidl
@@ -24,5 +24,5 @@
* @hide
*/
oneway interface IBluetoothMetadataListener {
- void onMetadataChanged(in BluetoothDevice devices, in int key, in String value);
+ void onMetadataChanged(in BluetoothDevice devices, in int key, in byte[] value);
}
diff --git a/gd/.gitignore b/gd/.gitignore
new file mode 100644
index 0000000..6cfa2da
--- /dev/null
+++ b/gd/.gitignore
@@ -0,0 +1 @@
+**/default.profraw
diff --git a/gd/Android.bp b/gd/Android.bp
index 5e50536..c1d4a0c 100644
--- a/gd/Android.bp
+++ b/gd/Android.bp
@@ -98,6 +98,7 @@
},
},
srcs: [
+ "stack_manager.cc",
":BluetoothCommonSources",
":BluetoothPacketSources",
]
diff --git a/gd/hal/hci_hal.h b/gd/hal/hci_hal.h
index 044da84..375af4b 100644
--- a/gd/hal/hci_hal.h
+++ b/gd/hal/hci_hal.h
@@ -25,17 +25,16 @@
enum class Status : int32_t { SUCCESS, TRANSPORT_ERROR, INITIALIZATION_ERROR, UNKNOWN };
-// Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHciCallbacks.hal in Android
+// Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHciCallbacks.hal in Android, but moved initializationComplete
+// callback to BluetoothInitializationCompleteCallback
+
// The interface from the Bluetooth Controller to the stack
class BluetoothHciHalCallbacks {
public:
virtual ~BluetoothHciHalCallbacks() = default;
- // Invoked when the Bluetooth controller initialization has been completed
- virtual void initializationComplete(Status status) = 0;
-
- // This function is invoked when an HCI event is received from the Bluetooth controller to be forwarded to the
- // Bluetooth stack
+ // This function is invoked when an HCI event is received from the
+ // Bluetooth controller to be forwarded to the Bluetooth stack
// @param event is the HCI event to be sent to the Bluetooth stack
virtual void hciEventReceived(HciPacket event) = 0;
@@ -48,6 +47,15 @@
virtual void scoDataReceived(HciPacket data) = 0;
};
+// Callback for BluetoothHciHal::initialize()
+class BluetoothInitializationCompleteCallback {
+ public:
+ virtual ~BluetoothInitializationCompleteCallback() = default;
+
+ // Invoked when the Bluetooth controller initialization has been completed
+ virtual void initializationComplete(Status status) = 0;
+};
+
// Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHci.hal in Android
// The Host Controller Interface (HCI) is the layer defined by the Bluetooth
// specification between the software that runs on the host and the Bluetooth
@@ -65,15 +73,25 @@
// required to communicate with the Bluetooth hardware in the
// device.
//
- // The |oninitializationComplete| callback must be invoked in response
+ // The |InitializationCompleteCallback| callback must be invoked in response
// to this function to indicate success before any other function
// (sendHciCommand, sendAclData, * sendScoData) is invoked on this
// interface.
//
- // @param callback implements IBluetoothHciCallbacks which will
+ // @param callback implements BluetoothInitializationCompleteCallback which will
+ // receive callbacks when incoming HCI initialization is complete
+ virtual void initialize(BluetoothInitializationCompleteCallback* callback) = 0;
+
+ // Register the callback for incoming packets. All incoming packets are dropped before
+ // this callback is registered. Callback can only be registered once, but will be reset
+ // after close().
+ //
+ // Call this function before initialize() to guarantee all incoming packets are received.
+ //
+ // @param callback implements BluetoothHciHalCallbacks which will
// receive callbacks when incoming HCI packets are received
// from the controller to be sent to the host.
- virtual void initialize(BluetoothHciHalCallbacks* callback) = 0;
+ virtual void registerIncomingPacketCallback(BluetoothHciHalCallbacks* callback) = 0;
// Send an HCI command (as specified in the Bluetooth Specification
// V4.2, Vol 2, Part 5, Section 5.4.1) to the Bluetooth controller.
diff --git a/gd/hal/hci_hal_android_hidl.cc b/gd/hal/hci_hal_android_hidl.cc
index 0431b38..95e4e4b 100644
--- a/gd/hal/hci_hal_android_hidl.cc
+++ b/gd/hal/hci_hal_android_hidl.cc
@@ -47,38 +47,55 @@
class HciHalBluetoothHciCallbacks : public IBluetoothHciCallbacks {
public:
- HciHalBluetoothHciCallbacks(BluetoothHciHalCallbacks* callback) : callback_(callback) {}
+ HciHalBluetoothHciCallbacks(BluetoothInitializationCompleteCallback* initialization_callback)
+ : initialization_callback_(initialization_callback) {}
+
+ void SetCallback(BluetoothHciHalCallbacks* callback) {
+ ASSERT(callback_ == nullptr && callback != nullptr);
+ callback_ = callback;
+ }
+
+ void ResetCallback() {
+ callback_ = nullptr;
+ }
Return<void> initializationComplete(HidlStatus status) {
ASSERT(status == HidlStatus::SUCCESS);
- callback_->initializationComplete(Status::SUCCESS);
+ initialization_callback_->initializationComplete(Status::SUCCESS);
return Void();
}
Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
- callback_->hciEventReceived(std::vector<uint8_t>(event.begin(), event.end()));
+ if (callback_ != nullptr) {
+ callback_->hciEventReceived(std::vector<uint8_t>(event.begin(), event.end()));
+ }
return Void();
}
Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
- callback_->aclDataReceived(std::vector<uint8_t>(data.begin(), data.end()));
+ if (callback_ != nullptr) {
+ callback_->aclDataReceived(std::vector<uint8_t>(data.begin(), data.end()));
+ }
return Void();
}
Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
- callback_->scoDataReceived(std::vector<uint8_t>(data.begin(), data.end()));
+ if (callback_ != nullptr) {
+ callback_->scoDataReceived(std::vector<uint8_t>(data.begin(), data.end()));
+ }
return Void();
}
private:
- BluetoothHciHalCallbacks* callback_;
+ BluetoothInitializationCompleteCallback* initialization_callback_ = nullptr;
+ BluetoothHciHalCallbacks* callback_ = nullptr;
};
} // namespace
class BluetoothHciHalHidl : public BluetoothHciHal {
public:
- void initialize(BluetoothHciHalCallbacks* callback) override {
+ void initialize(BluetoothInitializationCompleteCallback* callback) override {
bt_hci_ = IBluetoothHci::getService();
ASSERT(bt_hci_ != nullptr);
auto death_link = bt_hci_->linkToDeath(bluetooth_hci_death_recipient_, 0);
@@ -86,11 +103,15 @@
// Block allows allocation of a variable that might be bypassed by goto.
{
- android::sp<IBluetoothHciCallbacks> callbacks = new HciHalBluetoothHciCallbacks(callback);
- bt_hci_->initialize(callbacks);
+ callbacks_ = new HciHalBluetoothHciCallbacks(callback);
+ bt_hci_->initialize(callbacks_);
}
}
+ void registerIncomingPacketCallback(BluetoothHciHalCallbacks* callback) override {
+ callbacks_->SetCallback(callback);
+ }
+
void sendHciCommand(HciPacket command) override {
bt_hci_->sendHciCommand(command);
}
@@ -110,10 +131,12 @@
LOG_ERROR("Error unlinking death recipient from the Bluetooth HAL");
}
bt_hci_->close();
+ callbacks_->ResetCallback();
bt_hci_ = nullptr;
}
private:
+ android::sp<HciHalBluetoothHciCallbacks> callbacks_;
android::sp<IBluetoothHci> bt_hci_;
};
diff --git a/gd/hal/hci_hal_android_hidl_test.cc b/gd/hal/hci_hal_android_hidl_test.cc
index ed0e924..0171fc5 100644
--- a/gd/hal/hci_hal_android_hidl_test.cc
+++ b/gd/hal/hci_hal_android_hidl_test.cc
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2019 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 "hal/hci_hal.h"
#include <chrono>
@@ -11,18 +27,12 @@
std::promise<void>* g_promise;
-class TestBluetoothHciHalCallbacks : public BluetoothHciHalCallbacks {
+class TestBluetoothInitializationCompleteCallback : public BluetoothInitializationCompleteCallback {
public:
void initializationComplete(Status status) override {
EXPECT_EQ(status, Status::SUCCESS);
g_promise->set_value();
}
-
- void hciEventReceived(HciPacket) override {}
-
- void aclDataReceived(HciPacket) override {}
-
- void scoDataReceived(HciPacket) override {}
};
class HciHalHidlTest : public ::testing::Test {
@@ -30,7 +40,7 @@
void SetUp() override {
g_promise = new std::promise<void>;
hal_ = GetBluetoothHciHal();
- hal_->initialize(&callbacks_);
+ hal_->initialize(&init_callback_);
}
void TearDown() override {
@@ -40,7 +50,7 @@
}
BluetoothHciHal* hal_ = nullptr;
- TestBluetoothHciHalCallbacks callbacks_;
+ TestBluetoothInitializationCompleteCallback init_callback_;
};
TEST_F(HciHalHidlTest, init_and_close) {
diff --git a/gd/hal/hci_hal_host_rootcanal.cc b/gd/hal/hci_hal_host_rootcanal.cc
index c130263..5a1e2fb 100644
--- a/gd/hal/hci_hal_host_rootcanal.cc
+++ b/gd/hal/hci_hal_host_rootcanal.cc
@@ -19,20 +19,17 @@
#include <fcntl.h>
#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <sys/socket.h>
-#include <sys/types.h>
#include <unistd.h>
#include <mutex>
#include <queue>
-#include <string>
#include "os/log.h"
#include "os/reactor.h"
#include "os/thread.h"
namespace {
+constexpr int INVALID_FD = -1;
+
constexpr uint8_t kH4Command = 0x01;
constexpr uint8_t kH4Acl = 0x02;
constexpr uint8_t kH4Sco = 0x03;
@@ -48,14 +45,14 @@
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 1) {
LOG_ERROR("can't create socket: %s", strerror(errno));
- return -1;
+ return INVALID_FD;
}
struct hostent* host;
host = gethostbyname(server.c_str());
if (host == nullptr) {
LOG_ERROR("can't get server name");
- return -1;
+ return INVALID_FD;
}
struct sockaddr_in serv_addr;
@@ -67,14 +64,14 @@
int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if (result < 0) {
LOG_ERROR("can't connect: %s", strerror(errno));
- return -1;
+ return INVALID_FD;
}
int flags = fcntl(socket_fd, F_GETFL, NULL);
int ret = fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
if (ret == -1) {
LOG_ERROR("can't control socket fd: %s", strerror(errno));
- return -1;
+ return INVALID_FD;
}
return socket_fd;
}
@@ -85,20 +82,26 @@
class BluetoothHciHalHostRootcanal : public BluetoothHciHal {
public:
- void initialize(BluetoothHciHalCallbacks* callback) override {
+ void initialize(BluetoothInitializationCompleteCallback* callback) override {
std::lock_guard<std::mutex> lock(mutex_);
- ASSERT(callback_ == nullptr && callback != nullptr);
+ ASSERT(sock_fd_ == INVALID_FD && callback != nullptr);
sock_fd_ = ConnectToRootCanal(config_->GetServerAddress(), config_->GetPort());
+ ASSERT(sock_fd_ != INVALID_FD);
reactable_ =
hci_incoming_thread_.GetReactor()->Register(sock_fd_, [this]() { this->incoming_packet_received(); }, nullptr);
- callback_ = callback;
callback->initializationComplete(Status::SUCCESS);
LOG_INFO("Rootcanal HAL opened successfully");
}
+ void registerIncomingPacketCallback(BluetoothHciHalCallbacks* callback) override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(incoming_packet_callback_ == nullptr && callback != nullptr);
+ incoming_packet_callback_ = callback;
+ }
+
void sendHciCommand(HciPacket command) override {
std::lock_guard<std::mutex> lock(mutex_);
- ASSERT(callback_ != nullptr);
+ ASSERT(sock_fd_ != INVALID_FD);
std::vector<uint8_t> packet = std::move(command);
packet.insert(packet.cbegin(), kH4Command);
write_to_rootcanal_fd(packet);
@@ -106,7 +109,7 @@
void sendAclData(HciPacket data) override {
std::lock_guard<std::mutex> lock(mutex_);
- ASSERT(callback_ != nullptr);
+ ASSERT(sock_fd_ != INVALID_FD);
std::vector<uint8_t> packet = std::move(data);
packet.insert(packet.cbegin(), kH4Acl);
write_to_rootcanal_fd(packet);
@@ -114,7 +117,7 @@
void sendScoData(HciPacket data) override {
std::lock_guard<std::mutex> lock(mutex_);
- ASSERT(callback_ != nullptr);
+ ASSERT(sock_fd_ != INVALID_FD);
std::vector<uint8_t> packet = std::move(data);
packet.insert(packet.cbegin(), kH4Sco);
write_to_rootcanal_fd(packet);
@@ -122,19 +125,22 @@
void close() override {
std::lock_guard<std::mutex> lock(mutex_);
- ASSERT(callback_ != nullptr);
- hci_incoming_thread_.GetReactor()->Unregister(reactable_);
+ if (reactable_ != nullptr) {
+ hci_incoming_thread_.GetReactor()->Unregister(reactable_);
+ ASSERT(sock_fd_ != INVALID_FD);
+ }
reactable_ = nullptr;
- callback_ = nullptr;
+ incoming_packet_callback_ = nullptr;
::close(sock_fd_);
+ sock_fd_ = INVALID_FD;
LOG_INFO("Rootcanal HAL is closed");
}
private:
std::mutex mutex_;
HciHalHostRootcanalConfig* config_ = HciHalHostRootcanalConfig::Get();
- BluetoothHciHalCallbacks* callback_ = nullptr;
- int sock_fd_ = 0;
+ BluetoothHciHalCallbacks* incoming_packet_callback_ = nullptr;
+ int sock_fd_ = INVALID_FD;
bluetooth::os::Thread hci_incoming_thread_ =
bluetooth::os::Thread("hci_incoming_thread", bluetooth::os::Thread::Priority::NORMAL);
bluetooth::os::Reactor::Reactable* reactable_ = nullptr;
@@ -163,6 +169,8 @@
}
void incoming_packet_received() {
+ ASSERT(incoming_packet_callback_ != nullptr);
+
uint8_t buf[kBufSize] = {};
ssize_t received_size;
@@ -188,7 +196,7 @@
HciPacket receivedHciPacket;
receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciEvtHeaderSize + payload_size);
- callback_->hciEventReceived(receivedHciPacket);
+ incoming_packet_callback_->hciEventReceived(receivedHciPacket);
}
if (buf[0] == kH4Acl) {
@@ -204,7 +212,7 @@
HciPacket receivedHciPacket;
receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciAclHeaderSize + payload_size);
- callback_->aclDataReceived(receivedHciPacket);
+ incoming_packet_callback_->aclDataReceived(receivedHciPacket);
}
if (buf[0] == kH4Sco) {
@@ -217,7 +225,7 @@
HciPacket receivedHciPacket;
receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciScoHeaderSize + payload_size);
- callback_->scoDataReceived(receivedHciPacket);
+ incoming_packet_callback_->scoDataReceived(receivedHciPacket);
}
memset(buf, 0, kBufSize);
}
diff --git a/gd/hal/hci_hal_host_rootcanal_test.cc b/gd/hal/hci_hal_host_rootcanal_test.cc
index 2ad2f4a..e26ec95 100644
--- a/gd/hal/hci_hal_host_rootcanal_test.cc
+++ b/gd/hal/hci_hal_host_rootcanal_test.cc
@@ -50,12 +50,15 @@
std::queue<std::pair<uint8_t, HciPacket>> incoming_packets_queue_;
-class TestBluetoothHciHalCallbacks : public BluetoothHciHalCallbacks {
+class TestBluetoothInitializationCompleteCallback : public BluetoothInitializationCompleteCallback {
public:
void initializationComplete(Status status) override {
EXPECT_EQ(status, Status::SUCCESS);
}
+};
+class TestBluetoothHciHalCallbacks : public BluetoothHciHalCallbacks {
+ public:
void hciEventReceived(HciPacket packet) override {
incoming_packets_queue_.emplace(kH4Event, packet);
}
@@ -139,7 +142,8 @@
HciHalHostRootcanalConfig::Get()->SetPort(kTestPort);
fake_server_ = new FakeRootcanalDesktopHciServer;
hal_ = GetBluetoothHciHal();
- hal_->initialize(&callbacks_);
+ hal_->initialize(&init_callback_);
+ hal_->registerIncomingPacketCallback(&callbacks_);
fake_server_socket_ = fake_server_->Accept(); // accept() after client is connected to avoid blocking
std::queue<std::pair<uint8_t, HciPacket>> empty;
std::swap(incoming_packets_queue_, empty);
@@ -159,6 +163,7 @@
FakeRootcanalDesktopHciServer* fake_server_ = nullptr;
BluetoothHciHal* hal_ = nullptr;
+ TestBluetoothInitializationCompleteCallback init_callback_;
TestBluetoothHciHalCallbacks callbacks_;
int fake_server_socket_ = -1;
};
diff --git a/gd/stack_manager.cc b/gd/stack_manager.cc
new file mode 100644
index 0000000..f06bf87
--- /dev/null
+++ b/gd/stack_manager.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 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 "stack_manager.h"
+
+#include <chrono>
+#include <future>
+#include <queue>
+
+#include "hal/hci_hal.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+using ::bluetooth::hal::BluetoothHciHalCallbacks;
+using ::bluetooth::hal::BluetoothInitializationCompleteCallback;
+using ::bluetooth::hal::HciPacket;
+using ::bluetooth::hal::Status;
+using ::bluetooth::os::Handler;
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+namespace {
+std::promise<void>* startup_promise;
+
+class InitCallback : public BluetoothInitializationCompleteCallback {
+ public:
+ void initializationComplete(Status status) override {
+ ASSERT(status == Status::SUCCESS);
+ startup_promise->set_value();
+ }
+} init_callback;
+
+Thread* main_thread_;
+
+} // namespace
+
+void StackManager::StartUp() {
+ startup_promise = new std::promise<void>;
+ ::bluetooth::hal::GetBluetoothHciHal()->initialize(&init_callback);
+ auto init_status = startup_promise->get_future().wait_for(std::chrono::seconds(3));
+ ASSERT_LOG(init_status == std::future_status::ready, "Can't initialize HCI HAL");
+ delete startup_promise;
+
+ main_thread_ = new Thread("main_thread", Thread::Priority::NORMAL);
+
+ LOG_INFO("init complete");
+ // Bring up HCI layer
+}
+
+void StackManager::ShutDown() {
+ // Delete HCI layer
+ delete main_thread_;
+ ::bluetooth::hal::GetBluetoothHciHal()->close();
+}
+} // namespace bluetooth
diff --git a/gd/stack_manager.h b/gd/stack_manager.h
new file mode 100644
index 0000000..11d218b
--- /dev/null
+++ b/gd/stack_manager.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 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
+
+namespace bluetooth {
+
+class StackManager {
+ public:
+ static StackManager* Get() {
+ static StackManager instance;
+ return &instance;
+ }
+
+ // Start up the stack, init HCI HAL
+ void StartUp();
+
+ // Shut down the stack, close HCI HAL
+ void ShutDown();
+
+ private:
+ StackManager() = default;
+};
+
+} // namespace bluetooth
diff --git a/test/rootcanal/bluetooth_hci.cc b/test/rootcanal/bluetooth_hci.cc
index 2fd68cb..bdd44c5 100644
--- a/test/rootcanal/bluetooth_hci.cc
+++ b/test/rootcanal/bluetooth_hci.cc
@@ -124,9 +124,11 @@
if (BtTestConsoleEnabled()) {
SetUpTestChannel(6111);
+ SetUpHciServer(6211,
+ [this](int fd) { test_model_.IncomingHciConnection(fd); });
+ SetUpLinkLayerServer(
+ 6311, [this](int fd) { test_model_.IncomingLinkLayerConnection(fd); });
}
- SetUpHciServer(6211, [this](int fd) { test_model_.IncomingHciConnection(fd); });
- SetUpLinkLayerServer(6311, [this](int fd) { test_model_.IncomingLinkLayerConnection(fd); });
unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
if (death_recipient->getHasDied())