chromium/ash/quick_pair/fast_pair_handshake/fast_pair_gatt_service_client_impl.h

// 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.

#ifndef ASH_QUICK_PAIR_FAST_PAIR_HANDSHAKE_FAST_PAIR_GATT_SERVICE_CLIENT_IMPL_H_
#define ASH_QUICK_PAIR_FAST_PAIR_HANDSHAKE_FAST_PAIR_GATT_SERVICE_CLIENT_IMPL_H_

#include <stdint.h>

#include <optional>
#include <vector>

#include "ash/quick_pair/common/pair_failure.h"
#include "ash/quick_pair/fast_pair_handshake/fast_pair_gatt_service_client.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"

namespace device {

class BluetoothDevice;
class BluetoothGattConnection;
class BluetoothRemoteGattService;
class BluetoothGattNotifySession;
class BluetoothRemoteGattService;

}  // namespace device

namespace ash {
namespace quick_pair {

class FastPairDataEncryptor;

// This class is responsible for connecting to the Fast Pair GATT service for a
// device and invoking a callback when ready, or when an error is discovered
// during initialization.
class FastPairGattServiceClientImpl : public FastPairGattServiceClient {
 public:
  class Factory {
   public:
    static std::unique_ptr<FastPairGattServiceClient> Create(
        device::BluetoothDevice* device,
        scoped_refptr<device::BluetoothAdapter> adapter,
        base::OnceCallback<void(std::optional<PairFailure>)>
            on_initialized_callback);
    static void SetFactoryForTesting(Factory* test_factory);

   protected:
    virtual ~Factory();
    virtual std::unique_ptr<FastPairGattServiceClient> CreateInstance(
        device::BluetoothDevice* device,
        scoped_refptr<device::BluetoothAdapter> adapter,
        base::OnceCallback<void(std::optional<PairFailure>)>
            on_initialized_callback) = 0;

   private:
    static Factory* g_test_factory_;
  };

  ~FastPairGattServiceClientImpl() override;

  device::BluetoothRemoteGattService* gatt_service() override;

  bool IsConnected() override;

  void ReadModelIdAsync(
      base::OnceCallback<void(
          std::optional<device::BluetoothGattService::GattErrorCode> error_code,
          const std::vector<uint8_t>& value)> callback) override;

  void WriteRequestAsync(
      uint8_t message_type,
      uint8_t flags,
      const std::string& provider_address,
      const std::string& seekers_address,
      FastPairDataEncryptor* fast_pair_data_encryptor,
      base::OnceCallback<void(std::vector<uint8_t>, std::optional<PairFailure>)>
          write_response_callback) override;

  void WritePasskeyAsync(
      uint8_t message_type,
      uint32_t passkey,
      FastPairDataEncryptor* fast_pair_data_encryptor,
      base::OnceCallback<void(std::vector<uint8_t>, std::optional<PairFailure>)>
          write_response_callback) override;

  void WriteAccountKey(std::array<uint8_t, 16> account_key,
                       FastPairDataEncryptor* fast_pair_data_encryptor,
                       base::OnceCallback<void(
                           std::optional<ash::quick_pair::AccountKeyFailure>)>
                           write_account_key_callback) override;

  void WritePersonalizedName(
      const std::string& name,
      const std::string& provider_address,
      FastPairDataEncryptor* fast_pair_data_encryptor,
      base::OnceCallback<void(std::optional<PairFailure>)>
          write_additional_data_callback) override;

 private:
  FastPairGattServiceClientImpl(
      device::BluetoothDevice* device,
      scoped_refptr<device::BluetoothAdapter> adapter,
      base::OnceCallback<void(std::optional<PairFailure>)>
          on_initialized_callback);
  FastPairGattServiceClientImpl(const FastPairGattServiceClientImpl&) = delete;
  FastPairGattServiceClientImpl& operator=(
      const FastPairGattServiceClientImpl&) = delete;

  // Creates a data vector based on parameter information.
  const std::array<uint8_t, kBlockByteSize> CreateRequest(
      uint8_t message_type,
      uint8_t flags,
      const std::string& provider_address,
      const std::string& seekers_address);
  const std::array<uint8_t, kBlockByteSize> CreatePasskeyBlock(
      uint8_t message_type,
      uint32_t passkey);

  // Attempt to create a GATT connection with the device. This method may be
  // called multiple times.
  void AttemptGattConnection();
  void CreateGattConnection();
  void CoolOffBeforeCreateGattConnection();
  void OnDisconnectTimeout();
  void OnGattServiceDiscoveryTimeout();

  // Callback from the adapter's call to create GATT connection.
  void OnGattConnection(
      base::TimeTicks gatt_connection_start_time,
      std::unique_ptr<device::BluetoothGattConnection> gatt_connection,
      std::optional<device::BluetoothDevice::ConnectErrorCode> error_code);

  // Invokes the initialized callback with the proper PairFailure and clears
  // local state.
  void NotifyInitializedError(PairFailure failure);

  // Invokes the write response callback with the proper PairFailure on a
  // write error.
  void NotifyWriteRequestError(PairFailure failure);
  void NotifyWritePasskeyError(PairFailure failure);
  void NotifyWriteAccountKeyError(ash::quick_pair::AccountKeyFailure failure);

  void ClearCurrentState();

  // BluetoothAdapter::Observer
  void GattDiscoveryCompleteForService(
      device::BluetoothAdapter* adapter,
      device::BluetoothRemoteGattService* service) override;
  void GattCharacteristicValueChanged(
      device::BluetoothAdapter* adapter,
      device::BluetoothRemoteGattCharacteristic* characteristic,
      const std::vector<uint8_t>& value) override;

  std::optional<PairFailure> SetGattCharacteristics();

  std::vector<device::BluetoothRemoteGattCharacteristic*>
  GetCharacteristicsByUUIDs(const device::BluetoothUUID& uuidV1,
                            const device::BluetoothUUID& uuidV2);

  // Writes the encrypted personalized name packet to the
  // `additional_data_characteristic_`.
  void OnWritePersonalizedNameRequest(
      const std::string& name,
      const std::string& provider_address,
      FastPairDataEncryptor* fast_pair_data_encryptor);

  // Writes `encrypted_request` to `characteristic`.
  void WriteGattCharacteristicWithTimeout(
      device::BluetoothRemoteGattCharacteristic* characteristic,
      const std::vector<uint8_t>& encrypted_request,
      device::BluetoothRemoteGattCharacteristic::WriteType write_type,
      base::OnceClosure on_timeout,
      base::OnceClosure on_sucess,
      base::OnceCallback<void(device::BluetoothGattService::GattErrorCode)>
          on_failure);

  // Helper functions to WriteGattCharacteristicTimeout.
  // Both stop `characteristic`'s corresponding timer in
  // `characteristic_write_request_timers_` and run `on_success`/`on_failure`
  // callbacks. `on_failure` must take parameter `error`.
  void StopTimerRunSuccess(
      device::BluetoothRemoteGattCharacteristic* characteristic,
      base::OnceClosure on_success);
  void StopTimerRunFailure(
      device::BluetoothRemoteGattCharacteristic* characteristic,
      base::OnceCallback<void(device::BluetoothGattService::GattErrorCode)>
          on_failure,
      device::BluetoothGattService::GattErrorCode error);

  // Stops `characteristic`'s corresponding timer in
  // `characteristic_write_request_timers_` if it exists.
  void StopWriteRequestTimer(
      device::BluetoothRemoteGattCharacteristic* characteristic);

  // Stops all timers in `characteristic_write_request_timers_`.
  void StopAllWriteRequestTimers();

  // BluetoothRemoteGattCharacteristic StartNotifySession callbacks
  void OnKeyBasedRequestNotifySession(
      const std::vector<uint8_t>& request_data,
      std::unique_ptr<device::BluetoothGattNotifySession> session);
  void OnPasskeyNotifySession(
      const std::vector<uint8_t>& passkey_data,
      std::unique_ptr<device::BluetoothGattNotifySession> session);
  void OnNotifySessionError(PairFailure failure,
                            device::BluetoothGattService::GattErrorCode error);

  void OnWriteAdditionalDataTimeout();

  // BluetoothRemoteGattCharacteristic WriteRemoteCharacteristic callbacks
  void OnWriteRequest();
  void OnWriteRequestError(device::BluetoothGattService::GattErrorCode error);
  void OnWritePasskey();
  void OnWritePasskeyError(device::BluetoothGattService::GattErrorCode error);
  void OnWriteAccountKey(base::TimeTicks write_account_key_start_time);
  void OnWriteAccountKeyError(
      device::BluetoothGattService::GattErrorCode error);
  void OnWriteAdditionalData();
  void OnWriteAdditionalDataError(
      device::BluetoothGattService::GattErrorCode error);

  base::OneShotTimer gatt_connect_after_disconnect_cool_off_timer_;
  base::OneShotTimer gatt_disconnect_timer_;
  base::OneShotTimer gatt_service_discovery_timer_;
  base::OneShotTimer passkey_notify_session_timer_;
  base::OneShotTimer keybased_notify_session_timer_;
  base::OneShotTimer key_based_write_request_timer_;

  std::map<device::BluetoothRemoteGattCharacteristic*,
           std::unique_ptr<base::OneShotTimer>>
      characteristic_write_request_timers_;

  base::TimeTicks gatt_service_discovery_start_time_;
  base::TimeTicks passkey_notify_session_start_time_;
  base::TimeTicks keybased_notify_session_start_time_;
  base::TimeTicks passkey_write_request_start_time_;
  base::TimeTicks key_based_write_request_start_time_;

  base::OnceCallback<void(std::optional<PairFailure>)> on_initialized_callback_;
  base::OnceCallback<void(std::vector<uint8_t>, std::optional<PairFailure>)>
      key_based_write_response_callback_;
  base::OnceCallback<void(std::vector<uint8_t>, std::optional<PairFailure>)>
      passkey_write_response_callback_;
  base::OnceCallback<void(std::optional<ash::quick_pair::AccountKeyFailure>)>
      write_account_key_callback_;
  base::OnceCallback<void(std::optional<PairFailure>)>
      write_additional_data_callback_;

  std::string device_address_;
  bool is_initialized_ = false;

  // Initial timestamps used to calculate duration to log to metrics.
  base::TimeTicks notify_keybased_start_time_;
  base::TimeTicks notify_passkey_start_time_;

  raw_ptr<device::BluetoothRemoteGattCharacteristic, DanglingUntriaged>
      model_id_characteristic_ = nullptr;
  raw_ptr<device::BluetoothRemoteGattCharacteristic, DanglingUntriaged>
      key_based_characteristic_ = nullptr;
  raw_ptr<device::BluetoothRemoteGattCharacteristic, DanglingUntriaged>
      passkey_characteristic_ = nullptr;
  raw_ptr<device::BluetoothRemoteGattCharacteristic, DanglingUntriaged>
      account_key_characteristic_ = nullptr;
  raw_ptr<device::BluetoothRemoteGattCharacteristic, DanglingUntriaged>
      additional_data_characteristic_ = nullptr;

  // Initialize with zero failures.
  int num_gatt_connection_attempts_ = 0;

  std::unique_ptr<device::BluetoothGattNotifySession> key_based_notify_session_;
  std::unique_ptr<device::BluetoothGattNotifySession> passkey_notify_session_;
  scoped_refptr<device::BluetoothAdapter> adapter_;
  std::unique_ptr<device::BluetoothGattConnection> gatt_connection_;
  raw_ptr<device::BluetoothRemoteGattService, DanglingUntriaged> gatt_service_ =
      nullptr;

  base::ScopedObservation<device::BluetoothAdapter,
                          device::BluetoothAdapter::Observer>
      adapter_observation_{this};
  base::WeakPtrFactory<FastPairGattServiceClientImpl> weak_ptr_factory_{this};
};

}  // namespace quick_pair
}  // namespace ash

#endif  // ASH_QUICK_PAIR_FAST_PAIR_HANDSHAKE_FAST_PAIR_GATT_SERVICE_CLIENT_IMPL_H_