Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5e497c1 authored by Chris Manton's avatar Chris Manton
Browse files

legacy: Truncate all of hci layer

Bug: 197150934
Tag: #refactor
Test: gd/cert/run

Change-Id: Ia971fbbcf5405b4da704a1af3c5bc951c7bc3374
parent dab23929
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -376,7 +376,6 @@ cc_test {
          ":TestMockUdrv",
          ":TestMockUtils",
          "test/btif_core_test.cc",
          "test/btif_stack_test.cc",
      ],
      generated_headers: [
        "BluetoothGeneratedBundlerSchema_h_bfbs",
+0 −188
Original line number Diff line number Diff line
/*
 * Copyright 2021 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 "btif/include/btif_profile_queue.h"

#include <gtest/gtest.h>

#include <base/bind.h>
#include <base/callback.h>
#include <base/location.h>

#include "hci/include/hci_layer.h"   // hci_t
#include "osi/include/log.h"
#include "stack_manager.h"
#include "test/common/mock_functions.h"
#include "test/mock/mock_hci_layer.h"
#include "types/raw_address.h"

void set_hal_cbacks(bt_callbacks_t* callbacks);  // btif/src/bluetooth.cc

namespace {

namespace _adapter_state_changed {
bt_state_t state{BT_STATE_OFF};
}
void adapter_state_changed(bt_state_t state) {
  LOG_INFO("%u => %u", _adapter_state_changed::state, state);
}

void adapter_properties(bt_status_t status, int num_properties,
                        bt_property_t* properties) {
  LOG_INFO("Callback rx");
}

void remote_device_properties(bt_status_t status, RawAddress* bd_addr,
                              int num_properties, bt_property_t* properties) {
  LOG_INFO("Callback rx");
}

void device_found(int num_properties, bt_property_t* properties) {
  LOG_INFO("Callback rx");
}

void discovery_state_changed(bt_discovery_state_t state) {
  LOG_INFO("Callback rx");
}

/** Bluetooth Legacy PinKey Request callback */
void pin_request(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod,
                 bool min_16_digit) {
  LOG_INFO("Callback rx");
}

void ssp_request(RawAddress* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod,
                 bt_ssp_variant_t pairing_variant, uint32_t pass_key) {
  LOG_INFO("Callback rx");
}

/** Bluetooth Bond state changed callback */
/* Invoked in response to create_bond, cancel_bond or remove_bond */
void bond_state_changed(bt_status_t status, RawAddress* remote_bd_addr,
                        bt_bond_state_t state, int fail_reason) {
  LOG_INFO("Callback rx");
}

/** Bluetooth ACL connection state changed callback */
void acl_state_changed(bt_status_t status, RawAddress* remote_bd_addr,
                       bt_acl_state_t state, int transport_link_type,
                       bt_hci_error_code_t hci_reason) {
  LOG_INFO("status:%s device:%s state:%s", bt_status_text(status).c_str(),
           remote_bd_addr->ToString().c_str(),
           (state) ? "disconnected" : "connected");
}

/** Bluetooth Link Quality Report callback */
void link_quality_report(uint64_t timestamp, int report_id, int rssi, int snr,
                         int retransmission_count,
                         int packets_not_receive_count,
                         int negative_acknowledgement_count) {
  LOG_INFO("Callback rx");
}

void thread_event(bt_cb_thread_evt evt) { LOG_INFO("Callback rx"); }

void dut_mode_recv(uint16_t opcode, uint8_t* buf, uint8_t len) {
  LOG_INFO("Callback rx");
}

void le_test_mode(bt_status_t status, uint16_t num_packets) {
  LOG_INFO("Callback rx");
}

void energy_info(bt_activity_energy_info* energy_info,
                 bt_uid_traffic_t* uid_data) {
  LOG_INFO("Callback rx");
}

bt_callbacks_t bt_callbacks{
    /** set to sizeof(bt_callbacks_t) */
    .size = sizeof(bt_callbacks_t),
    .adapter_state_changed_cb = adapter_state_changed,
    .adapter_properties_cb = adapter_properties,
    .remote_device_properties_cb = remote_device_properties,
    .device_found_cb = device_found,
    .discovery_state_changed_cb = discovery_state_changed,
    .pin_request_cb = pin_request,
    .ssp_request_cb = ssp_request,
    .bond_state_changed_cb = bond_state_changed,
    .acl_state_changed_cb = acl_state_changed,
    .thread_evt_cb = thread_event,
    .dut_mode_recv_cb = dut_mode_recv,
    .le_test_mode_cb = le_test_mode,
    .energy_info_cb = energy_info,
    .link_quality_report_cb = link_quality_report,
};

void set_data_cb(
    base::Callback<void(const base::Location&, BT_HDR*)> send_data_cb) {
  mock_function_count_map[__func__]++;
}

void transmit_command(BT_HDR* command, command_complete_cb complete_callback,
                      command_status_cb status_cb, void* context) {
  mock_function_count_map[__func__]++;
}

future_t* transmit_command_futured(BT_HDR* command) {
  mock_function_count_map[__func__]++;
  return nullptr;
}

void transmit_downward(uint16_t type, void* data) {
  mock_function_count_map[__func__]++;
}

}  // namespace

hci_t mock_hci = {
    .set_data_cb = set_data_cb,
    .transmit_command = transmit_command,
    .transmit_command_futured = transmit_command_futured,
    .transmit_downward = transmit_downward,
};

namespace bluetooth {
namespace common {

class BluetoothMetricsLogger {};

}  // namespace common
}  // namespace bluetooth

class StackCycleTest : public ::testing::Test {
 protected:
  void SetUp() override {
    test::mock::hci_layer::hci_layer_get_interface.hci = &mock_hci;
    stack_manager_ = stack_manager_get_interface();
  }

  void TearDown() override { stack_manager_ = nullptr; }
  const stack_manager_t* stack_manager_{nullptr};
};

TEST_F(StackCycleTest, stack_init) {
  // TODO load init flags
  // bluetooth::common::InitFlags::Load(init_flags);

  set_hal_cbacks(&bt_callbacks);

  stack_manager_get_interface()->init_stack();

  LOG_INFO("Initialized stack");

  dump_mock_function_count_map();
}
+0 −1
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ cc_library_static {
        "src/btsnoop_net.cc",
        "src/buffer_allocator.cc",
        "src/hci_inject.cc",
        "src/hci_layer.cc",
        "src/hci_packet_factory.cc",
        "src/hci_packet_parser.cc",
        "src/packet_fragmenter.cc",
+0 −208
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2014 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_inject"

#include "hci_inject.h"

#include <base/logging.h>
#include <errno.h>
#include <string.h>

#include "bt_types.h"
#include "check.h"
#include "hci/include/buffer_allocator.h"
#include "hci_layer.h"
#include "osi/include/allocator.h"
#include "osi/include/list.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "osi/include/socket.h"
#include "osi/include/thread.h"

typedef enum {
  HCI_PACKET_COMMAND = 1,
  HCI_PACKET_ACL_DATA = 2,
  HCI_PACKET_SCO_DATA = 3,
  HCI_PACKET_EVENT = 4,
  HCI_PACKET_ISO_DATA = 5,
} hci_packet_t;

typedef struct {
  socket_t* socket;
  uint8_t buffer[65536 + 3];  // 2 bytes length prefix, 1 byte type prefix.
  size_t buffer_size;
} client_t;

static bool hci_inject_open(const hci_t* hci_interface);
static void hci_inject_close(void);
static int hci_packet_to_event(hci_packet_t packet);
static void accept_ready(socket_t* socket, void* context);
static void read_ready(socket_t* socket, void* context);
static void client_free(void* ptr);

static const port_t LISTEN_PORT = 8873;

static const hci_inject_t interface = {hci_inject_open, hci_inject_close};

static const hci_t* hci;
static const allocator_t* buffer_allocator;
static socket_t* listen_socket;
static thread_t* thread;
static list_t* clients;

static bool hci_inject_open(const hci_t* hci_interface) {
#if (BT_NET_DEBUG != true)
  return true;  // Disable using network sockets for security reasons
#endif

  CHECK(listen_socket == NULL);
  CHECK(thread == NULL);
  CHECK(clients == NULL);
  CHECK(hci_interface != NULL);

  hci = hci_interface;

  thread = thread_new("hci_inject");
  if (!thread) goto error;

  clients = list_new(client_free);
  if (!clients) goto error;

  listen_socket = socket_new();
  if (!listen_socket) goto error;

  if (!socket_listen(listen_socket, LISTEN_PORT)) goto error;

  socket_register(listen_socket, thread_get_reactor(thread), NULL, accept_ready,
                  NULL);
  return true;

error:;
  interface.close();
  return false;
}

static void hci_inject_close(void) {
#if (BT_NET_DEBUG != true)
  return;  // Disable using network sockets for security reasons
#endif

  socket_free(listen_socket);
  list_free(clients);
  thread_free(thread);

  listen_socket = NULL;
  thread = NULL;
  clients = NULL;
}

static int hci_packet_to_event(hci_packet_t packet) {
  switch (packet) {
    case HCI_PACKET_COMMAND:
      return MSG_STACK_TO_HC_HCI_CMD;
    case HCI_PACKET_ACL_DATA:
      return MSG_STACK_TO_HC_HCI_ACL;
    case HCI_PACKET_SCO_DATA:
      return MSG_STACK_TO_HC_HCI_SCO;
    case HCI_PACKET_ISO_DATA:
      return MSG_STACK_TO_HC_HCI_ISO;
    default:
      LOG_ERROR("%s unsupported packet type: %d", __func__, packet);
      return -1;
  }
}

static void accept_ready(socket_t* socket, UNUSED_ATTR void* context) {
  CHECK(socket != NULL);
  CHECK(socket == listen_socket);

  socket = socket_accept(socket);
  if (!socket) return;

  client_t* client = (client_t*)osi_calloc(sizeof(client_t));

  client->socket = socket;

  if (!list_append(clients, client)) {
    LOG_ERROR("%s unable to add client to list.", __func__);
    client_free(client);
    return;
  }

  socket_register(socket, thread_get_reactor(thread), client, read_ready, NULL);
}

static void read_ready(UNUSED_ATTR socket_t* socket, void* context) {
  CHECK(socket != NULL);
  CHECK(context != NULL);

  client_t* client = (client_t*)context;

  ssize_t ret =
      socket_read(client->socket, client->buffer + client->buffer_size,
                  sizeof(client->buffer) - client->buffer_size);
  if (ret == 0 || (ret == -1 && ret != EWOULDBLOCK && ret != EAGAIN)) {
    list_remove(clients, client);
    return;
  }
  client->buffer_size += ret;

  while (client->buffer_size > 3) {
    uint8_t* buffer = client->buffer;
    hci_packet_t packet_type = (hci_packet_t)buffer[0];
    size_t packet_len = (buffer[2] << 8) | buffer[1];
    size_t frame_len = 3 + packet_len;

    if (client->buffer_size < frame_len) break;

    // TODO(sharvil): validate incoming HCI messages.
    // TODO(sharvil): once we have an HCI parser, we can eliminate
    //   the 2-byte size field since it will be contained in the packet.

    BT_HDR* buf = (BT_HDR*)buffer_allocator->alloc(BT_HDR_SIZE + packet_len);
    if (buf) {
      buf->event = hci_packet_to_event(packet_type);
      buf->offset = 0;
      buf->layer_specific = 0;
      buf->len = packet_len;
      memcpy(buf->data, buffer + 3, packet_len);
      hci->transmit_downward(buf->event, buf);
    } else {
      LOG_ERROR("%s dropping injected packet of length %zu", __func__,
                packet_len);
    }

    size_t remainder = client->buffer_size - frame_len;
    memmove(buffer, buffer + frame_len, remainder);
    client->buffer_size -= frame_len;
  }
}

static void client_free(void* ptr) {
  if (!ptr) return;

  client_t* client = (client_t*)ptr;
  socket_free(client->socket);
  osi_free(client);
}

const hci_inject_t* hci_inject_get_interface() {
  buffer_allocator = buffer_allocator_get_interface();
  return &interface;
}
+0 −260
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  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 "check.h"
#include "common/stop_watch_legacy.h"
#include "hci/include/buffer_allocator.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) {
      btHci_1_1->initialize_1_1(callbacks);
    } else {
      btHci->initialize(callbacks);
    }
  }
}

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:
      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("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));
}
Loading