chromium/chromeos/ash/components/phonehub/phone_hub_structured_metrics_logger.h

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMEOS_ASH_COMPONENTS_PHONEHUB_PHONE_HUB_STRUCTURED_METRICS_LOGGER_H_
#define CHROMEOS_ASH_COMPONENTS_PHONEHUB_PHONE_HUB_STRUCTURED_METRICS_LOGGER_H_

#include <optional>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "chromeos/ash/components/phonehub/proto/phonehub_api.pb.h"
#include "chromeos/ash/services/secure_channel/public/cpp/client/secure_channel_structured_metrics_logger.h"
#include "chromeos/ash/services/secure_channel/public/mojom/nearby_connector.mojom-shared.h"
#include "chromeos/ash/services/secure_channel/public/mojom/secure_channel.mojom-shared.h"
#include "chromeos/ash/services/secure_channel/public/mojom/secure_channel.mojom.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "components/metrics/structured/event.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace {
base::TimeDelta kMaxStructuredMetricsPseudonymousIdDays = base::Days(90);
}
namespace ash::phonehub {

enum class DiscoveryEntryPoint {
  kUserSignIn = 0,
  kChromebookUnlock = 1,
  // TODO(b/324320785): Record attempt times with entrypoint instead of
  // recording retry as separate entrypoints.
  kAutomaticConnectionRetry = 2,
  kManualConnectionRetry = 3,
  kConnectionRetryAfterConnected = 4,
  kPhoneHubBubbleOpen = 5,
  kMultiDeviceFeatureSetup = 6,
  kBluetoothEnabled = 7,
  kUserEnabledFeature = 8,
  kUserOnboardedToFeature = 9
};

enum class PhoneHubMessageDirection {
  kPhoneToChromebook = 0,
  kChromebookToPhone = 1
};

enum class PhoneHubUiState {
  kDisconnected = 0,
  kConnecting = 1,
  kConnected = 2
};

enum class BluetoothStack { kBlueZ = 0, kFloss = 1 };

enum class NetworkState {
  kUnknown = 0,
  kSameNetwork = 1,
  kDifferentNetwork = 2,
  kPhoneOnCellular = 3
};

enum class Medium { kBluetooth = 0, kWebRTC = 1 };

class PhoneHubStructuredMetricsLogger
    : public ash::secure_channel::SecureChannelStructuredMetricsLogger {
 public:
  static void RegisterPrefs(PrefRegistrySimple* registry);

  explicit PhoneHubStructuredMetricsLogger(PrefService* pref_service);
  ~PhoneHubStructuredMetricsLogger() override;

  PhoneHubStructuredMetricsLogger(const PhoneHubStructuredMetricsLogger&) =
      delete;
  PhoneHubStructuredMetricsLogger& operator=(
      const PhoneHubStructuredMetricsLogger&) = delete;

  void LogPhoneHubDiscoveryStarted(DiscoveryEntryPoint entry_point);

  // secure_channel::mojom::SecureChannelStructuredMetricsLogger
  void LogDiscoveryAttempt(
      secure_channel::mojom::DiscoveryResult result,
      std::optional<secure_channel::mojom::DiscoveryErrorCode> error_code)
      override;
  void LogNearbyConnectionState(
      secure_channel::mojom::NearbyConnectionStep step,
      secure_channel::mojom::NearbyConnectionStepResult result) override;
  void LogSecureChannelState(
      secure_channel::mojom::SecureChannelState state) override;

  void LogPhoneHubMessageEvent(proto::MessageType message_type,
                               PhoneHubMessageDirection message_direction);
  void LogPhoneHubUiStateUpdated(PhoneHubUiState ui_state);

  void ProcessPhoneInformation(const proto::PhoneProperties& phone_properties);

  void ResetCachedInformation();

  void ResetSessionId();

  void SetChromebookInfo(proto::CrosState& cros_state_message);

 private:
  FRIEND_TEST_ALL_PREFIXES(PhoneHubStructuredMetricsLoggerTest,
                           ProcessPhoneInformation_MissingFields);
  FRIEND_TEST_ALL_PREFIXES(PhoneHubStructuredMetricsLoggerTest,
                           ProcessPhoneInformation_AllFields);
  FRIEND_TEST_ALL_PREFIXES(PhoneHubStructuredMetricsLoggerTest, LogEvents);

  void UpdateIdentifiersIfNeeded();
  void OnNetworkStateListFetched(
      std::vector<chromeos::network_config::mojom::NetworkStatePropertiesPtr>
          networks);
  void UploadDeviceInfo();

  // Phone information
  std::optional<proto::NetworkStatus> phone_network_status_;
  std::optional<std::string> phone_network_ssid_;

  // Chromebook information
  BluetoothStack bluetooth_stack_;
  NetworkState network_state_ = NetworkState::kUnknown;
  std::string chromebook_locale_;

  std::string phone_hub_session_id_;
  Medium medium_ = Medium::kBluetooth;

  mojo::Remote<chromeos::network_config::mojom::CrosNetworkConfig>
      cros_network_config_;
  raw_ptr<PrefService> pref_service_;
};

}  // namespace ash::phonehub

#endif  // CHROMEOS_ASH_COMPONENTS_PHONEHUB_PHONE_HUB_STRUCTURED_METRICS_LOGGER_H_