bluetooth: Add support for linux bluetooth raw hci sockets
The implementation is imported from
packages/modules/Bluetooth/system/vendor_libs/linux/interface
with modifications to modernize the code.
The default bluetooth HAL implementation now jointly uses
the serial implementation and the bluetooth socket
implementation.
Bug: 205758693
Test: VtsHalBluetoothTargetTest
Change-Id: I791fd406e56a0144e1117cb6f8e27ec71b48a192
diff --git a/bluetooth/aidl/default/Android.bp b/bluetooth/aidl/default/Android.bp
index d1761f5..3f4ba99 100644
--- a/bluetooth/aidl/default/Android.bp
+++ b/bluetooth/aidl/default/Android.bp
@@ -30,6 +30,7 @@
defaults: ["android.hardware.bluetooth-service-build-defaults"],
srcs: [
"BluetoothHci.cpp",
+ "net_bluetooth_mgmt.cpp",
],
}
@@ -37,7 +38,7 @@
name: "android.hardware.bluetooth-service.default",
relative_install_path: "hw",
init_rc: ["bluetooth-service-default.rc"],
- vintf_fragments: ["bluetooth-service-default.xml"],
+ vintf_fragments: [":manifest_android.hardware.bluetooth-service.default.xml"],
vendor: true,
defaults: ["android.hardware.bluetooth-service-build-defaults"],
srcs: [
@@ -77,3 +78,8 @@
],
},
}
+
+filegroup {
+ name: "manifest_android.hardware.bluetooth-service.default.xml",
+ srcs: ["bluetooth-service-default.xml"],
+}
diff --git a/bluetooth/aidl/default/BluetoothHci.cpp b/bluetooth/aidl/default/BluetoothHci.cpp
index 4d4896d..dd102a1 100644
--- a/bluetooth/aidl/default/BluetoothHci.cpp
+++ b/bluetooth/aidl/default/BluetoothHci.cpp
@@ -44,6 +44,7 @@
using namespace ::android::hardware::bluetooth::hci;
using namespace ::android::hardware::bluetooth::async;
+using aidl::android::hardware::bluetooth::Status;
namespace aidl::android::hardware::bluetooth::impl {
@@ -97,21 +98,25 @@
mDeathRecipient = std::make_shared<BluetoothDeathRecipient>(this);
}
-ndk::ScopedAStatus BluetoothHci::initialize(
- const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
- ALOGI(__func__);
-
- mFd = open(mDevPath.c_str(), O_RDWR);
- if (mFd < 0) {
+int BluetoothHci::getFdFromDevPath() {
+ int fd = open(mDevPath.c_str(), O_RDWR);
+ if (fd < 0) {
ALOGE("Could not connect to bt: %s (%s)", mDevPath.c_str(),
strerror(errno));
- return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
+ return fd;
}
if (int ret = SetTerminalRaw(mFd) < 0) {
ALOGE("Could not make %s a raw terminal %d(%s)", mDevPath.c_str(), ret,
strerror(errno));
- return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
+ ::close(fd);
+ return -1;
}
+ return fd;
+}
+
+ndk::ScopedAStatus BluetoothHci::initialize(
+ const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
+ ALOGI(__func__);
mCb = cb;
if (mCb == nullptr) {
@@ -119,16 +124,20 @@
return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
}
+ management_.reset(new NetBluetoothMgmt);
+ mFd = management_->openHci();
+ if (mFd < 0) {
+ management_.reset();
+
+ ALOGI("Unable to open Linux interface, trying default path.");
+ mFd = getFdFromDevPath();
+ if (mFd < 0) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
+ }
+ }
+
mDeathRecipient->LinkToDeath(mCb);
- auto init_ret = cb->initializationComplete(Status::SUCCESS);
- if (!init_ret.isOk()) {
- if (!mDeathRecipient->getHasDied()) {
- ALOGE("Error sending init callback, but no death notification.");
- }
- return ndk::ScopedAStatus::fromServiceSpecificError(
- STATUS_FAILED_TRANSACTION);
- }
mH4 = std::make_shared<H4Protocol>(
mFd,
[](const std::vector<uint8_t>& /* raw_command */) {
@@ -152,13 +161,29 @@
});
mFdWatcher.WatchFdForNonBlockingReads(mFd,
[this](int) { mH4->OnDataReady(); });
+
+ ALOGI("initialization complete");
+ auto status = mCb->initializationComplete(Status::SUCCESS);
+ if (!status.isOk()) {
+ if (!mDeathRecipient->getHasDied()) {
+ ALOGE("Error sending init callback, but no death notification");
+ }
+ close();
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ STATUS_FAILED_TRANSACTION);
+ }
+
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus BluetoothHci::close() {
ALOGI(__func__);
mFdWatcher.StopWatchingFileDescriptors();
- ::close(mFd);
+ if (management_) {
+ management_->closeHci();
+ } else {
+ ::close(mFd);
+ }
return ndk::ScopedAStatus::ok();
}
diff --git a/bluetooth/aidl/default/BluetoothHci.h b/bluetooth/aidl/default/BluetoothHci.h
index 0ed0623..a0908f8 100644
--- a/bluetooth/aidl/default/BluetoothHci.h
+++ b/bluetooth/aidl/default/BluetoothHci.h
@@ -24,6 +24,7 @@
#include "async_fd_watcher.h"
#include "h4_protocol.h"
+#include "net_bluetooth_mgmt.h"
namespace aidl::android::hardware::bluetooth::impl {
@@ -64,8 +65,10 @@
::android::hardware::bluetooth::async::AsyncFdWatcher mFdWatcher;
+ int getFdFromDevPath();
void send(::android::hardware::bluetooth::hci::PacketType type,
const std::vector<uint8_t>& packet);
+ std::unique_ptr<NetBluetoothMgmt> management_{};
};
} // namespace aidl::android::hardware::bluetooth::impl
diff --git a/bluetooth/aidl/default/bluetooth-service-default.rc b/bluetooth/aidl/default/bluetooth-service-default.rc
index 1841c77..dc78698 100644
--- a/bluetooth/aidl/default/bluetooth-service-default.rc
+++ b/bluetooth/aidl/default/bluetooth-service-default.rc
@@ -1,4 +1,4 @@
-service bluetooth_hal_service /vendor/bin/hw/android.hardware.bluetooth-service.default
+service vendor.bluetooth-default /vendor/bin/hw/android.hardware.bluetooth-service.default
class hal
capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
user bluetooth
diff --git a/bluetooth/aidl/default/net_bluetooth_mgmt.cpp b/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
new file mode 100644
index 0000000..937cd57
--- /dev/null
+++ b/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2022 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.service.default"
+
+#include "net_bluetooth_mgmt.h"
+
+#include <fcntl.h>
+#include <log/log.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+
+// Definitions imported from <linux/net/bluetooth/bluetooth.h>
+#define BTPROTO_HCI 1
+
+// Definitions imported from <linux/net/bluetooth/hci_sock.h>
+#define HCI_CHANNEL_USER 1
+#define HCI_CHANNEL_CONTROL 3
+#define HCI_DEV_NONE 0xffff
+
+struct sockaddr_hci {
+ sa_family_t hci_family;
+ unsigned short hci_dev;
+ unsigned short hci_channel;
+};
+
+// Definitions imported from <linux/net/bluetooth/mgmt.h>
+#define MGMT_OP_READ_INDEX_LIST 0x0003
+#define MGMT_EV_INDEX_ADDED 0x0004
+#define MGMT_EV_CMD_COMPLETE 0x0001
+#define MGMT_PKT_SIZE_MAX 1024
+#define MGMT_INDEX_NONE 0xFFFF
+
+struct mgmt_pkt {
+ uint16_t opcode;
+ uint16_t index;
+ uint16_t len;
+ uint8_t data[MGMT_PKT_SIZE_MAX];
+} __attribute__((packed));
+
+struct mgmt_ev_read_index_list {
+ uint16_t opcode;
+ uint8_t status;
+ uint16_t num_controllers;
+ uint16_t index[];
+} __attribute__((packed));
+
+// Definitions imported from <linux/rfkill.h>
+#define RFKILL_STATE_SOFT_BLOCKED 0
+#define RFKILL_STATE_UNBLOCKED 1
+#define RFKILL_STATE_HARD_BLOCKED 2
+
+#define RFKILL_TYPE_BLUETOOTH 2
+
+#define RFKILL_OP_ADD 0
+#define RFKILL_OP_CHANGE 2
+
+struct rfkill_event {
+ uint32_t idx;
+ uint8_t type;
+ uint8_t op;
+ uint8_t soft;
+ uint8_t hard;
+} __attribute__((packed));
+
+namespace aidl::android::hardware::bluetooth::impl {
+
+// Wait indefinitely for the selected HCI interface to be enabled in the
+// bluetooth driver.
+int NetBluetoothMgmt::waitHciDev(int hci_interface) {
+ ALOGI("waiting for hci interface %d", hci_interface);
+
+ int ret = -1;
+ struct mgmt_pkt cmd;
+ struct pollfd pollfd;
+ struct sockaddr_hci hci_addr = {
+ .hci_family = AF_BLUETOOTH,
+ .hci_dev = HCI_DEV_NONE,
+ .hci_channel = HCI_CHANNEL_CONTROL,
+ };
+
+ // Open and bind a socket to the bluetooth control interface in the
+ // kernel driver, used to send control commands and receive control
+ // events.
+ int fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (fd < 0) {
+ ALOGE("unable to open raw bluetooth socket: %s", strerror(errno));
+ return -1;
+ }
+
+ if (bind(fd, (struct sockaddr*)&hci_addr, sizeof(hci_addr)) < 0) {
+ ALOGE("unable to bind bluetooth control channel: %s", strerror(errno));
+ goto end;
+ }
+
+ // Send the control command [Read Index List].
+ cmd = {
+ .opcode = MGMT_OP_READ_INDEX_LIST,
+ .index = MGMT_INDEX_NONE,
+ .len = 0,
+ };
+
+ if (write(fd, &cmd, 6) != 6) {
+ ALOGE("error writing mgmt command: %s", strerror(errno));
+ goto end;
+ }
+
+ // Poll the control socket waiting for the command response,
+ // and subsequent [Index Added] events. The loops continue without
+ // timeout until the selected hci interface is detected.
+ pollfd = {.fd = fd, .events = POLLIN};
+
+ for (;;) {
+ ret = poll(&pollfd, 1, -1);
+
+ // Poll interrupted, try again.
+ if (ret == -1 && (errno == EINTR || errno == EAGAIN)) {
+ continue;
+ }
+
+ // Poll failure, abandon.
+ if (ret == -1) {
+ ALOGE("poll error: %s", strerror(errno));
+ break;
+ }
+
+ // Spurious wakeup, try again.
+ if (ret == 0 || (pollfd.revents & POLLIN) == 0) {
+ continue;
+ }
+
+ // Read the next control event.
+ struct mgmt_pkt ev {};
+ ret = read(fd, &ev, sizeof(ev));
+ if (ret < 0) {
+ ALOGE("error reading mgmt event: %s", strerror(errno));
+ goto end;
+ }
+
+ // Received [Read Index List] command response.
+ if (ev.opcode == MGMT_EV_CMD_COMPLETE) {
+ struct mgmt_ev_read_index_list* data =
+ (struct mgmt_ev_read_index_list*)ev.data;
+
+ for (int i = 0; i < data->num_controllers; i++) {
+ if (data->index[i] == hci_interface) {
+ ALOGI("hci interface %d found", hci_interface);
+ ret = 0;
+ goto end;
+ }
+ }
+ }
+
+ // Received [Index Added] event.
+ if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
+ ALOGI("hci interface %d added", hci_interface);
+ ret = 0;
+ goto end;
+ }
+ }
+
+end:
+ ::close(fd);
+ return ret;
+}
+
+int NetBluetoothMgmt::openRfkill() {
+ int fd = open("/dev/rfkill", O_RDWR);
+ if (fd < 0) {
+ ALOGE("unable to open /dev/rfkill: %s", strerror(errno));
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ ALOGE("unable to set rfkill control device to non-blocking: %s",
+ strerror(errno));
+ ::close(fd);
+ return -1;
+ }
+
+ for (;;) {
+ struct rfkill_event event {};
+ ssize_t res = read(fd, &event, sizeof(event));
+ if (res < 0) {
+ ALOGE("error reading rfkill events: %s", strerror(errno));
+ break;
+ }
+
+ ALOGI("index:%d type:%d op:%d", event.idx, event.type, event.op);
+
+ if (event.op == RFKILL_OP_ADD && event.type == RFKILL_TYPE_BLUETOOTH) {
+ rfkill_bt_index_ = event.idx;
+ rfkill_fd_ = fd;
+ return 0;
+ }
+ }
+
+ ::close(fd);
+ return -1;
+}
+
+// Block or unblock Bluetooth.
+int NetBluetoothMgmt::rfkill(int block) {
+ if (rfkill_fd_ == -1) {
+ openRfkill();
+ }
+
+ if (rfkill_fd_ == -1) {
+ ALOGE("rfkill unavailable");
+ return -1;
+ }
+
+ struct rfkill_event event = {
+ .idx = static_cast<uint32_t>(rfkill_bt_index_),
+ .type = RFKILL_TYPE_BLUETOOTH,
+ .op = RFKILL_OP_CHANGE,
+ .soft = static_cast<uint8_t>(block),
+ .hard = 0,
+ };
+
+ int res = write(rfkill_fd_, &event, sizeof(event));
+ if (res < 0) {
+ ALOGE("error writing rfkill command: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int NetBluetoothMgmt::openHci(int hci_interface) {
+ ALOGI("opening hci interface %d", hci_interface);
+
+ // Block Bluetooth.
+ rfkill(1);
+
+ // Wait for the HCI interface to complete initialization or to come online.
+ if (waitHciDev(hci_interface)) {
+ ALOGE("hci interface %d not found", hci_interface);
+ return -1;
+ }
+
+ // Open the raw HCI socket.
+ int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (fd < 0) {
+ ALOGE("unable to open raw bluetooth socket: %s", strerror(errno));
+ return -1;
+ }
+
+ struct sockaddr_hci hci_addr = {
+ .hci_family = AF_BLUETOOTH,
+ .hci_dev = static_cast<uint16_t>(hci_interface),
+ .hci_channel = HCI_CHANNEL_USER,
+ };
+
+ // Bind the socket to the selected interface.
+ if (bind(fd, (struct sockaddr*)&hci_addr, sizeof(hci_addr)) < 0) {
+ ALOGE("unable to bind bluetooth user channel: %s", strerror(errno));
+ ::close(fd);
+ return -1;
+ }
+
+ ALOGI("hci interface %d ready", hci_interface);
+ bt_fd_ = fd;
+ return fd;
+}
+
+void NetBluetoothMgmt::closeHci() {
+ if (bt_fd_ != -1) {
+ ::close(bt_fd_);
+ bt_fd_ = -1;
+ }
+
+ // Unblock Bluetooth.
+ rfkill(0);
+}
+
+} // namespace aidl::android::hardware::bluetooth::impl
diff --git a/bluetooth/aidl/default/net_bluetooth_mgmt.h b/bluetooth/aidl/default/net_bluetooth_mgmt.h
new file mode 100644
index 0000000..5c473f2
--- /dev/null
+++ b/bluetooth/aidl/default/net_bluetooth_mgmt.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2022 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 <unistd.h>
+
+namespace aidl::android::hardware::bluetooth::impl {
+
+class NetBluetoothMgmt {
+ public:
+ NetBluetoothMgmt() {}
+ ~NetBluetoothMgmt() {
+ ::close(rfkill_fd_);
+ ::close(bt_fd_);
+ }
+
+ int openHci(int hci_interface = 0);
+ void closeHci();
+
+ private:
+ int waitHciDev(int hci_interface);
+ int openRfkill();
+ int rfkill(int block);
+
+ // Index of the first rfkill device of type bluetooth.
+ int rfkill_bt_index_{-1};
+ // File descriptor opened to /dev/rfkill.
+ int rfkill_fd_{-1};
+ // File descriptor opened to the bluetooth user channel.
+ int bt_fd_{-1};
+};
+
+} // namespace aidl::android::hardware::bluetooth::impl