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

Commit 3b7fc5a4 authored by Jack He's avatar Jack He Committed by Hansong Zhang
Browse files

Simple btsnoop logger implementation

Test: run unit test and check btsnoop log
Change-Id: Ib5ea3fc6440c48e1a7b5d5f3bcc3a0b1c23ac9c2
parent 34b1dc53
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ cc_library {
    srcs: [
        "stack_manager.cc",
        ":BluetoothCommonSources",
        ":BluetoothHalSources",
        ":BluetoothPacketSources",
    ]
}
+7 −0
Original line number Diff line number Diff line
filegroup {
    name: "BluetoothHalSources",
    srcs: [
        "bluetooth_snoop_logger.cc",
    ],
}

filegroup {
    name: "BluetoothHalSources_hci_rootcanal",
    srcs: [
+120 −0
Original line number Diff line number Diff line
/*
 * 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/bluetooth_snoop_logger.h"

#include <arpa/inet.h>
#include <netinet/in.h>
#include <bitset>
#include <chrono>

#include "os/log.h"

namespace bluetooth {
namespace hal {

namespace {
typedef struct {
  uint32_t length_original;
  uint32_t length_captured;
  uint32_t flags;
  uint32_t dropped_packets;
  uint64_t timestamp;
  uint8_t type;
} __attribute__((__packed__)) btsnoop_packet_header_t;

typedef struct {
  uint8_t identification_pattern[8];
  uint32_t version_number;
  uint32_t datalink_type;
} __attribute__((__packed__)) btsnoop_file_header_t;

constexpr uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;

constexpr uint32_t kBytesToTest = 0x12345678;
constexpr uint8_t kFirstByte = (const uint8_t&)kBytesToTest;
constexpr bool isLittleEndian = kFirstByte == 0x78;
constexpr bool isBigEndian = kFirstByte == 0x12;
static_assert(isLittleEndian || isBigEndian && isLittleEndian != isBigEndian);

constexpr uint32_t BTSNOOP_VERSION_NUMBER = isLittleEndian ? 0x01000000 : 1;
constexpr uint32_t BTSNOOP_DATALINK_TYPE =
    isLittleEndian ? 0xea030000 : 0x03ea;  // Datalink Type code for HCI UART (H4) is 1002
uint64_t htonll(uint64_t ll) {
  if constexpr (isLittleEndian) {
    return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 | htonl(ll >> 32);
  } else {
    return ll;
  }
}

constexpr btsnoop_file_header_t BTSNOOP_FILE_HEADER = {
    .identification_pattern = {'b', 't', 's', 'n', 'o', 'o', 'p', 0x00},
    .version_number = BTSNOOP_VERSION_NUMBER,
    .datalink_type = BTSNOOP_DATALINK_TYPE};
}  // namespace

BluetoothSnoopLogger::BluetoothSnoopLogger(const std::string& filename) {
  {
    std::ifstream btsnoop_istream(filename);
    file_exists_ = btsnoop_istream.is_open();
  }
  btsnoop_ostream_.open(filename, std::ios::binary | std::ios::app | std::ios::out);
  if (!file_exists_) {
    LOG_INFO("Creating new BTSNOOP");
    btsnoop_ostream_.write(reinterpret_cast<const char*>(&BTSNOOP_FILE_HEADER), sizeof(btsnoop_file_header_t));
  } else {
    LOG_INFO("Appending to old BTSNOOP");
  }
}

void BluetoothSnoopLogger::capture(const HciPacket& packet, Direction direction, PacketType type) {
  uint64_t timestamp_us =
      std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch())
          .count();
  std::lock_guard<std::mutex> lock(file_mutex_);
  std::bitset<32> flags = 0;
  switch (type) {
    case PacketType::CMD:
      flags.set(0, false);
      flags.set(1, true);
      break;
    case PacketType::ACL:
      flags.set(0, direction == Direction::INCOMING);
      flags.set(1, false);
      break;
    case PacketType::SCO:
      flags.set(0, direction == Direction::INCOMING);
      flags.set(1, false);
      break;
    case PacketType::EVT:
      flags.set(0, true);
      flags.set(1, true);
      break;
  }
  uint32_t length = packet.size() + /* type byte */ 1;
  btsnoop_packet_header_t header = {.length_original = htonl(length),
                                    .length_captured = htonl(length),
                                    .flags = htonl(static_cast<uint32_t>(flags.to_ulong())),
                                    .dropped_packets = 0,
                                    .timestamp = htonll(timestamp_us + BTSNOOP_EPOCH_DELTA),
                                    .type = static_cast<uint8_t>(type)};
  btsnoop_ostream_.write(reinterpret_cast<const char*>(&header), sizeof(btsnoop_packet_header_t));
  btsnoop_ostream_.write(reinterpret_cast<const char*>(packet.data()), packet.size());
}

}  // namespace hal
}  // namespace bluetooth
+54 −0
Original line number Diff line number Diff line
/*
 * 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

#include <fstream>
#include <iostream>
#include <mutex>
#include <string>

#include "hal/hci_hal.h"

namespace bluetooth {
namespace hal {

class BluetoothSnoopLogger {
 public:
  explicit BluetoothSnoopLogger(const std::string& filename);

  enum class PacketType {
    CMD = 1,
    ACL = 2,
    SCO = 3,
    EVT = 4,
  };

  enum class Direction {
    INCOMING,
    OUTGOING,
  };

  void capture(const HciPacket& packet, Direction direction, PacketType type);

 private:
  bool file_exists_;
  std::ofstream btsnoop_ostream_;
  std::mutex file_mutex_;
};

}  // namespace hal
}  // namespace bluetooth
+27 −7
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
#include <android/hardware/bluetooth/1.0/types.h>

#include "hal/bluetooth_snoop_logger.h"
#include "os/log.h"

using ::android::hardware::hidl_vec;
@@ -35,6 +36,8 @@ using HidlStatus = ::android::hardware::bluetooth::V1_0::Status;
namespace bluetooth {
namespace hal {
namespace {
constexpr char kDefaultBtsnoopPath[] = "/data/misc/bluetooth/logs/btsnoop_hci.log";

class BluetoothHciDeathRecipient : public ::android::hardware::hidl_death_recipient {
 public:
  virtual void serviceDied(uint64_t /*cookie*/, const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
@@ -47,8 +50,9 @@ android::sp<BluetoothHciDeathRecipient> bluetooth_hci_death_recipient_ = new Blu

class HciHalBluetoothHciCallbacks : public IBluetoothHciCallbacks {
 public:
  HciHalBluetoothHciCallbacks(BluetoothInitializationCompleteCallback* initialization_callback)
      : initialization_callback_(initialization_callback) {}
  HciHalBluetoothHciCallbacks(BluetoothInitializationCompleteCallback* initialization_callback,
                              BluetoothSnoopLogger* btsnoop_logger)
      : initialization_callback_(initialization_callback), btsnoop_logger_(btsnoop_logger) {}

  void SetCallback(BluetoothHciHalCallbacks* callback) {
    ASSERT(callback_ == nullptr && callback != nullptr);
@@ -66,22 +70,31 @@ class HciHalBluetoothHciCallbacks : public IBluetoothHciCallbacks {
  }

  Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
    std::vector<uint8_t> received_hci_packet(event.begin(), event.end());
    btsnoop_logger_->capture(received_hci_packet, BluetoothSnoopLogger::Direction::INCOMING,
                             BluetoothSnoopLogger::PacketType::EVT);
    if (callback_ != nullptr) {
      callback_->hciEventReceived(std::vector<uint8_t>(event.begin(), event.end()));
      callback_->hciEventReceived(std::move(received_hci_packet));
    }
    return Void();
  }

  Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
    std::vector<uint8_t> received_hci_packet(data.begin(), data.end());
    btsnoop_logger_->capture(received_hci_packet, BluetoothSnoopLogger::Direction::INCOMING,
                             BluetoothSnoopLogger::PacketType::ACL);
    if (callback_ != nullptr) {
      callback_->aclDataReceived(std::vector<uint8_t>(data.begin(), data.end()));
      callback_->aclDataReceived(std::move(received_hci_packet));
    }
    return Void();
  }

  Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
    std::vector<uint8_t> received_hci_packet(data.begin(), data.end());
    btsnoop_logger_->capture(received_hci_packet, BluetoothSnoopLogger::Direction::INCOMING,
                             BluetoothSnoopLogger::PacketType::SCO);
    if (callback_ != nullptr) {
      callback_->scoDataReceived(std::vector<uint8_t>(data.begin(), data.end()));
      callback_->scoDataReceived(std::move(received_hci_packet));
    }
    return Void();
  }
@@ -89,6 +102,7 @@ class HciHalBluetoothHciCallbacks : public IBluetoothHciCallbacks {
 private:
  BluetoothInitializationCompleteCallback* initialization_callback_ = nullptr;
  BluetoothHciHalCallbacks* callback_ = nullptr;
  BluetoothSnoopLogger* btsnoop_logger_ = nullptr;
};

}  // namespace
@@ -96,14 +110,14 @@ class HciHalBluetoothHciCallbacks : public IBluetoothHciCallbacks {
class BluetoothHciHalHidl : public BluetoothHciHal {
 public:
  void initialize(BluetoothInitializationCompleteCallback* callback) override {
    btsnoop_logger_ = new BluetoothSnoopLogger(kDefaultBtsnoopPath);
    bt_hci_ = IBluetoothHci::getService();
    ASSERT(bt_hci_ != nullptr);
    auto death_link = bt_hci_->linkToDeath(bluetooth_hci_death_recipient_, 0);
    ASSERT_LOG(death_link.isOk(), "Unable to set the death recipient for the Bluetooth HAL");

    // Block allows allocation of a variable that might be bypassed by goto.
    {
      callbacks_ = new HciHalBluetoothHciCallbacks(callback);
      callbacks_ = new HciHalBluetoothHciCallbacks(callback, btsnoop_logger_);
      bt_hci_->initialize(callbacks_);
    }
  }
@@ -113,14 +127,17 @@ class BluetoothHciHalHidl : public BluetoothHciHal {
  }

  void sendHciCommand(HciPacket command) override {
    btsnoop_logger_->capture(command, BluetoothSnoopLogger::Direction::OUTGOING, BluetoothSnoopLogger::PacketType::CMD);
    bt_hci_->sendHciCommand(command);
  }

  void sendAclData(HciPacket packet) override {
    btsnoop_logger_->capture(packet, BluetoothSnoopLogger::Direction::OUTGOING, BluetoothSnoopLogger::PacketType::ACL);
    bt_hci_->sendAclData(packet);
  }

  void sendScoData(HciPacket packet) override {
    btsnoop_logger_->capture(packet, BluetoothSnoopLogger::Direction::OUTGOING, BluetoothSnoopLogger::PacketType::SCO);
    bt_hci_->sendScoData(packet);
  }

@@ -133,11 +150,14 @@ class BluetoothHciHalHidl : public BluetoothHciHal {
    bt_hci_->close();
    callbacks_->ResetCallback();
    bt_hci_ = nullptr;
    delete btsnoop_logger_;
    btsnoop_logger_ = nullptr;
  }

 private:
  android::sp<HciHalBluetoothHciCallbacks> callbacks_;
  android::sp<IBluetoothHci> bt_hci_;
  BluetoothSnoopLogger* btsnoop_logger_;
};

BluetoothHciHal* GetBluetoothHciHal() {
Loading