910e62b5创建于 1月15日历史提交
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "device/bluetooth/floss/floss_dbus_client.h"

#include <string>

#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "dbus/message.h"
#include "device/bluetooth/floss/floss_adapter_client.h"
#include "device/bluetooth/floss/floss_lescan_client.h"

namespace floss {

// All Floss D-Bus methods return immediately, so the timeout can be very short.
int kDBusTimeoutMs = 2000;
// Timeout for waiting HCI enabled changed. Make it longer since it takes longer
// when there is a connected device.
int kAdapterEnabledTimeoutMs = 5000;

namespace {
constexpr char kDeviceIdNameKey[] = "name";
constexpr char kDeviceIdAddressKey[] = "address";
}  // namespace

Error::Error(const std::string& name, const std::string& message)
    : name(name), message(message) {}

std::ostream& operator<<(std::ostream& os, const Error& error) {
  os << error.name;

  if (error.name.size() == 0) {
    os << "<no error name>";
  }

  if (error.message.size()) {
    os << ": " << error.message;
  }

  return os;
}

std::string Error::ToString() {
  std::stringstream ss;
  ss << *this;
  return ss.str();
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const bool*) {
  static DBusTypeInfo info{"b", "bool"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const uint8_t*) {
  static DBusTypeInfo info{"y", "uint8_t"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const int8_t*) {
  static DBusTypeInfo info{"n", "int8"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const uint16_t*) {
  static DBusTypeInfo info{"q", "uint16"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const int16_t*) {
  static DBusTypeInfo info{"n", "int16"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const uint32_t*) {
  static DBusTypeInfo info{"u", "uint32"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const int32_t*) {
  static DBusTypeInfo info{"i", "int32"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const uint64_t*) {
  static DBusTypeInfo info{"t", "uint64"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const int64_t*) {
  static DBusTypeInfo info{"x", "int64"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const double*) {
  static DBusTypeInfo info{"d", "double"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const std::string*) {
  static DBusTypeInfo info{"s", "string"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const dbus::ObjectPath*) {
  static DBusTypeInfo info{"o", "object_path"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const base::ScopedFD*) {
  static DBusTypeInfo info{"h", "FD"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(const FlossDeviceId*) {
  static DBusTypeInfo info{"a{sv}", "FlossDeviceId"};
  return info;
}

template <>
const DBusTypeInfo& GetDBusTypeInfo(
    const FlossAdapterClient::VendorProductInfo*) {
  static DBusTypeInfo info{"a{sv}", "VendorProductInfo"};
  return info;
}

template <>
DEVICE_BLUETOOTH_EXPORT const DBusTypeInfo& GetDBusTypeInfo(
    const device::BluetoothUUID*) {
  static DBusTypeInfo info{"ay", "BluetoothUUID"};
  return info;
}

FlossDBusClient::FlossDBusClient() = default;
FlossDBusClient::~FlossDBusClient() = default;

const char FlossDBusClient::kErrorDBus[] = "org.chromium.Error.DBus";
const char FlossDBusClient::kErrorNoResponse[] =
    "org.chromium.Error.NoResponse";
const char FlossDBusClient::kErrorInvalidParameters[] =
    "org.chromium.Error.InvalidParameters";
const char FlossDBusClient::kErrorInvalidReturn[] =
    "org.chromium.Error.InvalidReturn";
const char FlossDBusClient::kErrorDoesNotExist[] =
    "org.chromium.Error.DoesNotExist";
const char FlossDBusClient::kOptionalValueKey[] = "optional_value";

// static
dbus::ObjectPath FlossDBusClient::GenerateAdapterPath(int adapter_index) {
  return dbus::ObjectPath(
      base::StringPrintf(kAdapterObjectFormat, adapter_index));
}

// static
dbus::ObjectPath FlossDBusClient::GenerateGattPath(int adapter_index) {
  return dbus::ObjectPath(base::StringPrintf(kGattObjectFormat, adapter_index));
}

// static
dbus::ObjectPath FlossDBusClient::GenerateBatteryManagerPath(
    int adapter_index) {
  return dbus::ObjectPath(
      base::StringPrintf(kBatteryManagerObjectFormat, adapter_index));
}

// static
dbus::ObjectPath FlossDBusClient::GenerateBluetoothTelephonyPath(
    int adapter_index) {
  return dbus::ObjectPath(
      base::StringPrintf(kBluetoothTelephonyObjectFormat, adapter_index));
}

dbus::ObjectPath FlossDBusClient::GenerateAdminPath(int adapter_index) {
  return dbus::ObjectPath(
      base::StringPrintf(kAdminObjectFormat, adapter_index));
}

dbus::ObjectPath FlossDBusClient::GenerateLoggingPath(int adapter_index) {
  return dbus::ObjectPath(
      base::StringPrintf(kAdapterLoggingObjectFormat, adapter_index));
}

device::BluetoothDevice::ConnectErrorCode
FlossDBusClient::BtifStatusToConnectErrorCode(
    FlossDBusClient::BtifStatus status) {
  switch (status) {
    case BtifStatus::kSuccess:
      NOTREACHED();
    case BtifStatus::kFail:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_FAILED;
    case BtifStatus::kNotReady:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_DEVICE_NOT_READY;
    case BtifStatus::kAuthFailure:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_FAILED;
    case BtifStatus::kAuthRejected:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_REJECTED;
    case BtifStatus::kDone:
    case BtifStatus::kBusy:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_INPROGRESS;
    case BtifStatus::kUnsupported:
      return device::BluetoothDevice::ConnectErrorCode::
          ERROR_UNSUPPORTED_DEVICE;
    case BtifStatus::kNomem:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_NO_MEMORY;
    case BtifStatus::kParmInvalid:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_INVALID_ARGS;
    case BtifStatus::kUnhandled:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_UNKNOWN;
    case BtifStatus::kRmtDevDown:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_DOES_NOT_EXIST;
    case BtifStatus::kJniEnvironmentError:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_JNI_ENVIRONMENT;
    case BtifStatus::kJniThreadAttachError:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_JNI_THREAD_ATTACH;
    case BtifStatus::kWakelockError:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_WAKELOCK;
    case BtifStatus::kTimeout:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_NON_AUTH_TIMEOUT;
    case BtifStatus::kDeviceNotFound:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_DOES_NOT_EXIST;
    case BtifStatus::kUnexpectedState:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_UNEXPECTED_STATE;
    case BtifStatus::kSocketError:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_SOCKET;
    default:
      return device::BluetoothDevice::ConnectErrorCode::ERROR_FAILED;
  }
}

// Default error handler for dbus clients is to just print the error right now.
// TODO(abps) - Deprecate this once error handling is implemented in the upper
//              layers.
void FlossDBusClient::LogErrorResponse(const std::string& message,
                                       dbus::ErrorResponse* error) {
  if (!error) {
    return;
  }

  dbus::MessageReader reader(error);
  auto error_name = error->GetErrorName();
  std::string error_message;
  reader.PopString(&error_message);

  LOG(ERROR) << message << ": " << error_name << ": " << error_message;
}

// static
Error FlossDBusClient::ErrorResponseToError(const std::string& default_name,
                                            const std::string& default_message,
                                            dbus::ErrorResponse* error) {
  Error result(default_name, default_message);

  if (error) {
    dbus::MessageReader reader(error);
    result.name = error->GetErrorName();
    reader.PopString(&result.message);
  }

  return result;
}

// static
// No-op read for a void value.
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader, Void* value) {
  return true;
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader, bool* value) {
  return reader->PopBool(value);
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    uint8_t* value) {
  return reader->PopByte(value);
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    int8_t* value) {
  int16_t val;
  bool success;

  success = reader->PopInt16(&val);
  *value = static_cast<int8_t>(val);

  return success;
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    uint16_t* value) {
  return reader->PopUint16(value);
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    uint32_t* value) {
  return reader->PopUint32(value);
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    uint64_t* value) {
  return reader->PopUint64(value);
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    int32_t* value) {
  return reader->PopInt32(value);
}

// static
template bool FlossDBusClient::ReadDBusParam<int32_t>(
    dbus::MessageReader* reader,
    std::optional<int32_t>* value);

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    std::string* value) {
  return reader->PopString(value);
}

// static
template bool FlossDBusClient::ReadDBusParam<std::string>(
    dbus::MessageReader* reader,
    std::optional<std::string>* value);

// static
template <>
bool FlossDBusClient::ReadDBusParam(
    dbus::MessageReader* reader,
    FlossAdapterClient::BluetoothDeviceType* value) {
  uint32_t val;
  bool success;

  success = reader->PopUint32(&val);
  *value = static_cast<FlossAdapterClient::BluetoothDeviceType>(val);

  return success;
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    device::BluetoothUUID* uuid) {
  base::span<const uint8_t> bytes;
  if (!reader->PopArrayOfBytes(&bytes)) {
    return false;
  }

  if (bytes.size() != 16U) {
    return false;
  }

  *uuid = device::BluetoothUUID(bytes);
  DCHECK(uuid->IsValid());
  return true;
}

// static
template bool FlossDBusClient::ReadDBusParam<device::BluetoothUUID>(
    dbus::MessageReader* reader,
    std::optional<device::BluetoothUUID>* uuid);

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    FlossDBusClient::BtifStatus* status) {
  uint32_t raw_type = 0;
  bool read = FlossDBusClient::ReadDBusParam(reader, &raw_type);

  if (read) {
    *status = static_cast<FlossDBusClient::BtifStatus>(raw_type);
  }

  return read;
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    base::ScopedFD* fd) {
  return reader->PopFileDescriptor(fd);
}

// static
template bool FlossDBusClient::ReadDBusParam<base::ScopedFD>(
    dbus::MessageReader* reader,
    std::optional<base::ScopedFD>* fd);

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    FlossDeviceId* device) {
  static StructReader<FlossDeviceId> struct_reader({
      {"address", CreateFieldReader(&FlossDeviceId::address)},
      {"name", CreateFieldReader(&FlossDeviceId::name)},
  });

  return struct_reader.ReadDBusParam(reader, device);
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(
    dbus::MessageReader* reader,
    FlossAdapterClient::VendorProductInfo* vpi) {
  static StructReader<FlossAdapterClient::VendorProductInfo> struct_reader({
      {"vendor_id_src",
       CreateFieldReader(&FlossAdapterClient::VendorProductInfo::vendorIdSrc)},
      {"vendor_id",
       CreateFieldReader(&FlossAdapterClient::VendorProductInfo::vendorId)},
      {"product_id",
       CreateFieldReader(&FlossAdapterClient::VendorProductInfo::productId)},
      {"version",
       CreateFieldReader(&FlossAdapterClient::VendorProductInfo::version)},
  });

  return struct_reader.ReadDBusParam(reader, vpi);
}

// static
template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    FlossAdapterClient::BtAddressType* type) {
  uint32_t val;
  bool success;

  success = reader->PopUint32(&val);
  *type = static_cast<FlossAdapterClient::BtAddressType>(val);

  return success;
}

template <>
bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                    FlossAdapterClient::BtAdapterRole* type) {
  uint32_t val;
  bool success;

  success = reader->PopUint32(&val);
  *type = static_cast<FlossAdapterClient::BtAdapterRole>(val);

  return success;
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const FlossDeviceId& device) {
  dbus::MessageWriter array(nullptr);
  dbus::MessageWriter dict(nullptr);

  writer->OpenArray("{sv}", &array);

  WriteDictEntry(&array, kDeviceIdNameKey, device.name);
  WriteDictEntry(&array, kDeviceIdAddressKey, device.address);

  writer->CloseContainer(&array);
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const uint64_t& data) {
  writer->AppendUint64(data);
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const uint32_t& data) {
  writer->AppendUint32(data);
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const uint8_t& data) {
  writer->AppendByte(data);
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const int8_t& data) {
  return writer->AppendInt16(static_cast<int16_t>(data));
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const uint16_t& data) {
  return writer->AppendUint16(data);
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const int16_t& data) {
  return writer->AppendInt16(data);
}

template void FlossDBusClient::WriteDBusParam<uint32_t>(
    dbus::MessageWriter* writer,
    const std::optional<uint32_t>& data);

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const int32_t& data) {
  writer->AppendInt32(data);
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const std::string& data) {
  writer->AppendString(data);
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const bool& data) {
  writer->AppendBool(data);
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const std::vector<uint8_t>& data) {
  writer->AppendArrayOfBytes(data);
}

template <>
DEVICE_BLUETOOTH_EXPORT void FlossDBusClient::WriteDBusParam(
    dbus::MessageWriter* writer,
    const device::BluetoothUUID& uuid) {
  WriteDBusParam(writer, uuid.GetBytes());
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const base::ScopedFD& fd) {
  writer->AppendFileDescriptor(fd.get());
}

template <>
void FlossDBusClient::WriteDBusParam(dbus::MessageWriter* writer,
                                     const dbus::ObjectPath& path) {
  writer->AppendObjectPath(path);
}

template <>
void FlossDBusClient::WriteDBusParam(
    dbus::MessageWriter* writer,
    const FlossDBusClient::BtifStatus& status) {
  uint32_t raw_type = static_cast<uint32_t>(status);
  WriteDBusParam(writer, raw_type);
}

template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<bool> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<uint8_t> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<uint32_t> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<std::string> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<std::vector<FlossDeviceId>> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<FlossAdapterClient::BluetoothDeviceType> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<device::BluetoothDevice::UUIDList> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<FlossAdapterClient::VendorProductInfo> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<FlossAdapterClient::BtAddressType> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

template void FlossDBusClient::DefaultResponseWithCallback(
    ResponseCallback<FlossDBusClient::BtifStatus> callback,
    dbus::Response* response,
    dbus::ErrorResponse* error_response);

void FlossDBusClient::DefaultResponse(const std::string& caller,
                                      dbus::Response* response,
                                      dbus::ErrorResponse* error_response) {
  if (error_response) {
    FlossDBusClient::LogErrorResponse(caller, error_response);
  } else {
    DVLOG(1) << caller << "::OnResponse";
  }
}

}  // namespace floss