910e62b5创建于 1月15日历史提交
// Copyright 2023 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/bluetooth_local_gatt_descriptor_floss.h"

#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/types/cxx23_to_underlying.h"
#include "device/bluetooth/floss/bluetooth_gatt_characteristic_floss.h"
#include "device/bluetooth/floss/floss_dbus_manager.h"

namespace floss {

// static
base::WeakPtr<BluetoothLocalGattDescriptorFloss>
BluetoothLocalGattDescriptorFloss::Create(
    const device::BluetoothUUID& uuid,
    device::BluetoothGattCharacteristic::Permissions permissions,
    BluetoothLocalGattCharacteristicFloss* characteristic) {
  const auto& [_, floss_permissions] =
      BluetoothGattCharacteristicFloss::ConvertPropsAndPermsToFloss(
          /*properties=*/0, static_cast<uint16_t>(permissions));
  auto* descriptor = new BluetoothLocalGattDescriptorFloss(
      uuid, floss_permissions, characteristic);
  auto weak_ptr = descriptor->weak_ptr_factory_.GetWeakPtr();
  weak_ptr->index_ =
      characteristic->AddDescriptor(base::WrapUnique(descriptor));
  return weak_ptr;
}

BluetoothLocalGattDescriptorFloss::BluetoothLocalGattDescriptorFloss(
    const device::BluetoothUUID& uuid,
    device::BluetoothGattCharacteristic::Permissions permissions,
    BluetoothLocalGattCharacteristicFloss* characteristic)
    : uuid_(uuid),
      permissions_(permissions),
      characteristic_(raw_ref<BluetoothLocalGattCharacteristicFloss>::from_ptr(
          characteristic)),
      client_instance_id_(characteristic_->service_->NewInstanceId()) {}

BluetoothLocalGattDescriptorFloss::~BluetoothLocalGattDescriptorFloss() {
  characteristic_->service_->RemoveServerObserverForHandle(floss_instance_id_);
}

std::string BluetoothLocalGattDescriptorFloss::GetIdentifier() const {
  return base::StringPrintf(
      "%s-%s/%04x",
      characteristic_->service_->GetAdapter()->GetAddress().c_str(),
      GetUUID().value().c_str(), client_instance_id_);
}

device::BluetoothUUID BluetoothLocalGattDescriptorFloss::GetUUID() const {
  return uuid_;
}

device::BluetoothGattCharacteristic::Permissions
BluetoothLocalGattDescriptorFloss::GetPermissions() const {
  const auto& [_, perms] =
      BluetoothGattCharacteristicFloss::ConvertPropsAndPermsFromFloss(
          /*properties=*/0, permissions_);
  return perms;
}

device::BluetoothLocalGattCharacteristic*
BluetoothLocalGattDescriptorFloss::GetCharacteristic() const {
  return &*characteristic_;
}

GattDescriptor BluetoothLocalGattDescriptorFloss::ToGattDescriptor() {
  GattDescriptor descriptor;
  descriptor.uuid = uuid_;
  descriptor.instance_id = floss_instance_id_;
  descriptor.permissions = permissions_;
  return descriptor;
}

void BluetoothLocalGattDescriptorFloss::ResolveInstanceId(
    const GattCharacteristic& characteristic) {
  DCHECK(characteristic.descriptors[index_].uuid == GetUUID());
  floss_instance_id_ = characteristic.descriptors[index_].instance_id;
  characteristic_->service_->AddServerObserverForHandle(floss_instance_id_,
                                                        this);
}

void BluetoothLocalGattDescriptorFloss::GattServerDescriptorReadRequest(
    std::string address,
    int32_t request_id,
    int32_t offset,
    bool is_long,
    int32_t handle) {
  DCHECK(handle == floss_instance_id_);

  if (pending_request_.has_value()) {
    LOG(ERROR) << __func__ << ": A request for device '"
               << pending_request_.value().address << "' is already pending";
    FlossDBusManager::Get()->GetGattManagerClient()->SendResponse(
        base::DoNothing(), address, request_id, GattStatus::kBusy, offset,
        std::vector<uint8_t>());
    return;
  }

  device::BluetoothLocalGattService::Delegate* delegate =
      characteristic_->service_->delegate_;
  if (!delegate) {
    LOG(ERROR) << __func__ << ": No delegate for local GATT service";
    FlossDBusManager::Get()->GetGattManagerClient()->SendResponse(
        base::DoNothing(), address, request_id, GattStatus::kError, offset,
        std::vector<uint8_t>());
    return;
  }

  pending_request_.emplace(GattRequest{address, request_id, offset});
  auto* device = characteristic_->service_->GetAdapter()->GetDevice(address);
  BluetoothLocalGattDescriptor* descriptor =
      static_cast<BluetoothLocalGattDescriptor*>(this);

  // This callback is expected to run, so run it if the client has not done so
  // within the next second.
  response_timer_.Start(
      FROM_HERE, kResponseTimeout,
      base::BindOnce(&BluetoothLocalGattDescriptorFloss::OnReadRequestCallback,
                     weak_ptr_factory_.GetWeakPtr(), request_id,
                     BluetoothGattServiceFloss::GattErrorCode::kFailed,
                     base::OwnedRef(std::vector<uint8_t>())));

  delegate->OnDescriptorReadRequest(
      device, descriptor, offset,
      base::BindOnce(&BluetoothLocalGattDescriptorFloss::OnReadRequestCallback,
                     weak_ptr_factory_.GetWeakPtr(), request_id));
}

void BluetoothLocalGattDescriptorFloss::OnReadRequestCallback(
    int32_t request_id,
    std::optional<BluetoothGattServiceFloss::GattErrorCode> error_code,
    const std::vector<uint8_t>& value) {
  if (!pending_request_.has_value()) {
    // If this check trips, we have already handled the request response.
    LOG(ERROR) << __func__ << ": No pending read request for request with id "
               << request_id;
    return;
  }
  auto read_request = pending_request_.value();
  if (read_request.request_id != request_id) {
    // This check may trip due to a stale (timed-out) request being belatedly
    // responded to.
    LOG(ERROR) << __func__ << ": Read request id mismatch. Expected: "
               << read_request.request_id << ", Actual: " << request_id;
    return;
  }
  response_timer_.Stop();

  GattStatus status = error_code.has_value()
                          ? BluetoothGattServiceFloss::GattServiceErrorToStatus(
                                error_code.value())
                          : GattStatus::kSuccess;
  FlossDBusManager::Get()->GetGattManagerClient()->SendResponse(
      base::DoNothing(), read_request.address, request_id, status,
      read_request.offset, value);
  pending_request_.reset();
}

void BluetoothLocalGattDescriptorFloss::GattServerDescriptorWriteRequest(
    std::string address,
    int32_t request_id,
    int32_t offset,
    int32_t length,
    bool is_prepared_write,
    bool needs_response,
    int32_t handle,
    std::vector<uint8_t> value) {
  DCHECK(handle == floss_instance_id_);

  if (is_prepared_write) {
    // TODO(b/329709266) - Support prepare write requests for descriptors
    LOG(ERROR) << __func__ << ": Prepared write request not supported.";
    if (needs_response) {
      FlossDBusManager::Get()->GetGattManagerClient()->SendResponse(
          base::DoNothing(), address, request_id, GattStatus::kReqNotSupported,
          offset, value);
    }
    return;
  }

  if (pending_request_.has_value()) {
    LOG(ERROR) << __func__ << ": A request for device '"
               << pending_request_.value().address << "' is already pending";
    if (needs_response) {
      FlossDBusManager::Get()->GetGattManagerClient()->SendResponse(
          base::DoNothing(), address, request_id, GattStatus::kBusy, offset,
          value);
    }
    return;
  }

  device::BluetoothLocalGattService::Delegate* delegate =
      characteristic_->service_->delegate_;
  if (!delegate) {
    LOG(ERROR) << __func__ << ": No delegate for local GATT service";
    if (needs_response) {
      FlossDBusManager::Get()->GetGattManagerClient()->SendResponse(
          base::DoNothing(), address, request_id, GattStatus::kError, offset,
          value);
    }
    return;
  }

  if (GetUUID() ==
      BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid()) {
    auto status = HandleCccDescriptor(address, value);
    if (needs_response) {
      FlossDBusManager::Get()->GetGattManagerClient()->SendResponse(
          base::DoNothing(), address, request_id, status, offset, value);
    }
    return;
  }

  pending_request_.emplace(GattRequest{address, request_id, offset});
  auto* device = characteristic_->service_->GetAdapter()->GetDevice(address);
  BluetoothLocalGattDescriptor* descriptor =
      static_cast<BluetoothLocalGattDescriptor*>(this);

  // This callback is expected to run, so run it if the client has not done so
  // within the next second.
  response_timer_.Start(
      FROM_HERE, kResponseTimeout,
      base::BindOnce(&BluetoothLocalGattDescriptorFloss::OnWriteRequestCallback,
                     weak_ptr_factory_.GetWeakPtr(), request_id,
                     base::OwnedRef(value), needs_response, /*success=*/false));

  delegate->OnDescriptorWriteRequest(
      device, descriptor, value, offset,
      base::BindOnce(&BluetoothLocalGattDescriptorFloss::OnWriteRequestCallback,
                     weak_ptr_factory_.GetWeakPtr(), request_id,
                     base::OwnedRef(value), needs_response,
                     /*success=*/true),
      base::BindOnce(&BluetoothLocalGattDescriptorFloss::OnWriteRequestCallback,
                     weak_ptr_factory_.GetWeakPtr(), request_id,
                     base::OwnedRef(value), needs_response,
                     /*success=*/false));
}

void BluetoothLocalGattDescriptorFloss::OnWriteRequestCallback(
    int32_t request_id,
    std::vector<uint8_t>& value,
    bool needs_response,
    bool success) {
  if (!pending_request_.has_value()) {
    // If this check trips, we have already handled the request response.
    LOG(ERROR) << __func__ << ": No pending write request for request with id "
               << request_id;
    return;
  }
  auto write_request = pending_request_.value();
  if (write_request.request_id != request_id) {
    // This check may trip due to a stale (timed-out) request being belatedly
    // responded to.
    LOG(ERROR) << __func__ << ": Write request id mismatch. Expected: "
               << write_request.request_id << ", Actual: " << request_id;
    return;
  }
  response_timer_.Stop();

  if (!needs_response) {
    pending_request_.reset();
    return;
  }
  GattStatus status = success ? GattStatus::kSuccess : GattStatus::kError;
  FlossDBusManager::Get()->GetGattManagerClient()->SendResponse(
      base::DoNothing(), write_request.address, write_request.request_id,
      status, write_request.offset, value);
  pending_request_.reset();
}

GattStatus BluetoothLocalGattDescriptorFloss::HandleCccDescriptor(
    std::string address,
    std::vector<uint8_t>& value) {
  device::BluetoothLocalGattService::Delegate* delegate =
      characteristic_->service_->delegate_;
  auto* device = characteristic_->service_->GetAdapter()->GetDevice(address);
  device::BluetoothLocalGattCharacteristic* characteristic =
      static_cast<device::BluetoothLocalGattCharacteristic*>(
          &characteristic_.get());

  if (value.size() != 2) {
    LOG(ERROR) << __func__ << ": Value is not a valid CccdValueType";
    return GattStatus::kCccCfgErr;
  }
  uint16_t notification_type = (value[1] << 8) + value[0];

  auto properties = characteristic_->GetProperties();
  switch (notification_type) {
    case base::to_underlying(
        device::BluetoothGattCharacteristic::NotificationType::kNone):
      cccd_type_ = device::BluetoothGattCharacteristic::NotificationType::kNone;
      delegate->OnNotificationsStop(device, characteristic);
      break;
    case base::to_underlying(
        device::BluetoothGattCharacteristic::NotificationType::kNotification):
      if (!(properties &
            device::BluetoothGattCharacteristic::PROPERTY_NOTIFY)) {
        LOG(WARNING) << __func__ << ": Parent characteristic (uuid: "
                     << characteristic_->GetUUID()
                     << ") does not have the necessary properties to notify "
                        "(properties: "
                     << properties << ")";
        return GattStatus::kCccCfgErr;
      }
      cccd_type_ =
          device::BluetoothGattCharacteristic::NotificationType::kNotification;
      delegate->OnNotificationsStart(device, cccd_type_, characteristic);
      break;
    case base::to_underlying(
        device::BluetoothGattCharacteristic::NotificationType::kIndication):
      if (!(properties &
            device::BluetoothGattCharacteristic::PROPERTY_INDICATE)) {
        LOG(WARNING) << __func__ << ": Parent characteristic (uuid: "
                     << characteristic_->GetUUID()
                     << ") does not have the necessary properties to indicate "
                        "(properties: "
                     << properties << ")";
        return GattStatus::kCccCfgErr;
      }
      cccd_type_ =
          device::BluetoothGattCharacteristic::NotificationType::kIndication;
      delegate->OnNotificationsStart(device, cccd_type_, characteristic);
      break;
    default:
      LOG(WARNING) << __func__ << ": Value '" << notification_type
                   << "' is not a valid CccdValueType";
      return GattStatus::kCccCfgErr;
  }
  return GattStatus::kSuccess;
}

}  // namespace floss