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/fake_floss_adapter_client.h"

#include <string>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/logging.h"
#include "base/observer_list.h"
#include "base/task/single_thread_task_runner.h"
#include "device/bluetooth/floss/floss_dbus_client.h"

namespace floss {

namespace {

const int kDelayedTaskMs = 100;

FlossDeviceId ConvertAddressToDevice(const std::string& address) {
  static const base::flat_map<std::string, FlossDeviceId> address_to_device{
      {FakeFlossAdapterClient::kClassicAddress,
       FlossDeviceId{FakeFlossAdapterClient::kClassicAddress,
                     FakeFlossAdapterClient::kClassicName}},
      {FakeFlossAdapterClient::kPinCodeDisplayAddress,
       FlossDeviceId{FakeFlossAdapterClient::kPinCodeDisplayAddress,
                     FakeFlossAdapterClient::kPinCodeDisplayName}},
      {FakeFlossAdapterClient::kPasskeyDisplayAddress,
       FlossDeviceId{FakeFlossAdapterClient::kPasskeyDisplayAddress,
                     FakeFlossAdapterClient::kPasskeyDisplayName}},
      {FakeFlossAdapterClient::kPinCodeRequestAddress,
       FlossDeviceId{FakeFlossAdapterClient::kPinCodeRequestAddress,
                     FakeFlossAdapterClient::kPinCodeRequestName}},
      {FakeFlossAdapterClient::kPhoneAddress,
       FlossDeviceId{FakeFlossAdapterClient::kPhoneAddress,
                     FakeFlossAdapterClient::kPhoneName}},
      {FakeFlossAdapterClient::kPasskeyRequestAddress,
       FlossDeviceId{FakeFlossAdapterClient::kPasskeyRequestAddress,
                     FakeFlossAdapterClient::kPasskeyRequestName}},
      {FakeFlossAdapterClient::kJustWorksAddress,
       FlossDeviceId{FakeFlossAdapterClient::kJustWorksAddress,
                     FakeFlossAdapterClient::kJustWorksName}}};

  auto iter = address_to_device.find(address);
  if (iter != address_to_device.end()) {
    return iter->second;
  }
  return FlossDeviceId{address, ""};
}

uint32_t ConvertAddressToClassOfDevice(const std::string& address) {
  static const base::flat_map<std::string, uint32_t> address_to_cod{
      {FakeFlossAdapterClient::kClassicAddress,
       FakeFlossAdapterClient::kClassicClassOfDevice},
      {FakeFlossAdapterClient::kPinCodeDisplayAddress,
       FakeFlossAdapterClient::kPinCodeDisplayClassOfDevice},
      {FakeFlossAdapterClient::kPasskeyDisplayAddress,
       FakeFlossAdapterClient::kPasskeyDisplayClassOfDevice},
      {FakeFlossAdapterClient::kPinCodeRequestAddress,
       FakeFlossAdapterClient::kPinCodeRequestClassOfDevice},
      {FakeFlossAdapterClient::kPhoneAddress,
       FakeFlossAdapterClient::kPhoneClassOfDevice},
      {FakeFlossAdapterClient::kPasskeyRequestAddress,
       FakeFlossAdapterClient::kPasskeyRequestClassOfDevice},
      {FakeFlossAdapterClient::kJustWorksAddress,
       FakeFlossAdapterClient::kJustWorksClassOfDevice}};

  auto iter = address_to_cod.find(address);
  if (iter != address_to_cod.end()) {
    return iter->second;
  }
  return FakeFlossAdapterClient::kDefaultClassOfDevice;
}

}  // namespace

FakeFlossAdapterClient::FakeFlossAdapterClient()
    : bonded_addresses_({kBondedAddress1, kBondedAddress2}),
      connected_addresses_({}) {}

FakeFlossAdapterClient::~FakeFlossAdapterClient() = default;

const char FakeFlossAdapterClient::kBondedAddress1[] = "11:11:11:11:11:01";
const char FakeFlossAdapterClient::kBondedAddress2[] = "11:11:11:11:11:02";
const char FakeFlossAdapterClient::kPairedAddressBrEdr[] = "11:11:11:11:11:03";
const char FakeFlossAdapterClient::kPairedAddressLE[] = "11:11:11:11:11:04";
const uint32_t FakeFlossAdapterClient::kDefaultClassOfDevice = 0x240418;

const char FakeFlossAdapterClient::kClassicName[] = "Bluetooth 2.0 Mouse";
const char FakeFlossAdapterClient::kClassicAddress[] = "11:35:11:35:00:01";
const uint32_t FakeFlossAdapterClient::kClassicClassOfDevice = 0x002580;
const char FakeFlossAdapterClient::kPinCodeDisplayName[] =
    "Bluetooth 2.0 Keyboard";
const char FakeFlossAdapterClient::kPinCodeDisplayAddress[] =
    "11:35:11:35:00:02";
const uint32_t FakeFlossAdapterClient::kPinCodeDisplayClassOfDevice = 0x002540;
const char FakeFlossAdapterClient::kPasskeyDisplayName[] =
    "Bluetooth 2.1+ Keyboard";
const char FakeFlossAdapterClient::kPasskeyDisplayAddress[] =
    "11:35:11:35:00:03";
const uint32_t FakeFlossAdapterClient::kPasskeyDisplayClassOfDevice = 0x002540;
const char FakeFlossAdapterClient::kPinCodeRequestName[] = "PIN Device";
const char FakeFlossAdapterClient::kPinCodeRequestAddress[] =
    "11:35:11:35:00:04";
const uint32_t FakeFlossAdapterClient::kPinCodeRequestClassOfDevice = 0x240408;
const char FakeFlossAdapterClient::kPhoneName[] = "Phone";
const char FakeFlossAdapterClient::kPhoneAddress[] = "11:35:11:35:00:05";
const uint32_t FakeFlossAdapterClient::kPhoneClassOfDevice = 0x7a020c;
const char FakeFlossAdapterClient::kPasskeyRequestName[] = "Passkey Device";
const char FakeFlossAdapterClient::kPasskeyRequestAddress[] =
    "11:35:11:35:00:06";
const uint32_t FakeFlossAdapterClient::kPasskeyRequestClassOfDevice = 0x7a020c;
const char FakeFlossAdapterClient::kJustWorksName[] = "Just-Works Device";
const char FakeFlossAdapterClient::kJustWorksAddress[] = "11:35:11:35:00:07";
const uint32_t FakeFlossAdapterClient::kJustWorksClassOfDevice = 0x240428;

const uint32_t FakeFlossAdapterClient::kPasskey = 123456;
const char FakeFlossAdapterClient::kPinCode[] = "012345";

void FakeFlossAdapterClient::Init(dbus::Bus* bus,
                                  const std::string& service_name,
                                  const int adapter_index,
                                  base::Version version,
                                  base::OnceClosure on_ready) {
  bus_ = bus;
  adapter_path_ = GenerateAdapterPath(adapter_index);
  service_name_ = service_name;
  version_ = version;
  std::move(on_ready).Run();
}

void FakeFlossAdapterClient::SetName(ResponseCallback<Void> callback,
                                     const std::string& name) {
  PostDelayedTask(base::BindOnce(std::move(callback), Void{}));
}

void FakeFlossAdapterClient::StartDiscovery(ResponseCallback<Void> callback) {
  // Fail fast if we're meant to fail discovery
  if (fail_discovery_) {
    fail_discovery_ = std::nullopt;

    std::move(callback).Run(base::unexpected(
        Error("org.chromium.bluetooth.Bluetooth.FooError", "Foo error")));
    return;
  }

  // Simulate devices being discovered.

  const auto discoverable_devices = std::vector{
      // Report empty name first to simulate this device sends its name later.
      FlossDeviceId{kClassicAddress, ""},
      FlossDeviceId{kClassicAddress, kClassicName},

      FlossDeviceId{kPinCodeDisplayAddress, kPinCodeDisplayName},
      FlossDeviceId{kPasskeyDisplayAddress, kPasskeyDisplayName},
      FlossDeviceId{kPinCodeRequestAddress, kPinCodeRequestName},
      FlossDeviceId{kPhoneAddress, kPhoneName},
      FlossDeviceId{kPasskeyRequestAddress, kPasskeyRequestName},
      FlossDeviceId{kJustWorksAddress, kJustWorksName}};

  for (const auto& device : discoverable_devices) {
    if (base::Contains(connected_addresses_, device.address)) {
      // Skip connected devices.
      continue;
    }
    for (auto& observer : observers_) {
      observer.AdapterFoundDevice(device);
      observer.AdapterDevicePropertyChanged(
          FlossAdapterClient::BtPropertyType::kBdName, device);
      observer.AdapterDevicePropertyChanged(
          FlossAdapterClient::BtPropertyType::kClassOfDevice, device);
      observer.AdapterDevicePropertyChanged(
          FlossAdapterClient::BtPropertyType::kTypeOfDevice, device);
    }
  }

  PostDelayedTask(base::BindOnce(std::move(callback), Void{}));
}

void FakeFlossAdapterClient::CancelDiscovery(ResponseCallback<Void> callback) {
  // Will need to stop simulated discovery once the simulation grows.
  PostDelayedTask(base::BindOnce(std::move(callback), Void{}));
}

void FakeFlossAdapterClient::CreateBond(ResponseCallback<bool> callback,
                                        FlossDeviceId device,
                                        BluetoothTransport transport) {
  if (fail_bonding_) {
    fail_bonding_ = std::nullopt;

    std::move(callback).Run(base::unexpected(
        Error("org.chromium.Error.Failed", "Bonding failed by request")));
    return;
  }

  for (auto& observer : observers_) {
    observer.DeviceBondStateChanged(
        device, /*status=*/0,
        FlossAdapterClient::BondState::kBondingInProgress);
  }

  if (device.address == kJustWorksAddress ||
      device.address == kClassicAddress) {
    for (auto& observer : observers_) {
      observer.DeviceBondStateChanged(device, /*status=*/0,
                                      FlossAdapterClient::BondState::kBonded);
    }
    bonded_addresses_.insert(device.address);
    SetConnected(device.address, true);

    PostDelayedTask(base::BindOnce(std::move(callback), true));
  } else if (device.address == kPasskeyDisplayAddress) {
    for (auto& observer : observers_) {
      observer.AdapterSspRequest(device, /*cod=*/0,
                                 BluetoothSspVariant::kPasskeyNotification,
                                 kPasskey);
    }

    PostDelayedTask(base::BindOnce(std::move(callback), true));
  } else if (device.address == kPhoneAddress) {
    for (auto& observer : observers_) {
      observer.AdapterSspRequest(device, /*cod=*/0,
                                 BluetoothSspVariant::kPasskeyConfirmation,
                                 kPasskey);
    }

    PostDelayedTask(base::BindOnce(std::move(callback), true));
  } else if (device.address == kPasskeyRequestAddress) {
    for (auto& observer : observers_) {
      observer.AdapterSspRequest(device, /*cod=*/0,
                                 BluetoothSspVariant::kPasskeyEntry, 0);
    }

    PostDelayedTask(base::BindOnce(std::move(callback), true));
  } else if (device.address == kPinCodeDisplayAddress) {
    for (auto& observer : observers_) {
      observer.AdapterPinDisplay(device, std::string(kPinCode));
    }

    PostDelayedTask(base::BindOnce(std::move(callback), true));
  } else if (device.address == kPinCodeRequestAddress) {
    for (auto& observer : observers_) {
      observer.AdapterPinRequest(device, 0, false);
    }

    PostDelayedTask(base::BindOnce(std::move(callback), true));
  } else {
    for (auto& observer : observers_) {
      observer.DeviceBondStateChanged(
          device, static_cast<uint32_t>(BtifStatus::kFail),
          FlossAdapterClient::BondState::kNotBonded);
    }

    PostDelayedTask(base::BindOnce(
        std::move(callback),
        base::unexpected(Error("org.chromium.bluetooth.UnknownDevice", ""))));
  }
}

void FakeFlossAdapterClient::CreateBond(
    ResponseCallback<FlossDBusClient::BtifStatus> callback,
    FlossDeviceId device,
    BluetoothTransport transport) {
  if (fail_bonding_) {
    fail_bonding_ = std::nullopt;

    std::move(callback).Run(base::unexpected(
        Error("org.chromium.Error.Failed", "Bonding failed by request")));
    return;
  }

  for (auto& observer : observers_) {
    observer.DeviceBondStateChanged(
        device, /*status=*/0,
        FlossAdapterClient::BondState::kBondingInProgress);
  }

  if (device.address == kJustWorksAddress ||
      device.address == kClassicAddress) {
    for (auto& observer : observers_) {
      observer.DeviceBondStateChanged(device, /*status=*/0,
                                      FlossAdapterClient::BondState::kBonded);
    }
    bonded_addresses_.insert(device.address);
    SetConnected(device.address, true);

    PostDelayedTask(base::BindOnce(std::move(callback),
                                   FlossDBusClient::BtifStatus::kSuccess));
  } else if (device.address == kPasskeyDisplayAddress) {
    for (auto& observer : observers_) {
      observer.AdapterSspRequest(device, /*cod=*/0,
                                 BluetoothSspVariant::kPasskeyNotification,
                                 kPasskey);
    }

    PostDelayedTask(base::BindOnce(std::move(callback),
                                   FlossDBusClient::BtifStatus::kSuccess));
  } else if (device.address == kPhoneAddress) {
    for (auto& observer : observers_) {
      observer.AdapterSspRequest(device, /*cod=*/0,
                                 BluetoothSspVariant::kPasskeyConfirmation,
                                 kPasskey);
    }

    PostDelayedTask(base::BindOnce(std::move(callback),
                                   FlossDBusClient::BtifStatus::kSuccess));
  } else if (device.address == kPasskeyRequestAddress) {
    for (auto& observer : observers_) {
      observer.AdapterSspRequest(device, /*cod=*/0,
                                 BluetoothSspVariant::kPasskeyEntry, 0);
    }

    PostDelayedTask(base::BindOnce(std::move(callback),
                                   FlossDBusClient::BtifStatus::kSuccess));
  } else if (device.address == kPinCodeDisplayAddress) {
    for (auto& observer : observers_) {
      observer.AdapterPinDisplay(device, std::string(kPinCode));
    }

    PostDelayedTask(base::BindOnce(std::move(callback),
                                   FlossDBusClient::BtifStatus::kSuccess));
  } else if (device.address == kPinCodeRequestAddress) {
    for (auto& observer : observers_) {
      observer.AdapterPinRequest(device, 0, false);
    }

    PostDelayedTask(base::BindOnce(std::move(callback),
                                   FlossDBusClient::BtifStatus::kSuccess));
  } else {
    for (auto& observer : observers_) {
      observer.DeviceBondStateChanged(
          device, static_cast<uint32_t>(BtifStatus::kFail),
          FlossAdapterClient::BondState::kNotBonded);
    }

    PostDelayedTask(base::BindOnce(
        std::move(callback),
        base::unexpected(Error("org.chromium.bluetooth.UnknownDevice", ""))));
  }
}

void FakeFlossAdapterClient::CancelBondProcess(ResponseCallback<bool> callback,
                                               FlossDeviceId device) {
  for (auto& observer : observers_) {
    observer.DeviceBondStateChanged(device, /*status=*/0,
                                    FlossAdapterClient::BondState::kNotBonded);
  }
  PostDelayedTask(base::BindOnce(std::move(callback), true));
}

void FakeFlossAdapterClient::RemoveBond(ResponseCallback<bool> callback,
                                        FlossDeviceId device) {
  if (!base::Contains(bonded_addresses_, device.address)) {
    PostDelayedTask(base::BindOnce(std::move(callback), false));
    return;
  }

  for (auto& observer : observers_) {
    observer.DeviceBondStateChanged(device, /*status=*/0,
                                    FlossAdapterClient::BondState::kNotBonded);
  }
  bonded_addresses_.erase(device.address);
  SetConnected(device.address, false);

  PostDelayedTask(base::BindOnce(std::move(callback), true));
}

void FakeFlossAdapterClient::GetRemoteType(
    ResponseCallback<BluetoothDeviceType> callback,
    FlossDeviceId device) {
  auto remote_type = BluetoothDeviceType::kBredr;
  if (device.address == kBondedAddress1 || device.address == kBondedAddress2 ||
      device.address == kPairedAddressLE) {
    remote_type = BluetoothDeviceType::kBle;
  }
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), remote_type));
}

void FakeFlossAdapterClient::GetRemoteClass(ResponseCallback<uint32_t> callback,
                                            FlossDeviceId device) {
  uint32_t cod = ConvertAddressToClassOfDevice(device.address);
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), cod));
}

void FakeFlossAdapterClient::GetRemoteAppearance(
    ResponseCallback<uint16_t> callback,
    FlossDeviceId device) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), 0));
}

void FakeFlossAdapterClient::GetConnectionState(
    ResponseCallback<uint32_t> callback,
    const FlossDeviceId& device) {
  FlossAdapterClient::ConnectionState conn_state =
      FlossAdapterClient::ConnectionState::kDisconnected;

  if (base::Contains(connected_addresses_, device.address)) {
    if (device.address == kPairedAddressBrEdr) {
      conn_state = FlossAdapterClient::ConnectionState::kPairedBREDROnly;
    } else if (device.address == kPairedAddressLE) {
      conn_state = FlossAdapterClient::ConnectionState::kPairedLEOnly;
    } else {
      conn_state = FlossAdapterClient::ConnectionState::kConnectedOnly;
    }
  }

  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), static_cast<uint32_t>(conn_state)));
}

void FakeFlossAdapterClient::GetRemoteUuids(
    ResponseCallback<device::BluetoothDevice::UUIDList> callback,
    FlossDeviceId device) {
  device::BluetoothDevice::UUIDList uuid_list;
  PostDelayedTask(base::BindOnce(std::move(callback), std::move(uuid_list)));
}

void FakeFlossAdapterClient::GetRemoteVendorProductInfo(
    ResponseCallback<FlossAdapterClient::VendorProductInfo> callback,
    FlossDeviceId device) {
  FlossAdapterClient::VendorProductInfo info;
  PostDelayedTask(base::BindOnce(std::move(callback), std::move(info)));
}

void FakeFlossAdapterClient::GetRemoteAddressType(
    ResponseCallback<FlossAdapterClient::BtAddressType> callback,
    FlossDeviceId device) {
  PostDelayedTask(base::BindOnce(std::move(callback),
                                 FlossAdapterClient::BtAddressType::kPublic));
}

void FakeFlossAdapterClient::GetBondState(ResponseCallback<uint32_t> callback,
                                          const FlossDeviceId& device) {
  FlossAdapterClient::BondState bond_state =
      base::Contains(bonded_addresses_, device.address)
          ? floss::FlossAdapterClient::BondState::kBonded
          : floss::FlossAdapterClient::BondState::kNotBonded;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), static_cast<uint32_t>(bond_state)));
}

void FakeFlossAdapterClient::ConnectAllEnabledProfiles(
    ResponseCallback<Void> callback,
    const FlossDeviceId& device) {
  SetConnected(device.address, true);
  PostDelayedTask(base::BindOnce(std::move(callback), Void{}));
}

void FakeFlossAdapterClient::ConnectAllEnabledProfiles(
    ResponseCallback<FlossDBusClient::BtifStatus> callback,
    const FlossDeviceId& device) {
  SetConnected(device.address, true);
  PostDelayedTask(base::BindOnce(std::move(callback),
                                 FlossDBusClient::BtifStatus::kSuccess));
}

void FakeFlossAdapterClient::DisconnectAllEnabledProfiles(
    ResponseCallback<Void> callback,
    const FlossDeviceId& device) {
  SetConnected(device.address, false);
  PostDelayedTask(base::BindOnce(std::move(callback), Void{}));
}

void FakeFlossAdapterClient::PostDelayedTask(base::OnceClosure callback) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE, std::move(callback), base::Milliseconds(kDelayedTaskMs));
}

void FakeFlossAdapterClient::SetConnected(const std::string& address,
                                          bool connected) {
  if (base::Contains(connected_addresses_, address) == connected) {
    return;
  }
  const auto device = ConvertAddressToDevice(address);
  for (auto& observer : observers_) {
    if (connected) {
      connected_addresses_.insert(address);
      observer.AdapterDeviceConnected(device);
    } else {
      connected_addresses_.erase(address);
      observer.AdapterDeviceDisconnected(device);
    }
  }
}

void FakeFlossAdapterClient::NotifyObservers(
    const base::RepeatingCallback<void(Observer*)>& notify) const {
  for (auto& observer : observers_) {
    notify.Run(&observer);
  }
}

void FakeFlossAdapterClient::FailNextDiscovery() {
  fail_discovery_ = std::make_optional(true);
}

void FakeFlossAdapterClient::FailNextBonding() {
  fail_bonding_ = std::make_optional(true);
}

void FakeFlossAdapterClient::SetPairingConfirmation(
    ResponseCallback<Void> callback,
    const FlossDeviceId& device,
    bool accept) {
  for (auto& observer : observers_) {
    observer.DeviceBondStateChanged(device, /*status=*/0,
                                    FlossAdapterClient::BondState::kBonded);
  }
  bonded_addresses_.insert(device.address);
  SetConnected(device.address, true);

  PostDelayedTask(base::BindOnce(std::move(callback), Void{}));
}

void FakeFlossAdapterClient::SetPin(ResponseCallback<Void> callback,
                                    const FlossDeviceId& device,
                                    bool accept,
                                    const std::vector<uint8_t>& pin) {
  for (auto& observer : observers_) {
    observer.DeviceBondStateChanged(device, /*status=*/0,
                                    FlossAdapterClient::BondState::kBonded);
  }
  bonded_addresses_.insert(device.address);
  SetConnected(device.address, true);

  PostDelayedTask(base::BindOnce(std::move(callback), Void{}));
}

void FakeFlossAdapterClient::GetBondedDevices() {
  for (const auto& addr : bonded_addresses_) {
    const auto device_id = ConvertAddressToDevice(addr);
    for (auto& observer : observers_) {
      observer.AdapterFoundDevice(device_id);
    }
  }
}

void FakeFlossAdapterClient::GetConnectedDevices() {
  for (const auto& addr : connected_addresses_) {
    const auto device_id = ConvertAddressToDevice(addr);
    for (auto& observer : observers_) {
      observer.AdapterFoundDevice(device_id);
      observer.AdapterDeviceConnected(device_id);
    }
  }
}

}  // namespace floss