/*
 * Copyright (C) 2023 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 <VtsCoreUtil.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/bluetooth/BnBluetoothHciCallbacks.h>
#include <aidl/android/hardware/bluetooth/IBluetoothHci.h>
#include <aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.h>
#include <aidl/android/hardware/bluetooth/Status.h>
#include <android-base/properties.h>
#include <android/binder_auto_utils.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <binder/IServiceManager.h>

#include <chrono>
#include <condition_variable>
#include <future>
#include <queue>
#include <thread>
#include <utility>
#include <vector>

// TODO: Remove custom logging defines from PDL packets.
#undef LOG_INFO
#undef LOG_DEBUG
#undef LOG_TAG
#define LOG_TAG "VtsHalBluetooth"
#include "hci/hci_packets.h"
#include "packet/raw_builder.h"

using aidl::android::hardware::bluetooth::IBluetoothHci;
using aidl::android::hardware::bluetooth::IBluetoothHciCallbacks;
using aidl::android::hardware::bluetooth::Status;
using ndk::ScopedAStatus;
using ndk::SpAIBinder;

using ::bluetooth::hci::CommandBuilder;
using ::bluetooth::hci::CommandCompleteView;
using ::bluetooth::hci::CommandView;
using ::bluetooth::hci::ErrorCode;
using ::bluetooth::hci::EventView;
using ::bluetooth::hci::LeReadLocalSupportedFeaturesBuilder;
using ::bluetooth::hci::LeReadLocalSupportedFeaturesCompleteView;
using ::bluetooth::hci::LeReadNumberOfSupportedAdvertisingSetsBuilder;
using ::bluetooth::hci::LeReadNumberOfSupportedAdvertisingSetsCompleteView;
using ::bluetooth::hci::LeReadResolvingListSizeBuilder;
using ::bluetooth::hci::LeReadResolvingListSizeCompleteView;
using ::bluetooth::hci::LLFeaturesBits;
using ::bluetooth::hci::OpCode;
using ::bluetooth::hci::OpCodeText;
using ::bluetooth::hci::PacketView;
using ::bluetooth::hci::ReadLocalVersionInformationBuilder;
using ::bluetooth::hci::ReadLocalVersionInformationCompleteView;

static constexpr uint8_t kMinLeAdvSetForBt5 = 10;
static constexpr uint8_t kMinLeAdvSetForBt5ForTv = 10;
static constexpr uint8_t kMinLeResolvingListForBt5 = 8;

static constexpr size_t kNumHciCommandsBandwidth = 100;
static constexpr size_t kNumAclPacketsBandwidth = 100;
static constexpr std::chrono::milliseconds kWaitForInitTimeout(2000);
static constexpr std::chrono::milliseconds kWaitForHciEventTimeout(2000);
static constexpr std::chrono::milliseconds kWaitForAclDataTimeout(1000);
static constexpr std::chrono::milliseconds kInterfaceCloseDelayMs(200);

// To discard Qualcomm ACL debugging
static constexpr uint16_t kAclHandleQcaDebugMessage = 0xedc;

static int get_vsr_api_level() {
  int vendor_api_level =
      ::android::base::GetIntProperty("ro.vendor.api_level", -1);
  if (vendor_api_level != -1) {
    return vendor_api_level;
  }

  // Android S and older devices do not define ro.vendor.api_level
  vendor_api_level = ::android::base::GetIntProperty("ro.board.api_level", -1);
  if (vendor_api_level == -1) {
    vendor_api_level =
        ::android::base::GetIntProperty("ro.board.first_api_level", -1);
  }

  int product_api_level =
      ::android::base::GetIntProperty("ro.product.first_api_level", -1);
  if (product_api_level == -1) {
    product_api_level =
        ::android::base::GetIntProperty("ro.build.version.sdk", -1);
    EXPECT_NE(product_api_level, -1) << "Could not find ro.build.version.sdk";
  }

  // VSR API level is the minimum of vendor_api_level and product_api_level.
  if (vendor_api_level == -1 || vendor_api_level > product_api_level) {
    return product_api_level;
  }
  return vendor_api_level;
}

static bool isTv() {
  return testing::deviceSupportsFeature("android.software.leanback") ||
         testing::deviceSupportsFeature("android.hardware.type.television");
}

static bool isHandheld() {
  return testing::deviceSupportsFeature("android.hardware.type.handheld");
}

class ThroughputLogger {
 public:
  explicit ThroughputLogger(std::string task)
      : total_bytes_(0),
        task_(std::move(task)),
        start_time_(std::chrono::steady_clock::now()) {}

  ~ThroughputLogger() {
    if (total_bytes_ == 0) {
      return;
    }
    std::chrono::duration<double> duration =
        std::chrono::steady_clock::now() - start_time_;
    double s = duration.count();
    if (s == 0) {
      return;
    }
    double rate_kb = (static_cast<double>(total_bytes_) / s) / 1024;
    ALOGD("%s %.1f KB/s (%zu bytes in %.3fs)", task_.c_str(), rate_kb,
          total_bytes_, s);
  }

  void setTotalBytes(size_t total_bytes) { total_bytes_ = total_bytes; }

 private:
  size_t total_bytes_;
  std::string task_;
  std::chrono::steady_clock::time_point start_time_;
};

// The main test class for Bluetooth HAL.
class BluetoothAidlTest : public ::testing::TestWithParam<std::string> {
  std::chrono::time_point<std::chrono::system_clock>
      time_after_initialize_complete;

 public:
  void SetUp() override {
    // currently test passthrough mode only
    hci = IBluetoothHci::fromBinder(
        SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
    ASSERT_NE(hci, nullptr);
    ALOGI("%s: getService() for bluetooth hci is %s", __func__,
          hci->isRemote() ? "remote" : "local");

    // Lambda function
    auto on_binder_death = [](void* /*cookie*/) { FAIL(); };

    bluetooth_hci_death_recipient =
        AIBinder_DeathRecipient_new(on_binder_death);
    ASSERT_NE(bluetooth_hci_death_recipient, nullptr);
    ASSERT_EQ(STATUS_OK,
              AIBinder_linkToDeath(hci->asBinder().get(),
                                   bluetooth_hci_death_recipient, nullptr));

    hci_cb = ndk::SharedRefBase::make<BluetoothHciCallbacks>(*this);
    ASSERT_NE(hci_cb, nullptr);

    max_acl_data_packet_length = 0;
    max_sco_data_packet_length = 0;
    max_acl_data_packets = 0;
    max_sco_data_packets = 0;

    event_cb_count = 0;
    acl_cb_count = 0;
    sco_cb_count = 0;
    std::chrono::time_point<std::chrono::system_clock>
        timeout_after_initialize =
            std::chrono::system_clock::now() + kWaitForInitTimeout;

    ASSERT_TRUE(hci->initialize(hci_cb).isOk());
    auto future = initialized_promise.get_future();
    auto timeout_status = future.wait_for(kWaitForInitTimeout);
    ASSERT_EQ(timeout_status, std::future_status::ready);
    ASSERT_TRUE(future.get());
    ASSERT_GE(timeout_after_initialize, time_after_initialize_complete);
  }

  void TearDown() override {
    ALOGI("TearDown");
    // Should not be checked in production code
    ASSERT_TRUE(hci->close().isOk());
    std::this_thread::sleep_for(kInterfaceCloseDelayMs);
    handle_no_ops();
    discard_qca_debugging();
    EXPECT_EQ(static_cast<size_t>(0), event_queue.size());
    EXPECT_EQ(static_cast<size_t>(0), sco_queue.size());
    EXPECT_EQ(static_cast<size_t>(0), acl_queue.size());
    EXPECT_EQ(static_cast<size_t>(0), iso_queue.size());
  }

  void setBufferSizes();
  void setSynchronousFlowControlEnable();

  // Functions called from within tests in loopback mode
  void sendAndCheckHci(int num_packets);
  void sendAndCheckAcl(int num_packets, size_t size, uint16_t handle);

  // Helper functions to try to get a handle on verbosity
  void enterLoopbackMode();
  void handle_no_ops();
  void discard_qca_debugging();
  void wait_for_event(bool timeout_is_error);
  void wait_for_command_complete_event(OpCode opCode,
                                       std::vector<uint8_t>& complete_event);
  // Wait until a command complete is received.
  // Command complete will be consumed after this method
  void wait_and_validate_command_complete_event(OpCode opCode);
  int wait_for_completed_packets_event(uint16_t handle);
  void send_and_wait_for_cmd_complete(std::unique_ptr<CommandBuilder> cmd,
                                      std::vector<uint8_t>& cmd_complete);
  void reassemble_sco_loopback_pkt(std::vector<uint8_t>& scoPackets,
    size_t size);

  // A simple test implementation of BluetoothHciCallbacks.
  class BluetoothHciCallbacks
      : public aidl::android::hardware::bluetooth::BnBluetoothHciCallbacks {
    BluetoothAidlTest& parent_;

   public:
    explicit BluetoothHciCallbacks(BluetoothAidlTest& parent)
        : parent_(parent){};

    ~BluetoothHciCallbacks() override = default;

    ndk::ScopedAStatus initializationComplete(Status status) override {
      if (status == Status::SUCCESS) {
        parent_.time_after_initialize_complete =
            std::chrono::system_clock::now();
      }
      parent_.initialized_promise.set_value(status == Status::SUCCESS);
      ALOGV("%s (status = %d)", __func__, static_cast<int>(status));
      return ScopedAStatus::ok();
    };

    ndk::ScopedAStatus hciEventReceived(
        const std::vector<uint8_t>& event) override {
      parent_.event_cb_count++;
      parent_.event_queue.push(event);
      ALOGI("Event received (length = %d)", static_cast<int>(event.size()));
      return ScopedAStatus::ok();
    };

    ndk::ScopedAStatus aclDataReceived(
        const std::vector<uint8_t>& data) override {
      parent_.acl_cb_count++;
      parent_.acl_queue.push(data);
      return ScopedAStatus::ok();
    };

    ndk::ScopedAStatus scoDataReceived(
        const std::vector<uint8_t>& data) override {
      parent_.sco_cb_count++;
      parent_.sco_queue.push(data);
      return ScopedAStatus::ok();
    };

    ndk::ScopedAStatus isoDataReceived(
        const std::vector<uint8_t>& data) override {
      parent_.iso_cb_count++;
      parent_.iso_queue.push(data);
      return ScopedAStatus::ok();
    };
  };

  template <class T>
  class WaitQueue {
   public:
    WaitQueue() = default;
    ;

    virtual ~WaitQueue() = default;

    bool empty() const {
      std::lock_guard<std::mutex> lock(m_);
      return q_.empty();
    };

    size_t size() const {
      std::lock_guard<std::mutex> lock(m_);
      return q_.size();
    };

    void push(const T& v) {
      std::lock_guard<std::mutex> lock(m_);
      q_.push(v);
      ready_.notify_one();
    };

    bool pop(T& v) {
      std::lock_guard<std::mutex> lock(m_);
      if (q_.empty()) {
        return false;
      }
      v = std::move(q_.front());
      q_.pop();
      return true;
    };

    void pop() {
      std::lock_guard<std::mutex> lock(m_);
      if (q_.empty()) {
        return;
      }
      q_.pop();
    };

    bool front(T& v) {
      std::lock_guard<std::mutex> lock(m_);
      if (q_.empty()) {
        return false;
      }
      v = q_.front();
      return true;
    };

    void wait() {
      std::unique_lock<std::mutex> lock(m_);
      while (q_.empty()) {
        ready_.wait(lock);
      }
    };

    bool waitWithTimeout(std::chrono::milliseconds timeout) {
      std::unique_lock<std::mutex> lock(m_);
      while (q_.empty()) {
        if (ready_.wait_for(lock, timeout) == std::cv_status::timeout) {
          return false;
        }
      }
      return true;
    };

    bool tryPopWithTimeout(T& v, std::chrono::milliseconds timeout) {
      std::unique_lock<std::mutex> lock(m_);
      while (q_.empty()) {
        if (ready_.wait_for(lock, timeout) == std::cv_status::timeout) {
          return false;
        }
      }
      v = std::move(q_.front());
      q_.pop();
      return true;
    };

   private:
    mutable std::mutex m_;
    std::queue<T> q_;
    std::condition_variable_any ready_;
  };

  std::shared_ptr<IBluetoothHci> hci;
  std::shared_ptr<BluetoothHciCallbacks> hci_cb;
  AIBinder_DeathRecipient* bluetooth_hci_death_recipient{};
  WaitQueue<std::vector<uint8_t>> event_queue;
  WaitQueue<std::vector<uint8_t>> acl_queue;
  WaitQueue<std::vector<uint8_t>> sco_queue;
  WaitQueue<std::vector<uint8_t>> iso_queue;

  std::promise<bool> initialized_promise;
  int event_cb_count{};
  int sco_cb_count{};
  int acl_cb_count{};
  int iso_cb_count{};

  int max_acl_data_packet_length{};
  int max_sco_data_packet_length{};
  int max_acl_data_packets{};
  int max_sco_data_packets{};

  std::vector<uint16_t> sco_connection_handles;
  std::vector<uint16_t> acl_connection_handles;
};

// Discard NO-OPs from the event queue.
void BluetoothAidlTest::handle_no_ops() {
  while (!event_queue.empty()) {
    std::vector<uint8_t> event;
    event_queue.front(event);
    auto complete_view = ::bluetooth::hci::CommandCompleteView::Create(
        ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView<true>(
            std::make_shared<std::vector<uint8_t>>(event))));
    auto status_view = ::bluetooth::hci::CommandCompleteView::Create(
        ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView<true>(
            std::make_shared<std::vector<uint8_t>>(event))));
    bool is_complete_no_op =
        complete_view.IsValid() &&
        complete_view.GetCommandOpCode() == ::bluetooth::hci::OpCode::NONE;
    bool is_status_no_op =
        status_view.IsValid() &&
        status_view.GetCommandOpCode() == ::bluetooth::hci::OpCode::NONE;
    if (is_complete_no_op || is_status_no_op) {
      event_queue.pop();
    } else {
      break;
    }
  }
}

// Discard Qualcomm ACL debugging
void BluetoothAidlTest::discard_qca_debugging() {
  while (!acl_queue.empty()) {
    std::vector<uint8_t> acl_packet;
    acl_queue.front(acl_packet);
    auto acl_view =
        ::bluetooth::hci::AclView::Create(::bluetooth::hci::PacketView<true>(
            std::make_shared<std::vector<uint8_t>>(acl_packet)));
    EXPECT_TRUE(acl_view.IsValid());
    if (acl_view.GetHandle() == kAclHandleQcaDebugMessage) {
      acl_queue.pop();
    } else {
      break;
    }
  }
}

// Receive an event, discarding NO-OPs.
void BluetoothAidlTest::wait_for_event(bool timeout_is_error = true) {
  // Wait until we get something that's not a no-op.
  while (true) {
    bool event_ready = event_queue.waitWithTimeout(kWaitForHciEventTimeout);
    ASSERT_TRUE(event_ready || !timeout_is_error);
    if (event_queue.empty()) {
      // waitWithTimeout timed out
      return;
    }
    handle_no_ops();
    if (!event_queue.empty()) {
      // There's an event in the queue that's not a no-op.
      return;
    }
  }
}

void BluetoothAidlTest::wait_for_command_complete_event(
    OpCode opCode, std::vector<uint8_t>& complete_event) {
  ASSERT_NO_FATAL_FAILURE(wait_for_event());
  ASSERT_FALSE(event_queue.empty());
  ASSERT_TRUE(event_queue.pop(complete_event));
  auto complete_view = ::bluetooth::hci::CommandCompleteView::Create(
      ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView<true>(
          std::make_shared<std::vector<uint8_t>>(complete_event))));
  ASSERT_TRUE(complete_view.IsValid());
  ASSERT_EQ(complete_view.GetCommandOpCode(), opCode);
  ASSERT_EQ(complete_view.GetPayload()[0],
            static_cast<uint8_t>(::bluetooth::hci::ErrorCode::SUCCESS));
}

void BluetoothAidlTest::wait_and_validate_command_complete_event(
    ::bluetooth::hci::OpCode opCode) {
  std::vector<uint8_t> complete_event;
  ASSERT_NO_FATAL_FAILURE(
      wait_for_command_complete_event(opCode, complete_event));
}

// Send the command to read the controller's buffer sizes.
void BluetoothAidlTest::setBufferSizes() {
  std::vector<uint8_t> cmd;
  ::bluetooth::packet::BitInserter bi{cmd};
  ::bluetooth::hci::ReadBufferSizeBuilder::Create()->Serialize(bi);
  hci->sendHciCommand(cmd);

  ASSERT_NO_FATAL_FAILURE(wait_for_event());
  std::vector<uint8_t> event;
  ASSERT_TRUE(event_queue.pop(event));
  auto complete_view = ::bluetooth::hci::ReadBufferSizeCompleteView::Create(
      ::bluetooth::hci::CommandCompleteView::Create(
          ::bluetooth::hci::EventView::Create(
              ::bluetooth::hci::PacketView<true>(
                  std::make_shared<std::vector<uint8_t>>(event)))));

  ASSERT_TRUE(complete_view.IsValid());
  ASSERT_EQ(complete_view.GetStatus(), ::bluetooth::hci::ErrorCode::SUCCESS);
  max_acl_data_packet_length = complete_view.GetAclDataPacketLength();
  max_sco_data_packet_length = complete_view.GetSynchronousDataPacketLength();
  max_acl_data_packets = complete_view.GetTotalNumAclDataPackets();
  max_sco_data_packets = complete_view.GetTotalNumSynchronousDataPackets();

  ALOGD("%s: ACL max %d num %d SCO max %d num %d", __func__,
        static_cast<int>(max_acl_data_packet_length),
        static_cast<int>(max_acl_data_packets),
        static_cast<int>(max_sco_data_packet_length),
        static_cast<int>(max_sco_data_packets));
}

// Enable flow control packets for SCO
void BluetoothAidlTest::setSynchronousFlowControlEnable() {
  std::vector<uint8_t> cmd;
  ::bluetooth::packet::BitInserter bi{cmd};
  ::bluetooth::hci::WriteSynchronousFlowControlEnableBuilder::Create(
      ::bluetooth::hci::Enable::ENABLED)
      ->Serialize(bi);
  hci->sendHciCommand(cmd);

  wait_and_validate_command_complete_event(
      ::bluetooth::hci::OpCode::WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE);
}

// Send an HCI command (in Loopback mode) and check the response.
void BluetoothAidlTest::sendAndCheckHci(int num_packets) {
  ThroughputLogger logger{__func__};
  size_t command_size = 0;
  char new_name[] = "John Jacob Jingleheimer Schmidt ___________________";
  size_t new_name_length = strlen(new_name);
  for (int n = 0; n < num_packets; n++) {
    // The name to set is new_name
    std::array<uint8_t, 248> name_array{};
    for (size_t i = 0; i < new_name_length; i++) {
      name_array[i] = new_name[i];
    }
    // And the packet number
    char number[11] = "0000000000";
    snprintf(number, sizeof(number), "%010d", static_cast<int>(n));
    for (size_t i = new_name_length; i < new_name_length + sizeof(number) - 1;
         i++) {
      name_array[new_name_length + i] = number[i];
    }
    std::vector<uint8_t> write_name;
    ::bluetooth::packet::BitInserter bi{write_name};
    ::bluetooth::hci::WriteLocalNameBuilder::Create(name_array)->Serialize(bi);
    hci->sendHciCommand(write_name);

    // Check the loopback of the HCI packet
    ASSERT_NO_FATAL_FAILURE(wait_for_event());

    std::vector<uint8_t> event;
    ASSERT_TRUE(event_queue.pop(event));
    auto event_view = ::bluetooth::hci::LoopbackCommandView::Create(
        ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView<true>(
            std::make_shared<std::vector<uint8_t>>(event))));
    ASSERT_TRUE(event_view.IsValid());
    std::vector<uint8_t> looped_back_command{event_view.GetPayload().begin(),
                                             event_view.GetPayload().end()};
    ASSERT_EQ(looped_back_command, write_name);

    if (n == num_packets - 1) {
      command_size = write_name.size();
    }
  }
  logger.setTotalBytes(command_size * num_packets * 2);
}

// Send an ACL data packet (in Loopback mode) and check the response.
void BluetoothAidlTest::sendAndCheckAcl(int num_packets, size_t size,
                                        uint16_t handle) {
  ThroughputLogger logger{__func__};
  for (int n = 0; n < num_packets; n++) {
    // Send an ACL packet with counting data
    auto payload = std::make_unique<::bluetooth::packet::RawBuilder>();
    for (size_t i = 0; i < size; i++) {
      payload->AddOctets1(static_cast<uint8_t>(i + n));
    }
    std::vector<uint8_t> acl_packet;
    ::bluetooth::packet::BitInserter bi{acl_packet};
    ::bluetooth::hci::AclBuilder::Create(
        handle,
        ::bluetooth::hci::PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE,
        ::bluetooth::hci::BroadcastFlag::POINT_TO_POINT, std::move(payload))
        ->Serialize(bi);
    hci->sendAclData(acl_packet);

    std::vector<uint8_t> acl_loopback;
    // Check the loopback of the ACL packet
    ASSERT_TRUE(
        acl_queue.tryPopWithTimeout(acl_loopback, kWaitForAclDataTimeout));

    ASSERT_EQ(acl_packet, acl_loopback);
  }
  logger.setTotalBytes(num_packets * size * 2);
}

// Return the number of completed packets reported by the controller.
int BluetoothAidlTest::wait_for_completed_packets_event(uint16_t handle) {
  int packets_processed = 0;
  while (true) {
    // There should be at least one event.
    wait_for_event(packets_processed == 0);
    if (event_queue.empty()) {
      if (packets_processed == 0) {
        ALOGW("%s: waitForBluetoothCallback timed out.", __func__);
      }
      return packets_processed;
    }
    std::vector<uint8_t> event;
    EXPECT_TRUE(event_queue.pop(event));
    auto event_view = ::bluetooth::hci::NumberOfCompletedPacketsView::Create(
        ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView<true>(
            std::make_shared<std::vector<uint8_t>>(event))));
    if (!event_view.IsValid()) {
      ADD_FAILURE();
      return packets_processed;
    }
    auto completed_packets = event_view.GetCompletedPackets();
    for (const auto& entry : completed_packets) {
      EXPECT_EQ(handle, entry.connection_handle_);
      packets_processed += entry.host_num_of_completed_packets_;
    }
  }
  return packets_processed;
}

// Send local loopback command and initialize SCO and ACL handles.
void BluetoothAidlTest::enterLoopbackMode() {
  std::vector<uint8_t> cmd;
  ::bluetooth::packet::BitInserter bi{cmd};
  ::bluetooth::hci::WriteLoopbackModeBuilder::Create(
      bluetooth::hci::LoopbackMode::ENABLE_LOCAL)
      ->Serialize(bi);
  hci->sendHciCommand(cmd);

  // Receive connection complete events with data channels
  int connection_event_count = 0;
  bool command_complete_received = false;
  while (true) {
    wait_for_event(false);
    if (event_queue.empty()) {
      // Fail if there was no event received or no connections completed.
      ASSERT_TRUE(command_complete_received);
      ASSERT_LT(0, connection_event_count);
      return;
    }
    std::vector<uint8_t> event;
    ASSERT_TRUE(event_queue.pop(event));
    auto event_view =
        ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView<true>(
            std::make_shared<std::vector<uint8_t>>(event)));
    ASSERT_TRUE(event_view.IsValid());

    if (event_view.GetEventCode() ==
        ::bluetooth::hci::EventCode::CONNECTION_COMPLETE) {
      auto complete_view =
          ::bluetooth::hci::ConnectionCompleteView::Create(event_view);
      ASSERT_TRUE(complete_view.IsValid());
      switch (complete_view.GetLinkType()) {
        case ::bluetooth::hci::LinkType::ACL:
          acl_connection_handles.push_back(complete_view.GetConnectionHandle());
          break;
        case ::bluetooth::hci::LinkType::SCO:
          sco_connection_handles.push_back(complete_view.GetConnectionHandle());
          break;
        default:
          ASSERT_EQ(complete_view.GetLinkType(),
                    ::bluetooth::hci::LinkType::ACL);
      }
      connection_event_count++;
    } else {
      auto command_complete_view =
          ::bluetooth::hci::WriteLoopbackModeCompleteView::Create(
              ::bluetooth::hci::CommandCompleteView::Create(event_view));
      ASSERT_TRUE(command_complete_view.IsValid());
      ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS,
                command_complete_view.GetStatus());
      command_complete_received = true;
    }
  }
}

void BluetoothAidlTest::send_and_wait_for_cmd_complete(
    std::unique_ptr<CommandBuilder> cmd, std::vector<uint8_t>& cmd_complete) {
  std::vector<uint8_t> cmd_bytes = cmd->SerializeToBytes();
  hci->sendHciCommand(cmd_bytes);

  auto view = CommandView::Create(
      PacketView<true>(std::make_shared<std::vector<uint8_t>>(cmd_bytes)));
  ASSERT_TRUE(view.IsValid());
  ALOGI("Waiting for %s[0x%x]", OpCodeText(view.GetOpCode()).c_str(),
        static_cast<int>(view.GetOpCode()));
  ASSERT_NO_FATAL_FAILURE(
      wait_for_command_complete_event(view.GetOpCode(), cmd_complete));
}

// Empty test: Initialize()/Close() are called in SetUp()/TearDown().
TEST_P(BluetoothAidlTest, InitializeAndClose) {}

// Send an HCI Reset with sendHciCommand and wait for a command complete event.
TEST_P(BluetoothAidlTest, HciReset) {
  std::vector<uint8_t> reset;
  ::bluetooth::packet::BitInserter bi{reset};
  ::bluetooth::hci::ResetBuilder::Create()->Serialize(bi);
  hci->sendHciCommand(reset);

  wait_and_validate_command_complete_event(::bluetooth::hci::OpCode::RESET);
}

// Read and check the HCI version of the controller.
TEST_P(BluetoothAidlTest, HciVersionTest) {
  std::vector<uint8_t> cmd;
  ::bluetooth::packet::BitInserter bi{cmd};
  ::bluetooth::hci::ReadLocalVersionInformationBuilder::Create()->Serialize(bi);
  hci->sendHciCommand(cmd);

  ASSERT_NO_FATAL_FAILURE(wait_for_event());

  std::vector<uint8_t> event;
  ASSERT_TRUE(event_queue.pop(event));
  auto complete_view =
      ::bluetooth::hci::ReadLocalVersionInformationCompleteView::Create(
          ::bluetooth::hci::CommandCompleteView::Create(
              ::bluetooth::hci::EventView::Create(
                  ::bluetooth::hci::PacketView<true>(
                      std::make_shared<std::vector<uint8_t>>(event)))));
  ASSERT_TRUE(complete_view.IsValid());
  ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, complete_view.GetStatus());
  auto version = complete_view.GetLocalVersionInformation();
  ASSERT_LE(::bluetooth::hci::HciVersion::V_3_0, version.hci_version_);
  ASSERT_LE(::bluetooth::hci::LmpVersion::V_3_0, version.lmp_version_);
}

// Send an unknown HCI command and wait for the error message.
TEST_P(BluetoothAidlTest, HciUnknownCommand) {
  std::vector<uint8_t> cmd;
  ::bluetooth::packet::BitInserter bi{cmd};
  ::bluetooth::hci::CommandBuilder::Create(
      static_cast<::bluetooth::hci::OpCode>(0x3cff),
      std::make_unique<::bluetooth::packet::RawBuilder>())
      ->Serialize(bi);
  hci->sendHciCommand(cmd);

  ASSERT_NO_FATAL_FAILURE(wait_for_event());

  std::vector<uint8_t> event;
  ASSERT_TRUE(event_queue.pop(event));
  auto event_view =
      ::bluetooth::hci::EventView::Create(::bluetooth::hci::PacketView<true>(
          std::make_shared<std::vector<uint8_t>>(event)));
  ASSERT_TRUE(event_view.IsValid());

  switch (event_view.GetEventCode()) {
    case ::bluetooth::hci::EventCode::COMMAND_COMPLETE: {
      auto command_complete =
          ::bluetooth::hci::CommandCompleteView::Create(event_view);
      ASSERT_TRUE(command_complete.IsValid());
      ASSERT_EQ(command_complete.GetPayload()[0],
                static_cast<uint8_t>(
                    ::bluetooth::hci::ErrorCode::UNKNOWN_HCI_COMMAND));
    } break;
    case ::bluetooth::hci::EventCode::COMMAND_STATUS: {
      auto command_status =
          ::bluetooth::hci::CommandStatusView::Create(event_view);
      ASSERT_TRUE(command_status.IsValid());
      ASSERT_EQ(command_status.GetStatus(),
                ::bluetooth::hci::ErrorCode::UNKNOWN_HCI_COMMAND);
    } break;
    default:
      ADD_FAILURE();
  }
}

// Enter loopback mode, but don't send any packets.
TEST_P(BluetoothAidlTest, WriteLoopbackMode) { enterLoopbackMode(); }

// Enter loopback mode and send a single command.
TEST_P(BluetoothAidlTest, LoopbackModeSingleCommand) {
  setBufferSizes();

  enterLoopbackMode();

  sendAndCheckHci(1);
}

// Enter loopback mode and send a single ACL packet.
TEST_P(BluetoothAidlTest, LoopbackModeSingleAcl) {
  setBufferSizes();

  enterLoopbackMode();

  if (!acl_connection_handles.empty()) {
    ASSERT_LT(0, max_acl_data_packet_length);
    sendAndCheckAcl(1, max_acl_data_packet_length - 1,
                    acl_connection_handles[0]);
    int acl_packets_sent = 1;
    int completed_packets =
        wait_for_completed_packets_event(acl_connection_handles[0]);
    if (acl_packets_sent != completed_packets) {
      ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
            acl_packets_sent, completed_packets);
    }
  }
  ASSERT_GE(acl_cb_count, 1);
}

// Enter loopback mode and send command packets for bandwidth measurements.
TEST_P(BluetoothAidlTest, LoopbackModeCommandBandwidth) {
  setBufferSizes();

  enterLoopbackMode();

  sendAndCheckHci(kNumHciCommandsBandwidth);
}

// Enter loopback mode and send packets for ACL bandwidth measurements.
TEST_P(BluetoothAidlTest, LoopbackModeAclBandwidth) {
  setBufferSizes();

  enterLoopbackMode();

  if (!acl_connection_handles.empty()) {
    ASSERT_LT(0, max_acl_data_packet_length);
    sendAndCheckAcl(kNumAclPacketsBandwidth, max_acl_data_packet_length - 1,
                    acl_connection_handles[0]);
    int acl_packets_sent = kNumAclPacketsBandwidth;
    int completed_packets =
        wait_for_completed_packets_event(acl_connection_handles[0]);
    if (acl_packets_sent != completed_packets) {
      ALOGW("%s: packets_sent (%d) != completed_packets (%d)", __func__,
            acl_packets_sent, completed_packets);
    }
  }
}

// Set all bits in the event mask
TEST_P(BluetoothAidlTest, SetEventMask) {
  std::vector<uint8_t> cmd;
  ::bluetooth::packet::BitInserter bi{cmd};
  uint64_t full_mask = UINT64_MAX;
  ::bluetooth::hci::SetEventMaskBuilder::Create(full_mask)->Serialize(bi);
  hci->sendHciCommand(cmd);
  wait_and_validate_command_complete_event(
      ::bluetooth::hci::OpCode::SET_EVENT_MASK);
}

// Set all bits in the LE event mask
TEST_P(BluetoothAidlTest, SetLeEventMask) {
  std::vector<uint8_t> cmd;
  ::bluetooth::packet::BitInserter bi{cmd};
  uint64_t full_mask = UINT64_MAX;
  ::bluetooth::hci::LeSetEventMaskBuilder::Create(full_mask)->Serialize(bi);
  hci->sendHciCommand(cmd);
  wait_and_validate_command_complete_event(
      ::bluetooth::hci::OpCode::LE_SET_EVENT_MASK);
}

// Call initialize twice, second one should fail.
TEST_P(BluetoothAidlTest, CallInitializeTwice) {
  class SecondCb
      : public aidl::android::hardware::bluetooth::BnBluetoothHciCallbacks {
   public:
    ndk::ScopedAStatus initializationComplete(Status status) override {
      EXPECT_EQ(status, Status::ALREADY_INITIALIZED);
      init_promise.set_value();
      return ScopedAStatus::ok();
    };

    ndk::ScopedAStatus hciEventReceived(
        const std::vector<uint8_t>& /*event*/) override {
      ADD_FAILURE();
      return ScopedAStatus::ok();
    };

    ndk::ScopedAStatus aclDataReceived(
        const std::vector<uint8_t>& /*data*/) override {
      ADD_FAILURE();
      return ScopedAStatus::ok();
    };

    ndk::ScopedAStatus scoDataReceived(
        const std::vector<uint8_t>& /*data*/) override {
      ADD_FAILURE();
      return ScopedAStatus::ok();
    };

    ndk::ScopedAStatus isoDataReceived(
        const std::vector<uint8_t>& /*data*/) override {
      ADD_FAILURE();
      return ScopedAStatus::ok();
    };
    std::promise<void> init_promise;
  };

  std::shared_ptr<SecondCb> second_cb = ndk::SharedRefBase::make<SecondCb>();
  ASSERT_NE(second_cb, nullptr);

  auto future = second_cb->init_promise.get_future();
  ASSERT_TRUE(hci->initialize(second_cb).isOk());
  auto status = future.wait_for(std::chrono::seconds(1));
  ASSERT_EQ(status, std::future_status::ready);
}

// @VsrTest = 5.3.14-001
// @VsrTest = 5.3.14-002
// @VsrTest = 5.3.14-004
TEST_P(BluetoothAidlTest, Vsr_Bluetooth5Requirements) {
  int api_level = get_vsr_api_level();
  if (api_level < __ANDROID_API_U__) {
    GTEST_SKIP() << "API level is lower than 34";
    return;
  }

  std::vector<uint8_t> version_event;
  send_and_wait_for_cmd_complete(ReadLocalVersionInformationBuilder::Create(),
                                 version_event);
  auto version_view = ReadLocalVersionInformationCompleteView::Create(
      CommandCompleteView::Create(EventView::Create(PacketView<true>(
          std::make_shared<std::vector<uint8_t>>(version_event)))));
  ASSERT_TRUE(version_view.IsValid());
  ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, version_view.GetStatus());
  auto version = version_view.GetLocalVersionInformation();

  if (version.hci_version_ < ::bluetooth::hci::HciVersion::V_5_0) {
    GTEST_SKIP() << "Bluetooth version is lower than 5.0";
    return;
  }

  // When HCI version is 5.0, LMP version must also be at least 5.0
  ASSERT_GE(static_cast<int>(version.lmp_version_),
            static_cast<int>(version.hci_version_));

  std::vector<uint8_t> le_features_event;
  send_and_wait_for_cmd_complete(LeReadLocalSupportedFeaturesBuilder::Create(),
                                 le_features_event);
  auto le_features_view = LeReadLocalSupportedFeaturesCompleteView::Create(
      CommandCompleteView::Create(EventView::Create(PacketView<true>(
          std::make_shared<std::vector<uint8_t>>(le_features_event)))));
  ASSERT_TRUE(le_features_view.IsValid());
  ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, le_features_view.GetStatus());

  // CHIPSETs that set ro.board.api_level to 34 and report 5.0 or higher for
  // the Bluetooth version through the IBluetoothHci HAL:
  //
  // [VSR-5.3.14-001] Must return TRUE for
  //   - LE 2M PHY
  //   - LE Coded PHY
  //   - LE Advertising Extension
  //   - LE Periodic Advertising
  //   - LE Link Layer Privacy
  auto le_features = le_features_view.GetLeFeatures();
  ASSERT_TRUE(le_features & static_cast<uint64_t>(LLFeaturesBits::LL_PRIVACY));
  ASSERT_TRUE(le_features & static_cast<uint64_t>(LLFeaturesBits::LE_2M_PHY));
  ASSERT_TRUE(le_features &
              static_cast<uint64_t>(LLFeaturesBits::LE_CODED_PHY));
  ASSERT_TRUE(le_features &
              static_cast<uint64_t>(LLFeaturesBits::LE_EXTENDED_ADVERTISING));
  ASSERT_TRUE(le_features &
              static_cast<uint64_t>(LLFeaturesBits::LE_PERIODIC_ADVERTISING));

  std::vector<uint8_t> num_adv_set_event;
  send_and_wait_for_cmd_complete(
      LeReadNumberOfSupportedAdvertisingSetsBuilder::Create(),
      num_adv_set_event);
  auto num_adv_set_view =
      LeReadNumberOfSupportedAdvertisingSetsCompleteView::Create(
          CommandCompleteView::Create(EventView::Create(PacketView<true>(
              std::make_shared<std::vector<uint8_t>>(num_adv_set_event)))));
  ASSERT_TRUE(num_adv_set_view.IsValid());
  ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, num_adv_set_view.GetStatus());
  auto num_adv_set = num_adv_set_view.GetNumberSupportedAdvertisingSets();

  // CHIPSETs that set ro.board.api_level to 34 and report 5.0 or higher for
  // the Bluetooth version through the IBluetoothHci HAL:
  //
  // [VSR-5.3.14-002] MUST support at least 10 advertising sets.
  if (isTv() && get_vsr_api_level() == __ANDROID_API_U__) {
    ASSERT_GE(num_adv_set, kMinLeAdvSetForBt5ForTv);
  } else {
    ASSERT_GE(num_adv_set, kMinLeAdvSetForBt5);
  }

  std::vector<uint8_t> num_resolving_list_event;
  send_and_wait_for_cmd_complete(LeReadResolvingListSizeBuilder::Create(),
                                 num_resolving_list_event);
  auto num_resolving_list_view = LeReadResolvingListSizeCompleteView::Create(
      CommandCompleteView::Create(EventView::Create(PacketView<true>(
          std::make_shared<std::vector<uint8_t>>(num_resolving_list_event)))));
  ASSERT_TRUE(num_resolving_list_view.IsValid());
  ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS,
            num_resolving_list_view.GetStatus());
  auto num_resolving_list = num_resolving_list_view.GetResolvingListSize();

  // CHIPSETs that set ro.board.api_level to 34 and report 5.0 or higher for
  // the Bluetooth version through the IBluetoothHci HAL:
  //
  // [VSR-5.3.14-004] MUST support a resolving list size of at least 8 entries.
  ASSERT_GE(num_resolving_list, kMinLeResolvingListForBt5);
}

/**
 * VSR-5.3.14-007 MUST support Bluetooth 4.2 and Bluetooth LE Data Length Extension.
 * VSR-5.3.14-008 MUST support Bluetooth Low Energy (BLE).
 */
// @VsrTest = 5.3.14-007
// @VsrTest = 5.3.14-008
TEST_P(BluetoothAidlTest, Vsr_Bluetooth4_2Requirements) {
  // test only applies to handheld devices
  if (!isHandheld()) {
    return;
  }

  std::vector<uint8_t> version_event;
  send_and_wait_for_cmd_complete(ReadLocalVersionInformationBuilder::Create(),
                                 version_event);
  auto version_view = ReadLocalVersionInformationCompleteView::Create(
      CommandCompleteView::Create(EventView::Create(PacketView<true>(
          std::make_shared<std::vector<uint8_t>>(version_event)))));
  ASSERT_TRUE(version_view.IsValid());
  ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, version_view.GetStatus());
  auto version = version_view.GetLocalVersionInformation();
  // Starting with Android 15, Fails when HCI version is lower than 4.2.
  ASSERT_GE(static_cast<int>(version.hci_version_),
    static_cast<int>(::bluetooth::hci::HciVersion::V_4_2));
  ASSERT_GE(static_cast<int>(version.lmp_version_),
    static_cast<int>(::bluetooth::hci::LmpVersion::V_4_2));

  std::vector<uint8_t> le_features_event;
  send_and_wait_for_cmd_complete(LeReadLocalSupportedFeaturesBuilder::Create(),
                                 le_features_event);
  auto le_features_view = LeReadLocalSupportedFeaturesCompleteView::Create(
      CommandCompleteView::Create(EventView::Create(PacketView<true>(
          std::make_shared<std::vector<uint8_t>>(le_features_event)))));
  ASSERT_TRUE(le_features_view.IsValid());
  ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, le_features_view.GetStatus());
  auto le_features = le_features_view.GetLeFeatures();
  ASSERT_TRUE(le_features &
              static_cast<uint64_t>(LLFeaturesBits::LE_EXTENDED_ADVERTISING));

}

/**
 * VSR-5.3.14-012 MUST support at least eight LE concurrent connections with
 *                three in peripheral role.
 */
// @VsrTest = 5.3.14-012
TEST_P(BluetoothAidlTest, Vsr_BlE_Connection_Requirement) {
  std::vector<uint8_t> version_event;
  send_and_wait_for_cmd_complete(ReadLocalVersionInformationBuilder::Create(),
                                 version_event);
  auto version_view = ReadLocalVersionInformationCompleteView::Create(
      CommandCompleteView::Create(EventView::Create(PacketView<true>(
          std::make_shared<std::vector<uint8_t>>(version_event)))));
  ASSERT_TRUE(version_view.IsValid());
  ASSERT_EQ(::bluetooth::hci::ErrorCode::SUCCESS, version_view.GetStatus());
  auto version = version_view.GetLocalVersionInformation();
  if (version.hci_version_ < ::bluetooth::hci::HciVersion::V_5_0) {
    // This test does not apply to controllers below 5.0
    return;
  };

  int max_connections = ::android::base::GetIntProperty(
      "bluetooth.core.le.max_number_of_concurrent_connections", -1);
  if (max_connections == -1) {
    // With the property not set the default minimum of 8 will be used
    ALOGI("Max number of LE concurrent connections isn't set");
    return;
  }
  ALOGI("Max number of LE concurrent connections = %d", max_connections);
  ASSERT_GE(max_connections, 8);
}

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothAidlTest);
INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAidlTest,
                         testing::ValuesIn(android::getAidlHalInstanceNames(
                             IBluetoothHci::descriptor)),
                         android::PrintInstanceNameToString);

int main(int argc, char** argv) {
  ABinderProcess_startThreadPool();
  ::testing::InitGoogleTest(&argc, argv);
  int status = RUN_ALL_TESTS();
  ALOGI("Test result = %d", status);
  return status;
}
