/******************************************************************************
 *
 *  Copyright (C) 2016 The Linux Foundation
 *  Copyright 2009-2012 Broadcom Corporation
 *
 *  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.
 *
 ******************************************************************************/

/*******************************************************************************
 *
 *  Filename:      bluetooth.c
 *
 *  Description:   Bluetooth HAL implementation
 *
 ******************************************************************************/

#define LOG_TAG "bt_btif"

#include "hardware/bluetooth.h"

#include <base/functional/bind.h>
#include <base/functional/callback.h>
#include <bluetooth/log.h>

#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <utility>
#include <vector>

#include "bta/hh/bta_hh_int.h"
#include "bta/include/bta_api.h"
#include "bta/include/bta_ar_api.h"
#include "bta/include/bta_av_api.h"
#include "bta/include/bta_csis_api.h"
#include "bta/include/bta_has_api.h"
#include "bta/include/bta_hearing_aid_api.h"
#include "bta/include/bta_hf_client_api.h"
#include "bta/include/bta_le_audio_api.h"
#include "bta/include/bta_le_audio_broadcaster_api.h"
#include "bta/include/bta_vc_api.h"
#include "btif/avrcp/avrcp_service.h"
#include "btif/include/btif_a2dp.h"
#include "btif/include/btif_a2dp_source.h"
#include "btif/include/btif_api.h"
#include "btif/include/btif_av.h"
#include "btif/include/btif_bqr.h"
#include "btif/include/btif_common.h"
#include "btif/include/btif_config.h"
#include "btif/include/btif_debug_conn.h"
#include "btif/include/btif_dm.h"
#include "btif/include/btif_hd.h"
#include "btif/include/btif_hearing_aid.h"
#include "btif/include/btif_hf.h"
#include "btif/include/btif_hf_client.h"
#include "btif/include/btif_hh.h"
#include "btif/include/btif_keystore.h"
#include "btif/include/btif_metrics_logging.h"
#include "btif/include/btif_pan.h"
#include "btif/include/btif_profile_storage.h"
#include "btif/include/btif_rc.h"
#include "btif/include/btif_sock.h"
#include "btif/include/btif_sock_logging.h"
#include "btif/include/btif_storage.h"
#include "btif/include/core_callbacks.h"
#include "btif/include/stack_manager_t.h"
#include "common/address_obfuscator.h"
#include "common/metrics.h"
#include "common/os_utils.h"
#include "device/include/device_iot_config.h"
#include "device/include/esco_parameters.h"
#include "device/include/interop.h"
#include "device/include/interop_config.h"
#include "hardware/avrcp/avrcp.h"
#include "hardware/bt_csis.h"
#include "hardware/bt_gatt.h"
#include "hardware/bt_has.h"
#include "hardware/bt_hearing_aid.h"
#include "hardware/bt_le_audio.h"
#include "hardware/bt_rc.h"
#include "hardware/bt_sdp.h"
#include "hardware/bt_sock.h"
#include "hardware/bt_vc.h"
#include "internal_include/bt_target.h"
#include "main/shim/dumpsys.h"
#include "os/parameter_provider.h"
#include "osi/include/alarm.h"
#include "osi/include/allocator.h"
#include "osi/include/properties.h"
#include "osi/include/stack_power_telemetry.h"
#include "osi/include/wakelock.h"
#include "stack/btm/btm_dev.h"
#include "stack/btm/btm_sco_hfp_hal.h"
#include "stack/connection_manager/connection_manager.h"
#include "stack/include/a2dp_api.h"
#include "stack/include/avct_api.h"
#include "stack/include/avdt_api.h"
#include "stack/include/avrc_api.h"
#include "stack/include/bnep_api.h"
#include "stack/include/bt_name.h"
#include "stack/include/bt_octets.h"
#include "stack/include/btm_client_interface.h"
#include "stack/include/btm_status.h"
#include "stack/include/gatt_api.h"
#include "stack/include/hcidefs.h"
#include "stack/include/hfp_lc3_decoder.h"
#include "stack/include/hfp_lc3_encoder.h"
#include "stack/include/hfp_msbc_decoder.h"
#include "stack/include/hfp_msbc_encoder.h"
#include "stack/include/hidh_api.h"
#include "stack/include/l2cap_module.h"
#include "stack/include/main_thread.h"
#include "stack/include/pan_api.h"
#include "stack/include/sdp_api.h"
#include "storage/config_keys.h"
#include "types/ble_address_with_type.h"
#include "types/bt_transport.h"
#include "types/raw_address.h"

// TODO(b/369381361) Enfore -Wmissing-prototypes
#pragma GCC diagnostic ignored "-Wmissing-prototypes"

using bluetooth::csis::CsisClientInterface;
using bluetooth::has::HasClientInterface;
using bluetooth::le_audio::LeAudioBroadcasterInterface;
using bluetooth::le_audio::LeAudioClientInterface;
using bluetooth::vc::VolumeControlInterface;
using namespace bluetooth;

namespace {
tBT_TRANSPORT to_bt_transport(int val) {
  switch (val) {
    case 0:
      return BT_TRANSPORT_AUTO;
    case 1:
      return BT_TRANSPORT_BR_EDR;
    case 2:
      return BT_TRANSPORT_LE;
    default:
      break;
  }
  log::warn("Passed unexpected transport value:{}", val);
  return BT_TRANSPORT_AUTO;
}

}  // namespace

/*******************************************************************************
 *  Static variables
 ******************************************************************************/

static bt_callbacks_t* bt_hal_cbacks = NULL;
bool restricted_mode = false;
bool common_criteria_mode = false;
const int CONFIG_COMPARE_ALL_PASS = 0b11;
int common_criteria_config_compare_result = CONFIG_COMPARE_ALL_PASS;
bool is_local_device_atv = false;

/*******************************************************************************
 *  Externs
 ******************************************************************************/

/* list all extended interfaces here */

/*rfc l2cap*/
extern const btsock_interface_t* btif_sock_get_interface();
/* gatt */
extern const btgatt_interface_t* btif_gatt_get_interface();
/* avrc target */
extern const btrc_interface_t* btif_rc_get_interface();
/* avrc controller */
extern const btrc_ctrl_interface_t* btif_rc_ctrl_get_interface();
/*SDP search client*/
extern const btsdp_interface_t* btif_sdp_get_interface();
/* Hearing Access client */
extern HasClientInterface* btif_has_client_get_interface();
/* LeAudio testi client */
extern LeAudioClientInterface* btif_le_audio_get_interface();
/* LeAudio Broadcaster */
extern LeAudioBroadcasterInterface* btif_le_audio_broadcaster_get_interface();
/* Coordinated Set Service Client */
extern CsisClientInterface* btif_csis_client_get_interface();
/* Volume Control client */
extern VolumeControlInterface* btif_volume_control_get_interface();

bt_status_t btif_av_sink_execute_service(bool b_enable);

extern void bta_gatt_client_dump(int fd);

/*******************************************************************************
 *  Callbacks from bluetooth::core (see go/invisalign-bt)
 ******************************************************************************/

struct ConfigInterfaceImpl : bluetooth::core::ConfigInterface {
  ConfigInterfaceImpl() : bluetooth::core::ConfigInterface() {}

  bool isRestrictedMode() override { return is_restricted_mode(); }

  bool isA2DPOffloadEnabled() override {
    char value_sup[PROPERTY_VALUE_MAX] = {'\0'};
    char value_dis[PROPERTY_VALUE_MAX] = {'\0'};

    osi_property_get("ro.bluetooth.a2dp_offload.supported", value_sup, "false");
    osi_property_get("persist.bluetooth.a2dp_offload.disabled", value_dis, "false");
    auto a2dp_offload_enabled =
            (strcmp(value_sup, "true") == 0) && (strcmp(value_dis, "false") == 0);
    log::verbose("a2dp_offload.enable = {}", a2dp_offload_enabled);

    return a2dp_offload_enabled;
  }

  bool isAndroidTVDevice() override { return is_atv_device(); }
};

// TODO(aryarahul): remove unnecessary indirection through hfp_msbc_*.cc
struct MSBCCodec : bluetooth::core::CodecInterface {
  MSBCCodec() : bluetooth::core::CodecInterface() {}

  void initialize() override {
    hfp_msbc_decoder_init();
    hfp_msbc_encoder_init();
  }

  void cleanup() override {
    hfp_msbc_decoder_cleanup();
    hfp_msbc_encoder_cleanup();
  }

  uint32_t encodePacket(int16_t* input, uint8_t* output) {
    return hfp_msbc_encode_frames(input, output);
  }

  bool decodePacket(const uint8_t* i_buf, int16_t* o_buf, size_t out_len) {
    return hfp_msbc_decoder_decode_packet(i_buf, o_buf, out_len);
  }
};

struct LC3Codec : bluetooth::core::CodecInterface {
  LC3Codec() : bluetooth::core::CodecInterface() {}

  void initialize() override {
    hfp_lc3_decoder_init();
    hfp_lc3_encoder_init();
  }

  void cleanup() override {
    hfp_lc3_encoder_cleanup();
    hfp_lc3_decoder_cleanup();
  }

  uint32_t encodePacket(int16_t* input, uint8_t* output) {
    return hfp_lc3_encode_frames(input, output);
  }

  bool decodePacket(const uint8_t* i_buf, int16_t* o_buf, size_t out_len) {
    return hfp_lc3_decoder_decode_packet(i_buf, o_buf, out_len);
  }
};

struct CoreInterfaceImpl : bluetooth::core::CoreInterface {
  using bluetooth::core::CoreInterface::CoreInterface;

  void onBluetoothEnabled() override {
    /* init pan */
    btif_pan_init();
  }

  bt_status_t toggleProfile(tBTA_SERVICE_ID service_id, bool enable) override {
    /* Check the service_ID and invoke the profile's BT state changed API */
    switch (service_id) {
      case BTA_HFP_SERVICE_ID:
      case BTA_HSP_SERVICE_ID: {
        bluetooth::headset::ExecuteService(enable);
      } break;
      case BTA_A2DP_SOURCE_SERVICE_ID: {
        btif_av_source_execute_service(enable);
      } break;
      case BTA_A2DP_SINK_SERVICE_ID: {
        btif_av_sink_execute_service(enable);
      } break;
      case BTA_HID_SERVICE_ID: {
        btif_hh_execute_service(enable);
      } break;
      case BTA_HFP_HS_SERVICE_ID: {
        btif_hf_client_execute_service(enable);
      } break;
      case BTA_HIDD_SERVICE_ID: {
        btif_hd_execute_service(enable);
      } break;
      case BTA_PBAP_SERVICE_ID:
      case BTA_PCE_SERVICE_ID:
      case BTA_MAP_SERVICE_ID:
      case BTA_MN_SERVICE_ID: {
        /**
         * Do nothing; these services were started elsewhere. However, we need
         * to flow through this codepath in order to properly report back the
         * local UUIDs back to adapter properties in Java. To achieve this, we
         * need to catch these service IDs in order for {@link
         * btif_in_execute_service_request} to return {@code BT_STATUS_SUCCESS},
         * so that in {@link btif_dm_enable_service} the check passes and the
         * UUIDs are allowed to be passed up into the Java layer.
         */
      } break;
      default:
        log::error("Unknown service {} being {}", service_id, (enable) ? "enabled" : "disabled");
        return BT_STATUS_FAIL;
    }
    return BT_STATUS_SUCCESS;
  }

  void removeDeviceFromProfiles(const RawAddress& bd_addr) override {
/*special handling for HID devices */
#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE))
    tAclLinkSpec link_spec;
    link_spec.addrt.bda = bd_addr;
    link_spec.addrt.type = BLE_ADDR_PUBLIC;
    link_spec.transport = BT_TRANSPORT_AUTO;

    btif_hh_remove_device(link_spec);
#endif
#if (defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE))
    btif_hd_remove_device(bd_addr);
#endif
    btif_hearing_aid_get_interface()->RemoveDevice(bd_addr);

    if (bluetooth::csis::CsisClient::IsCsisClientRunning()) {
      btif_csis_client_get_interface()->RemoveDevice(bd_addr);
    }

    if (LeAudioClient::IsLeAudioClientRunning()) {
      btif_le_audio_get_interface()->RemoveDevice(bd_addr);
    }

    if (VolumeControl::IsVolumeControlRunning()) {
      btif_volume_control_get_interface()->RemoveDevice(bd_addr);
    }
  }

  void onLinkDown(const RawAddress& bd_addr, tBT_TRANSPORT transport) override {
    if (transport != BT_TRANSPORT_BR_EDR) {
      return;
    }

    btif_av_acl_disconnected(bd_addr, A2dpType::kSource);
    btif_av_acl_disconnected(bd_addr, A2dpType::kSink);
  }
};

static bluetooth::core::CoreInterface* CreateInterfaceToProfiles() {
  static bluetooth::core::EventCallbacks eventCallbacks{
          .invoke_adapter_state_changed_cb = invoke_adapter_state_changed_cb,
          .invoke_adapter_properties_cb = invoke_adapter_properties_cb,
          .invoke_remote_device_properties_cb = invoke_remote_device_properties_cb,
          .invoke_device_found_cb = invoke_device_found_cb,
          .invoke_discovery_state_changed_cb = invoke_discovery_state_changed_cb,
          .invoke_pin_request_cb = invoke_pin_request_cb,
          .invoke_ssp_request_cb = invoke_ssp_request_cb,
          .invoke_oob_data_request_cb = invoke_oob_data_request_cb,
          .invoke_bond_state_changed_cb = invoke_bond_state_changed_cb,
          .invoke_address_consolidate_cb = invoke_address_consolidate_cb,
          .invoke_le_address_associate_cb = invoke_le_address_associate_cb,
          .invoke_acl_state_changed_cb = invoke_acl_state_changed_cb,
          .invoke_thread_evt_cb = invoke_thread_evt_cb,
          .invoke_le_test_mode_cb = invoke_le_test_mode_cb,
          .invoke_energy_info_cb = invoke_energy_info_cb,
          .invoke_link_quality_report_cb = invoke_link_quality_report_cb,
          .invoke_key_missing_cb = invoke_key_missing_cb,
          .invoke_encryption_change_cb = invoke_encryption_change_cb,
  };
  static bluetooth::core::HACK_ProfileInterface profileInterface{
          // HID
          .btif_hh_virtual_unplug = btif_hh_virtual_unplug,
          .bta_hh_read_ssr_param = bta_hh_read_ssr_param,

          // AVDTP
          .btif_av_set_dynamic_audio_buffer_size = btif_av_set_dynamic_audio_buffer_size,

          // ASHA
          .GetHearingAidDeviceCount = HearingAid::GetDeviceCount,

          // LE Audio
          .IsLeAudioClientRunning = LeAudioClient::IsLeAudioClientRunning,

          // AVRCP
          .AVRC_GetProfileVersion = AVRC_GetProfileVersion,
  };

  static auto configInterface = ConfigInterfaceImpl();
  static auto msbcCodecInterface = MSBCCodec();
  static auto lc3CodecInterface = LC3Codec();

  static auto interfaceForCore =
          CoreInterfaceImpl(&eventCallbacks, &configInterface, &msbcCodecInterface,
                            &lc3CodecInterface, &profileInterface);
  return &interfaceForCore;
}

/*******************************************************************************
 *  Functions
 ******************************************************************************/

static bool interface_ready(void) { return bt_hal_cbacks != NULL; }
static void set_hal_cbacks(bt_callbacks_t* callbacks) { bt_hal_cbacks = callbacks; }

static bool is_profile(const char* p1, const char* p2) {
  log::assert_that(p1 != nullptr, "assert failed: p1 != nullptr");
  log::assert_that(p2 != nullptr, "assert failed: p2 != nullptr");
  return strlen(p1) == strlen(p2) && strncmp(p1, p2, strlen(p2)) == 0;
}

/*****************************************************************************
 *
 *   BLUETOOTH HAL INTERFACE FUNCTIONS
 *
 ****************************************************************************/

#ifdef TARGET_FLOSS
static int global_hci_adapter = 0;

static void set_adapter_index(int adapter) { global_hci_adapter = adapter; }
int GetAdapterIndex() { return global_hci_adapter; }
#else
int GetAdapterIndex() { return 0; }  // Unsupported outside of FLOSS
#endif

static int init(bt_callbacks_t* callbacks, bool start_restricted, bool is_common_criteria_mode,
                int config_compare_result, bool is_atv) {
  log::info(
          "start restricted = {} ; common criteria mode = {}, config compare "
          "result = {}",
          start_restricted, is_common_criteria_mode, config_compare_result);

  if (interface_ready()) {
    return BT_STATUS_DONE;
  }

  set_hal_cbacks(callbacks);

  restricted_mode = start_restricted;

  bluetooth::os::ParameterProvider::SetBtKeystoreInterface(
          bluetooth::bluetooth_keystore::getBluetoothKeystoreInterface());
  bluetooth::os::ParameterProvider::SetCommonCriteriaMode(is_common_criteria_mode);
  if (is_bluetooth_uid() && is_common_criteria_mode) {
    bluetooth::os::ParameterProvider::SetCommonCriteriaConfigCompareResult(config_compare_result);
  } else {
    bluetooth::os::ParameterProvider::SetCommonCriteriaConfigCompareResult(CONFIG_COMPARE_ALL_PASS);
  }

  is_local_device_atv = is_atv;

  stack_manager_get_interface()->init_stack(CreateInterfaceToProfiles());
  return BT_STATUS_SUCCESS;
}

static void start_profiles() {
#if (BNEP_INCLUDED == TRUE)
  BNEP_Init();
#if (PAN_INCLUDED == TRUE)
  PAN_Init();
#endif /* PAN */
#endif /* BNEP Included */
  A2DP_Init();
  AVRC_Init();
#if (HID_HOST_INCLUDED == TRUE)
  HID_HostInit();
#endif
  bta_ar_init();
}

static void stop_profiles() {
  btif_sock_cleanup();
  btif_pan_cleanup();
}

static int enable() {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  stack_manager_get_interface()->start_up_stack_async(CreateInterfaceToProfiles(), &start_profiles,
                                                      &stop_profiles);
  return BT_STATUS_SUCCESS;
}

static int disable(void) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  stack_manager_get_interface()->shut_down_stack_async(&stop_profiles);
  return BT_STATUS_SUCCESS;
}

static void cleanup(void) { stack_manager_get_interface()->clean_up_stack(&stop_profiles); }

static void start_rust_module(void) {
  std::promise<void> rust_up_promise;
  auto rust_up_future = rust_up_promise.get_future();
  stack_manager_get_interface()->start_up_rust_module_async(std::move(rust_up_promise));
  auto status = rust_up_future.wait_for(std::chrono::milliseconds(1000));
  if (status != std::future_status::ready) {
    log::error("Failed to wait for rust initialization in time. May lead to unpredictable crash");
  }
}

static void stop_rust_module(void) { stack_manager_get_interface()->shut_down_rust_module_async(); }

bool is_restricted_mode() { return restricted_mode; }

static bool get_wbs_supported() { return hfp_hal_interface::get_wbs_supported(); }

static bool get_swb_supported() { return hfp_hal_interface::get_swb_supported(); }

static bool is_coding_format_supported(esco_coding_format_t coding_format) {
  return hfp_hal_interface::is_coding_format_supported(coding_format);
}

bool is_common_criteria_mode() { return is_bluetooth_uid() && common_criteria_mode; }
// if common criteria mode disable, will always return
// CONFIG_COMPARE_ALL_PASS(0b11) indicate don't check config checksum.
int get_common_criteria_config_compare_result() {
  return is_common_criteria_mode() ? common_criteria_config_compare_result
                                   : CONFIG_COMPARE_ALL_PASS;
}

bool is_atv_device() { return is_local_device_atv; }

static int get_adapter_properties(void) {
  if (!btif_is_enabled()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_get_adapter_properties));
  return BT_STATUS_SUCCESS;
}

static int get_adapter_property(bt_property_type_t type) {
  /* Allow get_adapter_property only for BDADDR and BDNAME if BT is disabled */
  if (!btif_is_enabled() && (type != BT_PROPERTY_BDADDR) && (type != BT_PROPERTY_BDNAME)) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_get_adapter_property, type));
  return BT_STATUS_SUCCESS;
}

static void set_scan_mode(bt_scan_mode_t mode) {
  do_in_main_thread(base::BindOnce(btif_set_scan_mode, mode));
}

static int set_adapter_property(const bt_property_t* property) {
  if (!btif_is_enabled()) {
    return BT_STATUS_NOT_READY;
  }

  switch (property->type) {
    case BT_PROPERTY_BDNAME:
    case BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT:
    case BT_PROPERTY_CLASS_OF_DEVICE:
      break;
    default:
      return BT_STATUS_UNHANDLED;
  }

  do_in_main_thread(base::BindOnce(
          [](bt_property_t* property) {
            btif_set_adapter_property(property);
            osi_free(property);
          },
          property_deep_copy(property)));
  return BT_STATUS_SUCCESS;
}

int get_remote_device_properties(RawAddress* remote_addr) {
  if (!btif_is_enabled()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_get_remote_device_properties, *remote_addr));
  return BT_STATUS_SUCCESS;
}

int get_remote_device_property(RawAddress* remote_addr, bt_property_type_t type) {
  if (!btif_is_enabled()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_get_remote_device_property, *remote_addr, type));
  return BT_STATUS_SUCCESS;
}

int set_remote_device_property(RawAddress* remote_addr, const bt_property_t* property) {
  if (!btif_is_enabled()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(
          [](RawAddress remote_addr, bt_property_t* property) {
            btif_set_remote_device_property(&remote_addr, property);
            osi_free(property);
          },
          *remote_addr, property_deep_copy(property)));
  return BT_STATUS_SUCCESS;
}

int get_remote_services(RawAddress* remote_addr, int transport) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(
          base::BindOnce(btif_dm_get_remote_services, *remote_addr, to_bt_transport(transport)));
  return BT_STATUS_SUCCESS;
}

static int start_discovery(void) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_start_discovery));
  return BT_STATUS_SUCCESS;
}

static int cancel_discovery(void) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_cancel_discovery));
  return BT_STATUS_SUCCESS;
}

static int create_bond(const RawAddress* bd_addr, int transport) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  if (btif_dm_pairing_is_busy()) {
    return BT_STATUS_BUSY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_create_bond, *bd_addr, to_bt_transport(transport)));
  return BT_STATUS_SUCCESS;
}

static int create_bond_le(const RawAddress* bd_addr, uint8_t addr_type) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  if (btif_dm_pairing_is_busy()) {
    return BT_STATUS_BUSY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_create_bond_le, *bd_addr, addr_type));
  return BT_STATUS_SUCCESS;
}

static int create_bond_out_of_band(const RawAddress* bd_addr, int transport,
                                   const bt_oob_data_t* p192_data, const bt_oob_data_t* p256_data) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  if (btif_dm_pairing_is_busy()) {
    return BT_STATUS_BUSY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_create_bond_out_of_band, *bd_addr,
                                   to_bt_transport(transport), *p192_data, *p256_data));
  return BT_STATUS_SUCCESS;
}

static int generate_local_oob_data(tBT_TRANSPORT transport) {
  log::info("");
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  return do_in_main_thread(base::BindOnce(btif_dm_generate_local_oob_data, transport));
}

static int cancel_bond(const RawAddress* bd_addr) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_cancel_bond, *bd_addr));
  return BT_STATUS_SUCCESS;
}

static int remove_bond(const RawAddress* bd_addr) {
  if (is_restricted_mode() && !btif_storage_is_restricted_device(bd_addr)) {
    log::info("{} cannot be removed in restricted mode", *bd_addr);
    return BT_STATUS_SUCCESS;
  }

  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_remove_bond, *bd_addr));
  return BT_STATUS_SUCCESS;
}

static bool pairing_is_busy() {
  if (btif_dm_pairing_is_busy()) {
    return true;
  }

  return false;
}

static int get_connection_state(const RawAddress* bd_addr) {
  if (!interface_ready()) {
    return 0;
  }

  if (bd_addr == nullptr) {
    return 0;
  }

  return btif_dm_get_connection_state(*bd_addr);
}

static int pin_reply(const RawAddress* bd_addr, uint8_t accept, uint8_t pin_len,
                     bt_pin_code_t* pin_code) {
  bt_pin_code_t tmp_pin_code;
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  if (pin_code == nullptr || pin_len > PIN_CODE_LEN) {
    return BT_STATUS_PARM_INVALID;
  }

  memcpy(&tmp_pin_code, pin_code, pin_len);

  do_in_main_thread(base::BindOnce(btif_dm_pin_reply, *bd_addr, accept, pin_len, tmp_pin_code));
  return BT_STATUS_SUCCESS;
}

static int ssp_reply(const RawAddress* bd_addr, bt_ssp_variant_t variant, uint8_t accept,
                     uint32_t /* passkey */) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  if (variant == BT_SSP_VARIANT_PASSKEY_ENTRY) {
    return BT_STATUS_PARM_INVALID;
  }

  do_in_main_thread(base::BindOnce(btif_dm_ssp_reply, *bd_addr, variant, accept));
  return BT_STATUS_SUCCESS;
}

static int read_energy_info() {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_read_energy_info));
  return BT_STATUS_SUCCESS;
}

static int clear_event_filter() {
  log::verbose("");
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_clear_event_filter));
  return BT_STATUS_SUCCESS;
}

static int clear_event_mask() {
  log::verbose("");
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_clear_event_mask));
  return BT_STATUS_SUCCESS;
}

static int clear_filter_accept_list() {
  log::verbose("");
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_clear_filter_accept_list));
  return BT_STATUS_SUCCESS;
}

static int disconnect_all_acls() {
  log::verbose("");
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_disconnect_all_acls));
  return BT_STATUS_SUCCESS;
}

static void le_rand_btif_cb(uint64_t random_number) {
  log::verbose("");
  do_in_jni_thread(base::BindOnce(
          [](uint64_t random) { HAL_CBACK(bt_hal_cbacks, le_rand_cb, random); }, random_number));
}

static int le_rand() {
  log::verbose("");
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dm_le_rand, get_main_thread()->BindOnce(&le_rand_btif_cb)));
  return BT_STATUS_SUCCESS;
}

static int set_event_filter_inquiry_result_all_devices() {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  do_in_main_thread(base::BindOnce(btif_dm_set_event_filter_inquiry_result_all_devices));
  return BT_STATUS_SUCCESS;
}

static int set_default_event_mask_except(uint64_t mask, uint64_t le_mask) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  do_in_main_thread(base::BindOnce(btif_dm_set_default_event_mask_except, mask, le_mask));
  return BT_STATUS_SUCCESS;
}

static int restore_filter_accept_list() {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  // TODO(b/260922031) - When restoring the filter accept list after a system
  // suspend, we need to re-arm the LE connections that had `is_direct=False`.
  // This should be the list of bonded devices and potentially any GATT
  // connections that have `is_direct=False`. Currently, we only restore LE hid
  // devices.
  auto le_hid_addrs = btif_storage_get_le_hid_devices();
  do_in_main_thread(base::BindOnce(btif_dm_restore_filter_accept_list, std::move(le_hid_addrs)));
  return BT_STATUS_SUCCESS;
}

static int allow_wake_by_hid() {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  auto le_hid_addrs = btif_storage_get_le_hid_devices();
  auto classic_hid_addrs = btif_storage_get_wake_capable_classic_hid_devices();
  do_in_main_thread(base::BindOnce(btif_dm_allow_wake_by_hid, std::move(classic_hid_addrs),
                                   std::move(le_hid_addrs)));
  return BT_STATUS_SUCCESS;
}

static int set_event_filter_connection_setup_all_devices() {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  do_in_main_thread(base::BindOnce(btif_dm_set_event_filter_connection_setup_all_devices));
  return BT_STATUS_SUCCESS;
}

static void dump(int fd, const char** arguments) {
  log::debug("Started bluetooth dumpsys");
  btif_debug_conn_dump(fd);
  btif_debug_bond_event_dump(fd);
  btif_debug_linkkey_type_dump(fd);
  btif_debug_rc_dump(fd);
  btif_debug_a2dp_dump(fd);
  btif_debug_av_dump(fd);
  bta_debug_av_dump(fd);
  stack_debug_avdtp_api_dump(fd);
  btif_sock_dump(fd);
  bluetooth::avrcp::AvrcpService::DebugDump(fd);
  gatt_tcb_dump(fd);
  bta_gatt_client_dump(fd);
  device_debug_iot_config_dump(fd);
  BTA_HfClientDumpStatistics(fd);
  wakelock_debug_dump(fd);
  alarm_debug_dump(fd);
  bluetooth::csis::CsisClient::DebugDump(fd);
  ::bluetooth::le_audio::has::HasClient::DebugDump(fd);
  HearingAid::DebugDump(fd);
  LeAudioClient::DebugDump(fd);
  LeAudioBroadcaster::DebugDump(fd);
  VolumeControl::DebugDump(fd);
  connection_manager::dump(fd);
  bluetooth::bqr::DebugDump(fd);
  AVCT_Dumpsys(fd);
  PAN_Dumpsys(fd);
  DumpsysHid(fd);
  DumpsysBtaDm(fd);
  SDP_Dumpsys(fd);
  DumpsysRecord(fd);
  L2CA_Dumpsys(fd);
  DumpsysBtm(fd);
  bluetooth::shim::Dump(fd, arguments);
  power_telemetry::GetInstance().Dumpsys(fd);
  log::debug("Finished bluetooth dumpsys");
}

static void dumpMetrics(std::string* output) {
  bluetooth::common::BluetoothMetricsLogger::GetInstance()->WriteString(output);
}

static int get_remote_pbap_pce_version(const RawAddress* bd_addr) {
  // Read and restore the PCE version from local storage
  uint16_t pce_version = 0;
  size_t version_value_size = sizeof(pce_version);
  if (!btif_config_get_bin(bd_addr->ToString(), BTIF_STORAGE_KEY_PBAP_PCE_VERSION,
                           (uint8_t*)&pce_version, &version_value_size)) {
    log::warn("Failed to read cached peer PCE version for {}", *bd_addr);
  }
  return pce_version;
}

static bool pbap_pse_dynamic_version_upgrade_is_enabled() {
  log::info("PBAP PSE dynamic version upgrade is not enabled");
  return false;
}

static const void* get_profile_interface(const char* profile_id) {
  log::info("id = {}", profile_id);

  /* sanity check */
  if (!interface_ready()) {
    return NULL;
  }

  /* check for supported profile interfaces */
  if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID)) {
    return bluetooth::headset::GetInterface();
  }

  if (is_profile(profile_id, BT_PROFILE_HANDSFREE_CLIENT_ID)) {
    return btif_hf_client_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_SOCKETS_ID)) {
    return btif_sock_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_PAN_ID)) {
    return btif_pan_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID)) {
    return btif_hh_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_HIDDEV_ID)) {
    return btif_hd_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_SDP_CLIENT_ID)) {
    return btif_sdp_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_GATT_ID)) {
    return btif_gatt_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_AV_RC_ID)) {
    return btif_rc_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_AV_RC_CTRL_ID)) {
    return btif_rc_ctrl_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_HEARING_AID_ID)) {
    return btif_hearing_aid_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_HAP_CLIENT_ID)) {
    return btif_has_client_get_interface();
  }

  if (is_profile(profile_id, BT_KEYSTORE_ID)) {
    return bluetooth::bluetooth_keystore::getBluetoothKeystoreInterface();
  }

  if (is_profile(profile_id, BT_PROFILE_LE_AUDIO_ID)) {
    return btif_le_audio_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_LE_AUDIO_BROADCASTER_ID)) {
    return btif_le_audio_broadcaster_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_VC_ID)) {
    return btif_volume_control_get_interface();
  }

  if (is_profile(profile_id, BT_PROFILE_CSIS_CLIENT_ID)) {
    return btif_csis_client_get_interface();
  }

  if (is_profile(profile_id, BT_BQR_ID)) {
    return bluetooth::bqr::getBluetoothQualityReportInterface();
  }

  return NULL;
}

int dut_mode_configure(uint8_t enable) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  if (!stack_manager_get_interface()->get_stack_is_running()) {
    return BT_STATUS_NOT_READY;
  }

  do_in_main_thread(base::BindOnce(btif_dut_mode_configure, enable));
  return BT_STATUS_SUCCESS;
}

int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }
  if (!btif_is_dut_mode()) {
    return BT_STATUS_UNEXPECTED_STATE;
  }

  uint8_t* copy = (uint8_t*)osi_calloc(len);
  memcpy(copy, buf, len);

  do_in_main_thread(base::BindOnce(
          [](uint16_t opcode, uint8_t* buf, uint8_t len) {
            btif_dut_mode_send(opcode, buf, len);
            osi_free(buf);
          },
          opcode, copy, len));
  return BT_STATUS_SUCCESS;
}

int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) {
  if (!interface_ready()) {
    return BT_STATUS_NOT_READY;
  }

  switch (opcode) {
    case HCI_BLE_TRANSMITTER_TEST:
      if (len != 3) {
        return BT_STATUS_PARM_INVALID;
      }
      do_in_main_thread(base::BindOnce(btif_ble_transmitter_test, buf[0], buf[1], buf[2]));
      break;
    case HCI_BLE_RECEIVER_TEST:
      if (len != 1) {
        return BT_STATUS_PARM_INVALID;
      }
      do_in_main_thread(base::BindOnce(btif_ble_receiver_test, buf[0]));
      break;
    case HCI_BLE_TEST_END:
      do_in_main_thread(base::BindOnce(btif_ble_test_end));
      break;
    default:
      return BT_STATUS_UNSUPPORTED;
  }
  return BT_STATUS_SUCCESS;
}

static bt_os_callouts_t* wakelock_os_callouts_saved = nullptr;

static int acquire_wake_lock_cb(const char* lock_name) {
  return do_in_jni_thread(base::BindOnce(
          base::IgnoreResult(wakelock_os_callouts_saved->acquire_wake_lock), lock_name));
}

static int release_wake_lock_cb(const char* lock_name) {
  return do_in_jni_thread(base::BindOnce(
          base::IgnoreResult(wakelock_os_callouts_saved->release_wake_lock), lock_name));
}

static bt_os_callouts_t wakelock_os_callouts_jni = {
        sizeof(wakelock_os_callouts_jni),
        acquire_wake_lock_cb,
        release_wake_lock_cb,
};

static int set_os_callouts(bt_os_callouts_t* callouts) {
  wakelock_os_callouts_saved = callouts;
  wakelock_set_os_callouts(&wakelock_os_callouts_jni);
  return BT_STATUS_SUCCESS;
}

static int config_clear(void) {
  log::info("");
  int ret = BT_STATUS_SUCCESS;
  if (!btif_config_clear()) {
    log::error("Failed to clear btif config");
    ret = BT_STATUS_FAIL;
  }

  if (!device_iot_config_clear()) {
    log::error("Failed to clear device iot config");
    ret = BT_STATUS_FAIL;
  }

  return ret;
}

static bluetooth::avrcp::ServiceInterface* get_avrcp_service(void) {
  return bluetooth::avrcp::AvrcpService::GetServiceInterface();
}

static std::string obfuscate_address(const RawAddress& address) {
  return bluetooth::common::AddressObfuscator::GetInstance()->Obfuscate(address);
}

static int get_metric_id(const RawAddress& address) {
  return allocate_metric_id_from_metric_id_allocator(address);
}

static int set_dynamic_audio_buffer_size(int codec, int size) {
  return btif_set_dynamic_audio_buffer_size(codec, size);
}

static bool allow_low_latency_audio(bool allowed, const RawAddress& /* address */) {
  btif_a2dp_source_allow_low_latency_audio(allowed);
  return true;
}

static void metadata_changed(const RawAddress& remote_bd_addr, int key,
                             std::vector<uint8_t> value) {
  if (!interface_ready()) {
    log::error("Interface not ready!");
    return;
  }

  do_in_main_thread(
          base::BindOnce(btif_dm_metadata_changed, remote_bd_addr, key, std::move(value)));
}

static bool interop_match_addr(const char* feature_name, const RawAddress* addr) {
  if (feature_name == NULL || addr == NULL) {
    return false;
  }

  int feature = interop_feature_name_to_feature_id(feature_name);
  if (feature == -1) {
    log::error("feature doesn't exist: {}", feature_name);
    return false;
  }

  return interop_match_addr((interop_feature_t)feature, addr);
}

static bool interop_match_name(const char* feature_name, const char* name) {
  if (feature_name == NULL || name == NULL) {
    return false;
  }

  int feature = interop_feature_name_to_feature_id(feature_name);
  if (feature == -1) {
    log::error("feature doesn't exist: {}", feature_name);
    return false;
  }

  return interop_match_name((interop_feature_t)feature, name);
}

static bool interop_match_addr_or_name(const char* feature_name, const RawAddress* addr) {
  if (feature_name == NULL || addr == NULL) {
    return false;
  }

  int feature = interop_feature_name_to_feature_id(feature_name);
  if (feature == -1) {
    log::error("feature doesn't exist: {}", feature_name);
    return false;
  }

  return interop_match_addr_or_name((interop_feature_t)feature, addr,
                                    &btif_storage_get_remote_device_property);
}

static void interop_database_add_remove_addr(bool do_add, const char* feature_name,
                                             const RawAddress* addr, int length) {
  if (feature_name == NULL || addr == NULL) {
    return;
  }

  int feature = interop_feature_name_to_feature_id(feature_name);
  if (feature == -1) {
    log::error("feature doesn't exist: {}", feature_name);
    return;
  }

  if (do_add) {
    interop_database_add_addr((interop_feature_t)feature, addr, (size_t)length);
  } else {
    interop_database_remove_addr((interop_feature_t)feature, addr);
  }
}

static void interop_database_add_remove_name(bool do_add, const char* feature_name,
                                             const char* name) {
  if (feature_name == NULL || name == NULL) {
    return;
  }

  int feature = interop_feature_name_to_feature_id(feature_name);
  if (feature == -1) {
    log::error("feature doesn't exist: {}", feature_name);
    return;
  }

  if (do_add) {
    interop_database_add_name((interop_feature_t)feature, name);
  } else {
    interop_database_remove_name((interop_feature_t)feature, name);
  }
}

EXPORT_SYMBOL bt_interface_t bluetoothInterface = {
        sizeof(bluetoothInterface),
#ifdef TARGET_FLOSS
        .set_adapter_index = set_adapter_index,
#endif
        .init = init,
        .enable = enable,
        .disable = disable,
        .cleanup = cleanup,
        .start_rust_module = start_rust_module,
        .stop_rust_module = stop_rust_module,
        .get_adapter_properties = get_adapter_properties,
        .get_adapter_property = get_adapter_property,
        .set_scan_mode = set_scan_mode,
        .set_adapter_property = set_adapter_property,
        .get_remote_device_properties = get_remote_device_properties,
        .get_remote_device_property = get_remote_device_property,
        .set_remote_device_property = set_remote_device_property,
        .get_remote_service_record = nullptr,
        .get_remote_services = get_remote_services,
        .start_discovery = start_discovery,
        .cancel_discovery = cancel_discovery,
        .create_bond = create_bond,
        .create_bond_le = create_bond_le,
        .create_bond_out_of_band = create_bond_out_of_band,
        .remove_bond = remove_bond,
        .cancel_bond = cancel_bond,
        .pairing_is_busy = pairing_is_busy,
        .get_connection_state = get_connection_state,
        .pin_reply = pin_reply,
        .ssp_reply = ssp_reply,
        .get_profile_interface = get_profile_interface,
        .dut_mode_configure = dut_mode_configure,
        .dut_mode_send = dut_mode_send,
        .le_test_mode = le_test_mode,
        .set_os_callouts = set_os_callouts,
        .read_energy_info = read_energy_info,
        .dump = dump,
        .dumpMetrics = dumpMetrics,
        .config_clear = config_clear,
        .interop_database_clear = interop_database_clear,
        .interop_database_add = interop_database_add,
        .get_avrcp_service = get_avrcp_service,
        .obfuscate_address = obfuscate_address,
        .get_metric_id = get_metric_id,
        .set_dynamic_audio_buffer_size = set_dynamic_audio_buffer_size,
        .generate_local_oob_data = generate_local_oob_data,
        .allow_low_latency_audio = allow_low_latency_audio,
        .clear_event_filter = clear_event_filter,
        .clear_event_mask = clear_event_mask,
        .clear_filter_accept_list = clear_filter_accept_list,
        .disconnect_all_acls = disconnect_all_acls,
        .le_rand = le_rand,
        .set_event_filter_inquiry_result_all_devices = set_event_filter_inquiry_result_all_devices,
        .set_default_event_mask_except = set_default_event_mask_except,
        .restore_filter_accept_list = restore_filter_accept_list,
        .allow_wake_by_hid = allow_wake_by_hid,
        .set_event_filter_connection_setup_all_devices =
                set_event_filter_connection_setup_all_devices,
        .get_wbs_supported = get_wbs_supported,
        .get_swb_supported = get_swb_supported,
        .is_coding_format_supported = is_coding_format_supported,
        .metadata_changed = metadata_changed,
        .interop_match_addr = interop_match_addr,
        .interop_match_name = interop_match_name,
        .interop_match_addr_or_name = interop_match_addr_or_name,
        .interop_database_add_remove_addr = interop_database_add_remove_addr,
        .interop_database_add_remove_name = interop_database_add_remove_name,
        .get_remote_pbap_pce_version = get_remote_pbap_pce_version,
        .pbap_pse_dynamic_version_upgrade_is_enabled = pbap_pse_dynamic_version_upgrade_is_enabled,
};

// callback reporting helpers

bt_property_t* property_deep_copy_array(int num_properties, bt_property_t* properties) {
  bt_property_t* copy = nullptr;
  if (num_properties > 0) {
    size_t content_len = 0;
    for (int i = 0; i < num_properties; i++) {
      auto len = properties[i].len;
      if (len > 0) {
        content_len += len;
      }
    }

    copy = (bt_property_t*)osi_calloc((sizeof(bt_property_t) * num_properties) + content_len);
    log::assert_that(copy != nullptr, "assert failed: copy != nullptr");
    uint8_t* content = (uint8_t*)(copy + num_properties);

    for (int i = 0; i < num_properties; i++) {
      auto len = properties[i].len;
      copy[i].type = properties[i].type;
      copy[i].len = len;
      if (len <= 0) {
        continue;
      }
      copy[i].val = content;
      memcpy(content, properties[i].val, len);
      content += len;
    }
  }
  return copy;
}

void invoke_adapter_state_changed_cb(bt_state_t state) {
  do_in_jni_thread(base::BindOnce(
          [](bt_state_t state) { HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, state); },
          state));
}

void invoke_adapter_properties_cb(bt_status_t status, int num_properties,
                                  bt_property_t* properties) {
  do_in_jni_thread(base::BindOnce(
          [](bt_status_t status, int num_properties, bt_property_t* properties) {
            HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, num_properties, properties);
            if (properties) {
              osi_free(properties);
            }
          },
          status, num_properties, property_deep_copy_array(num_properties, properties)));
}

void invoke_remote_device_properties_cb(bt_status_t status, RawAddress bd_addr, int num_properties,
                                        bt_property_t* properties) {
  do_in_jni_thread(base::BindOnce(
          [](bt_status_t status, RawAddress bd_addr, int num_properties,
             bt_property_t* properties) {
            HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, status, &bd_addr, num_properties,
                      properties);
            if (properties) {
              osi_free(properties);
            }
          },
          status, bd_addr, num_properties, property_deep_copy_array(num_properties, properties)));
}

void invoke_device_found_cb(int num_properties, bt_property_t* properties) {
  do_in_jni_thread(base::BindOnce(
          [](int num_properties, bt_property_t* properties) {
            HAL_CBACK(bt_hal_cbacks, device_found_cb, num_properties, properties);
            if (properties) {
              osi_free(properties);
            }
          },
          num_properties, property_deep_copy_array(num_properties, properties)));
}

void invoke_discovery_state_changed_cb(bt_discovery_state_t state) {
  do_in_jni_thread(base::BindOnce(
          [](bt_discovery_state_t state) {
            HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, state);
          },
          state));
}

void invoke_pin_request_cb(RawAddress bd_addr, bt_bdname_t bd_name, uint32_t cod,
                           bool min_16_digit) {
  do_in_jni_thread(base::BindOnce(
          [](RawAddress bd_addr, bt_bdname_t bd_name, uint32_t cod, bool min_16_digit) {
            HAL_CBACK(bt_hal_cbacks, pin_request_cb, &bd_addr, &bd_name, cod, min_16_digit);
          },
          bd_addr, bd_name, cod, min_16_digit));
}

void invoke_ssp_request_cb(RawAddress bd_addr, bt_ssp_variant_t pairing_variant,
                           uint32_t pass_key) {
  do_in_jni_thread(base::BindOnce(
          [](RawAddress bd_addr, bt_ssp_variant_t pairing_variant, uint32_t pass_key) {
            HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, pairing_variant, pass_key);
          },
          bd_addr, pairing_variant, pass_key));
}

void invoke_oob_data_request_cb(tBT_TRANSPORT t, bool valid, Octet16 c, Octet16 r,
                                RawAddress raw_address, uint8_t address_type) {
  log::info("");
  bt_oob_data_t oob_data = {};
  const char* local_name;
  if (get_btm_client_interface().local.BTM_ReadLocalDeviceName(&local_name) !=
      tBTM_STATUS::BTM_SUCCESS) {
    log::warn("Unable to read local device name");
  }
  for (int i = 0; i < BD_NAME_LEN; i++) {
    oob_data.device_name[i] = local_name[i];
  }

  // Set the local address
  int j = 5;
  for (int i = 0; i < 6; i++) {
    oob_data.address[i] = raw_address.address[j];
    j--;
  }
  oob_data.address[6] = address_type;

  // Each value (for C and R) is 16 octets in length
  bool c_empty = true;
  for (int i = 0; i < 16; i++) {
    // C cannot be all 0s, if so then we want to fail
    if (c[i] != 0) {
      c_empty = false;
    }
    oob_data.c[i] = c[i];
    // R is optional and may be empty
    oob_data.r[i] = r[i];
  }
  oob_data.is_valid = valid && !c_empty;
  // The oob_data_length is 2 octets in length.  The value includes the length
  // of itself. 16 + 16 + 2 = 34 Data 0x0022 Little Endian order 0x2200
  oob_data.oob_data_length[0] = 0;
  oob_data.oob_data_length[1] = 34;
  bt_status_t status = do_in_jni_thread(base::BindOnce(
          [](tBT_TRANSPORT t, bt_oob_data_t oob_data) {
            HAL_CBACK(bt_hal_cbacks, generate_local_oob_data_cb, t, oob_data);
          },
          t, oob_data));
  if (status != BT_STATUS_SUCCESS) {
    log::error("Failed to call callback!");
  }
}

void invoke_bond_state_changed_cb(bt_status_t status, RawAddress bd_addr, bt_bond_state_t state,
                                  int fail_reason) {
  do_in_jni_thread(base::BindOnce(
          [](bt_status_t status, RawAddress bd_addr, bt_bond_state_t state, int fail_reason) {
            HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &bd_addr, state, fail_reason);
          },
          status, bd_addr, state, fail_reason));
}

void invoke_address_consolidate_cb(RawAddress main_bd_addr, RawAddress secondary_bd_addr) {
  do_in_jni_thread(base::BindOnce(
          [](RawAddress main_bd_addr, RawAddress secondary_bd_addr) {
            HAL_CBACK(bt_hal_cbacks, address_consolidate_cb, &main_bd_addr, &secondary_bd_addr);
          },
          main_bd_addr, secondary_bd_addr));
}

void invoke_le_address_associate_cb(RawAddress main_bd_addr, RawAddress secondary_bd_addr,
                                    uint8_t identity_address_type) {
  do_in_jni_thread(base::BindOnce(
          [](RawAddress main_bd_addr, RawAddress secondary_bd_addr, uint8_t identity_address_type) {
            HAL_CBACK(bt_hal_cbacks, le_address_associate_cb, &main_bd_addr, &secondary_bd_addr,
                      identity_address_type);
          },
          main_bd_addr, secondary_bd_addr, identity_address_type));
}

void invoke_acl_state_changed_cb(bt_status_t status, RawAddress bd_addr, bt_acl_state_t state,
                                 int transport_link_type, bt_hci_error_code_t hci_reason,
                                 bt_conn_direction_t direction, uint16_t acl_handle) {
  do_in_jni_thread(base::BindOnce(
          [](bt_status_t status, RawAddress bd_addr, bt_acl_state_t state, int transport_link_type,
             bt_hci_error_code_t hci_reason, bt_conn_direction_t direction, uint16_t acl_handle) {
            HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, status, &bd_addr, state,
                      transport_link_type, hci_reason, direction, acl_handle);
          },
          status, bd_addr, state, transport_link_type, hci_reason, direction, acl_handle));
}

void invoke_thread_evt_cb(bt_cb_thread_evt event) {
  do_in_jni_thread(base::BindOnce(
          [](bt_cb_thread_evt event) {
            HAL_CBACK(bt_hal_cbacks, thread_evt_cb, event);
            if (event == DISASSOCIATE_JVM) {
              bt_hal_cbacks = NULL;
            }
          },
          event));
}

void invoke_le_test_mode_cb(bt_status_t status, uint16_t count) {
  do_in_jni_thread(base::BindOnce(
          [](bt_status_t status, uint16_t count) {
            HAL_CBACK(bt_hal_cbacks, le_test_mode_cb, status, count);
          },
          status, count));
}

// takes ownership of |uid_data|
void invoke_energy_info_cb(bt_activity_energy_info energy_info, bt_uid_traffic_t* uid_data) {
  do_in_jni_thread(base::BindOnce(
          [](bt_activity_energy_info energy_info, bt_uid_traffic_t* uid_data) {
            HAL_CBACK(bt_hal_cbacks, energy_info_cb, &energy_info, uid_data);
            osi_free(uid_data);
          },
          energy_info, uid_data));
}

void invoke_link_quality_report_cb(uint64_t timestamp, int report_id, int rssi, int snr,
                                   int retransmission_count, int packets_not_receive_count,
                                   int negative_acknowledgement_count) {
  do_in_jni_thread(base::BindOnce(
          [](uint64_t timestamp, int report_id, int rssi, int snr, int retransmission_count,
             int packets_not_receive_count, int negative_acknowledgement_count) {
            HAL_CBACK(bt_hal_cbacks, link_quality_report_cb, timestamp, report_id, rssi, snr,
                      retransmission_count, packets_not_receive_count,
                      negative_acknowledgement_count);
          },
          timestamp, report_id, rssi, snr, retransmission_count, packets_not_receive_count,
          negative_acknowledgement_count));
}

void invoke_switch_buffer_size_cb(bool is_low_latency_buffer_size) {
  do_in_jni_thread(base::BindOnce(
          [](bool is_low_latency_buffer_size) {
            HAL_CBACK(bt_hal_cbacks, switch_buffer_size_cb, is_low_latency_buffer_size);
          },
          is_low_latency_buffer_size));
}

void invoke_switch_codec_cb(bool is_low_latency_buffer_size) {
  do_in_jni_thread(base::BindOnce(
          [](bool is_low_latency_buffer_size) {
            HAL_CBACK(bt_hal_cbacks, switch_codec_cb, is_low_latency_buffer_size);
          },
          is_low_latency_buffer_size));
}

void invoke_key_missing_cb(RawAddress bd_addr) {
  do_in_jni_thread(base::BindOnce(
          [](RawAddress bd_addr) { HAL_CBACK(bt_hal_cbacks, key_missing_cb, bd_addr); }, bd_addr));
}

void invoke_encryption_change_cb(bt_encryption_change_evt encryption_change) {
  do_in_jni_thread(base::BindOnce(
          [](bt_encryption_change_evt encryption_change) {
            HAL_CBACK(bt_hal_cbacks, encryption_change_cb, encryption_change);
          },
          encryption_change));
}

namespace bluetooth::testing {
void set_hal_cbacks(bt_callbacks_t* callbacks) { ::set_hal_cbacks(callbacks); }

}  // namespace bluetooth::testing
