282 lines
8.9 KiB
C++
282 lines
8.9 KiB
C++
/******************************************************************************
|
|
*
|
|
* 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 <iomanip>
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.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 <base/location.h>
|
|
#include <base/logging.h>
|
|
|
|
#include "buffer_allocator.h"
|
|
#include "common/stop_watch_legacy.h"
|
|
#include "osi/include/log.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::Return;
|
|
using ::android::hardware::Void;
|
|
using ::android::hardware::bluetooth::V1_0::HciPacket;
|
|
using ::android::hardware::bluetooth::V1_0::Status;
|
|
using ::bluetooth::common::StopWatchLegacy;
|
|
|
|
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);
|
|
extern void hal_service_died();
|
|
extern bool hci_is_root_inflammation_event_received();
|
|
|
|
android::sp<V1_0::IBluetoothHci> btHci;
|
|
android::sp<V1_1::IBluetoothHci> btHci_1_1;
|
|
|
|
std::string GetTimerText(std::string func_name, const hidl_vec<uint8_t>& vec) {
|
|
std::stringstream ss;
|
|
const unsigned char* vec_char =
|
|
reinterpret_cast<const unsigned char*>(vec.data());
|
|
int length = 5;
|
|
if ((int)vec.size() < 5) {
|
|
length = vec.size();
|
|
}
|
|
for (int i = 0; i < length; i++) {
|
|
ss << std::setw(2) << std::setfill('0') << std::hex << (int)vec_char[i];
|
|
}
|
|
std::string text = func_name + ": len " + std::to_string(vec.size()) +
|
|
", 1st 5 bytes '" + ss.str() + "'";
|
|
return text;
|
|
}
|
|
|
|
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("Bluetooth HAL service died!");
|
|
StopWatchLegacy::DumpStopWatchLog();
|
|
hal_service_died();
|
|
}
|
|
};
|
|
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 {
|
|
StopWatchLegacy(__func__);
|
|
if (hci_is_root_inflammation_event_received()) {
|
|
// Ignore the initializationComplete here as we have already received
|
|
// root inflammation event earlier.
|
|
LOG_ERROR(
|
|
"initializationComplete after root inflammation event! status=%d",
|
|
status);
|
|
return Void();
|
|
}
|
|
CHECK(status == Status::SUCCESS);
|
|
initialization_complete();
|
|
return Void();
|
|
}
|
|
|
|
Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) override {
|
|
StopWatchLegacy(GetTimerText(__func__, event));
|
|
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 {
|
|
StopWatchLegacy(GetTimerText(__func__, data));
|
|
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 {
|
|
StopWatchLegacy(GetTimerText(__func__, data));
|
|
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 {
|
|
StopWatchLegacy(GetTimerText(__func__, data));
|
|
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("%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("%s: Unable to set the death recipient for the Bluetooth HAL",
|
|
__func__);
|
|
abort();
|
|
}
|
|
LOG_INFO("%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) {
|
|
auto ret = btHci_1_1->initialize_1_1(callbacks);
|
|
if (!ret.isOk()) {
|
|
LOG_ERROR("%s: Unable to initialize btHci_1_1", __func__);
|
|
abort();
|
|
}
|
|
} else {
|
|
auto ret = btHci->initialize(callbacks);
|
|
if (!ret.isOk()) {
|
|
LOG_ERROR("%s: Unable to initialize btHci_1_0", __func__);
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void hci_close() {
|
|
if (btHci != nullptr) {
|
|
auto death_unlink = btHci->unlinkToDeath(bluetoothHciDeathRecipient);
|
|
if (!death_unlink.isOk()) {
|
|
LOG_ERROR("%s: Error unlinking death recipient from the Bluetooth HAL",
|
|
__func__);
|
|
}
|
|
auto close_status = btHci->close();
|
|
if (!close_status.isOk()) {
|
|
LOG_ERROR("%s: Error closing the Bluetooth HAL", __func__);
|
|
}
|
|
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:
|
|
{
|
|
auto ret = btHci->sendHciCommand(data);
|
|
if (!ret.isOk())
|
|
LOG_ERROR("%s: Error btHci->sendHciCmd", __func__);
|
|
break;
|
|
}
|
|
case MSG_STACK_TO_HC_HCI_ACL:
|
|
{
|
|
auto ret = btHci->sendAclData(data);
|
|
if (!ret.isOk())
|
|
LOG_ERROR("%s: Error btHci->sendAclData", __func__);
|
|
break;
|
|
}
|
|
case MSG_STACK_TO_HC_HCI_SCO:
|
|
{
|
|
auto ret = btHci->sendScoData(data);
|
|
if (!ret.isOk())
|
|
LOG_ERROR("%s: Error btHci->sendScoData", __func__);
|
|
break;
|
|
}
|
|
case MSG_STACK_TO_HC_HCI_ISO:
|
|
if (btHci_1_1 != nullptr) {
|
|
auto ret = btHci_1_1->sendIsoData(data);
|
|
if (!ret.isOk())
|
|
LOG_ERROR("%s: Error btHci_1_1->sendIsoData", __func__);
|
|
} else {
|
|
LOG_ERROR("ISO is not supported in HAL v1.0");
|
|
}
|
|
break;
|
|
default:
|
|
LOG_ERROR("Unknown packet type (%d)", event);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int hci_open_firmware_log_file() {
|
|
if (rename(LOG_PATH, LAST_LOG_PATH) == -1 && errno != ENOENT) {
|
|
LOG_ERROR("%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("%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));
|
|
}
|