| /****************************************************************************** |
| * |
| * Copyright 2017 Google, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| ******************************************************************************/ |
| |
| #define LOG_TAG "bt_hci" |
| |
| #include "hci_layer.h" |
| |
| #include <fcntl.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| |
| #include <base/location.h> |
| #include <base/logging.h> |
| #include "buffer_allocator.h" |
| #include "osi/include/log.h" |
| |
| #include <android/hardware/bluetooth/1.0/IBluetoothHci.h> |
| #include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h> |
| #include <android/hardware/bluetooth/1.0/types.h> |
| #include <android/hardware/bluetooth/1.1/IBluetoothHci.h> |
| #include <android/hardware/bluetooth/1.1/IBluetoothHciCallbacks.h> |
| #include <hwbinder/ProcessState.h> |
| |
| #define LOG_PATH "/data/misc/bluetooth/logs/firmware_events.log" |
| #define LAST_LOG_PATH "/data/misc/bluetooth/logs/firmware_events.log.last" |
| |
| using ::android::hardware::hidl_death_recipient; |
| using ::android::hardware::hidl_vec; |
| using ::android::hardware::ProcessState; |
| using ::android::hardware::Return; |
| using ::android::hardware::Void; |
| using ::android::hardware::bluetooth::V1_0::HciPacket; |
| using ::android::hardware::bluetooth::V1_0::Status; |
| |
| using namespace ::android::hardware::bluetooth; |
| |
| extern void initialization_complete(); |
| extern void hci_event_received(const base::Location& from_here, BT_HDR* packet); |
| extern void acl_event_received(BT_HDR* packet); |
| extern void sco_data_received(BT_HDR* packet); |
| extern void iso_data_received(BT_HDR* packet); |
| |
| android::sp<V1_0::IBluetoothHci> btHci; |
| android::sp<V1_1::IBluetoothHci> btHci_1_1; |
| |
| class BluetoothHciDeathRecipient : public hidl_death_recipient { |
| public: |
| virtual void serviceDied(uint64_t /*cookie*/, const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) { |
| LOG_ERROR(LOG_TAG, "Bluetooth HAL service died!"); |
| abort(); |
| } |
| }; |
| android::sp<BluetoothHciDeathRecipient> bluetoothHciDeathRecipient = new BluetoothHciDeathRecipient(); |
| |
| class BluetoothHciCallbacks : public V1_1::IBluetoothHciCallbacks { |
| public: |
| BluetoothHciCallbacks() { |
| buffer_allocator = buffer_allocator_get_interface(); |
| } |
| |
| BT_HDR* WrapPacketAndCopy(uint16_t event, const hidl_vec<uint8_t>& data) { |
| size_t packet_size = data.size() + BT_HDR_SIZE; |
| BT_HDR* packet = |
| reinterpret_cast<BT_HDR*>(buffer_allocator->alloc(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 ensured to |
| // be the only way the data is accessed, a pointer could be passed here... |
| memcpy(packet->data, data.data(), data.size()); |
| return packet; |
| } |
| |
| Return<void> initializationComplete(Status status) override { |
| CHECK(status == Status::SUCCESS); |
| initialization_complete(); |
| return Void(); |
| } |
| |
| Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) override { |
| BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, event); |
| hci_event_received(FROM_HERE, packet); |
| return Void(); |
| } |
| |
| Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) override { |
| BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_ACL, data); |
| acl_event_received(packet); |
| return Void(); |
| } |
| |
| Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) override { |
| BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_SCO, data); |
| sco_data_received(packet); |
| return Void(); |
| } |
| |
| Return<void> isoDataReceived(const hidl_vec<uint8_t>& data) override { |
| BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_ISO, data); |
| iso_data_received(packet); |
| return Void(); |
| } |
| |
| const allocator_t* buffer_allocator; |
| }; |
| |
| void hci_initialize() { |
| LOG_INFO(LOG_TAG, "%s", __func__); |
| |
| btHci_1_1 = V1_1::IBluetoothHci::getService(); |
| |
| if (btHci_1_1 != nullptr) { |
| btHci = btHci_1_1; |
| } else { |
| btHci = V1_0::IBluetoothHci::getService(); |
| } |
| |
| // If android.hardware.bluetooth* is not found, Bluetooth can not continue. |
| CHECK(btHci != nullptr); |
| auto death_link = btHci->linkToDeath(bluetoothHciDeathRecipient, 0); |
| if (!death_link.isOk()) { |
| LOG_ERROR(LOG_TAG, "%s: Unable to set the death recipient for the Bluetooth HAL", __func__); |
| abort(); |
| } |
| LOG_INFO(LOG_TAG, "%s: IBluetoothHci::getService() returned %p (%s)", |
| __func__, btHci.get(), (btHci->isRemote() ? "remote" : "local")); |
| |
| // Block allows allocation of a variable that might be bypassed by goto. |
| { |
| android::sp<V1_1::IBluetoothHciCallbacks> callbacks = |
| new BluetoothHciCallbacks(); |
| if (btHci_1_1 != nullptr) { |
| btHci_1_1->initialize(callbacks); |
| } else { |
| btHci->initialize(callbacks); |
| } |
| } |
| } |
| |
| void hci_close() { |
| if (btHci != nullptr) { |
| auto death_unlink = btHci->unlinkToDeath(bluetoothHciDeathRecipient); |
| if (!death_unlink.isOk()) { |
| LOG_ERROR(LOG_TAG, "%s: Error unlinking death recipient from the Bluetooth HAL", __func__); |
| } |
| } |
| btHci->close(); |
| btHci = nullptr; |
| } |
| |
| void hci_transmit(BT_HDR* packet) { |
| HciPacket data; |
| data.setToExternal(packet->data + packet->offset, packet->len); |
| |
| uint16_t event = packet->event & MSG_EVT_MASK; |
| switch (event & MSG_EVT_MASK) { |
| case MSG_STACK_TO_HC_HCI_CMD: |
| btHci->sendHciCommand(data); |
| break; |
| case MSG_STACK_TO_HC_HCI_ACL: |
| btHci->sendAclData(data); |
| break; |
| case MSG_STACK_TO_HC_HCI_SCO: |
| btHci->sendScoData(data); |
| break; |
| case MSG_STACK_TO_HC_HCI_ISO: |
| if (btHci_1_1 != nullptr) { |
| btHci_1_1->sendIsoData(data); |
| } else { |
| LOG_ERROR(LOG_TAG, "ISO is not supported in HAL v1.0"); |
| } |
| break; |
| default: |
| LOG_ERROR(LOG_TAG, "Unknown packet type (%d)", event); |
| break; |
| } |
| } |
| |
| int hci_open_firmware_log_file() { |
| if (rename(LOG_PATH, LAST_LOG_PATH) == -1 && errno != ENOENT) { |
| LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__, |
| LOG_PATH, LAST_LOG_PATH, strerror(errno)); |
| } |
| |
| mode_t prevmask = umask(0); |
| int logfile_fd = open(LOG_PATH, O_WRONLY | O_CREAT | O_TRUNC, |
| S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); |
| umask(prevmask); |
| if (logfile_fd == INVALID_FD) { |
| LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, LOG_PATH, |
| strerror(errno)); |
| } |
| |
| return logfile_fd; |
| } |
| |
| void hci_close_firmware_log_file(int fd) { |
| if (fd != INVALID_FD) close(fd); |
| } |
| |
| void hci_log_firmware_debug_packet(int fd, BT_HDR* packet) { |
| TEMP_FAILURE_RETRY(write(fd, packet->data, packet->len)); |
| } |