chromium/components/variations/service/variations_service.cc

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

#include "components/variations/service/variations_service.h"

#include <stddef.h>
#include <stdint.h>

#include <optional>
#include <string_view>
#include <utility>
#include <vector>

#include "base/base64.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/observer_list.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
#include "base/version.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/encrypted_messages/encrypted_message.pb.h"
#include "components/encrypted_messages/message_encrypter.h"
#include "components/metrics/metrics_state_manager.h"
#include "components/network_time/network_time_tracker.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/variations/field_trial_internals_utils.h"
#include "components/variations/pref_names.h"
#include "components/variations/proto/variations_seed.pb.h"
#include "components/variations/seed_response.h"
#include "components/variations/service/limited_entropy_synthetic_trial.h"
#include "components/variations/synthetic_trial_registry.h"
#include "components/variations/variations_safe_seed_store_local_state.h"
#include "components/variations/variations_seed_simulator.h"
#include "components/variations/variations_switches.h"
#include "components/variations/variations_url_constants.h"
#include "components/version_info/channel.h"
#include "components/version_info/version_info.h"
#include "net/base/net_errors.h"
#include "net/base/url_util.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "url/gurl.h"

namespace variations {
namespace {

// Constants used for encrypting the if-none-match header if we are retrieving a
// seed over http.
const char kEncryptedMessageLabel[] =;

// TODO(crbug.com/41359527): Change this key to a unique VariationsService one,
// once the matching private key is changed server side.
// Key is used to encrypt headers in seed retrieval requests that happen over
// HTTP connections (when retrying after an unsuccessful HTTPS retrieval
// attempt).
const uint8_t kServerPublicKey[] =;

const uint32_t kServerPublicKeyVersion =;

// For the HTTP date headers, the resolution of the server time is 1 second.
const uint32_t kServerTimeResolutionInSeconds =;

// Whether the VariationsService should fetch the seed for testing.
bool g_should_fetch_for_testing =;

// Returns a string that will be used for the value of the 'osname' URL param
// to the variations server.
std::string GetPlatformString() {}

// Gets the restrict parameter from either the passed override, the client or
// |policy_pref_service|.
std::string GetRestrictParameterValue(const std::string& restrict_mode_override,
                                      VariationsServiceClient* client,
                                      PrefService* policy_pref_service) {}

// Reported to UMA, keep in sync with enums.xml and don't renumber entries.
enum ResourceRequestsAllowedState {};

// Records UMA histogram with the current resource requests allowed state.
void RecordRequestsAllowedHistogram(ResourceRequestsAllowedState state) {}

// Converts ResourceRequestAllowedNotifier::State to the corresponding
// ResourceRequestsAllowedState value.
ResourceRequestsAllowedState ResourceRequestStateToHistogramValue(
    web_resource::ResourceRequestAllowedNotifier::State state) {}

// Returns the header value for |name| from |headers| or an empty string if not
// set.
std::string GetHeaderValue(const net::HttpResponseHeaders* headers,
                           std::string_view name) {}

// Returns the list of values for |name| from |headers|. If the header in not
// set, return an empty list.
std::vector<std::string> GetHeaderValuesList(
    const net::HttpResponseHeaders* headers,
    std::string_view name) {}

// Looks for delta and gzip compression instance manipulation flags set by the
// server in |headers|. Checks the order of flags and presence of unknown
// instance manipulations. If successful, |is_delta_compressed| and
// |is_gzip_compressed| contain compression flags and true is returned.
bool GetInstanceManipulations(const net::HttpResponseHeaders* headers,
                              bool* is_delta_compressed,
                              bool* is_gzip_compressed) {}

// Variations seed fetching is only enabled in official Chrome builds, if a URL
// is specified on the command line, and for testing.
bool IsFetchingEnabled() {}

// Returns the already downloaded first run seed, and clear the seed from the
// native-side prefs. At this point, the seed has already been fetched from the
// native seed storage, so it's no longer needed there. This is done regardless
// if we fail or succeed below - since if we succeed, we're good to go and if we
// fail, we probably don't want to keep around the bad content anyway.
std::unique_ptr<SeedResponse> MaybeImportFirstRunSeed(
    VariationsServiceClient* client,
    PrefService* local_state) {}

}  // namespace

#if BUILDFLAG(IS_CHROMEOS_ASH)
// This is a utility which syncs the policy-managed value of
// |prefs::kDeviceVariationsRestrictionsByPolicy| into
// |prefs::kVariationsRestrictionsByPolicy|.
// TODO(crbug.com/40121933): Remove this workaround and implement a better long
// term solution.
class DeviceVariationsRestrictionByPolicyApplicator {
 public:
  DeviceVariationsRestrictionByPolicyApplicator(
      PrefService* policy_pref_service)
      : policy_pref_service_(policy_pref_service) {
    DCHECK(policy_pref_service_);
    const PrefService::PrefInitializationStatus prefs_init_status =
        policy_pref_service_->GetAllPrefStoresInitializationStatus();
    if (prefs_init_status == PrefService::INITIALIZATION_STATUS_WAITING) {
      policy_pref_service_->AddPrefInitObserver(
          base::BindOnce(&DeviceVariationsRestrictionByPolicyApplicator::
                             OnPolicyPrefServiceInitialized,
                         weak_ptr_factory_.GetWeakPtr()));
      return;
    }
    OnPolicyPrefServiceInitialized(prefs_init_status ==
                                   PrefService::INITIALIZATION_STATUS_SUCCESS);
  }

  ~DeviceVariationsRestrictionByPolicyApplicator() = default;

  DeviceVariationsRestrictionByPolicyApplicator(
      const DeviceVariationsRestrictionByPolicyApplicator& other) = delete;
  DeviceVariationsRestrictionByPolicyApplicator& operator=(
      const DeviceVariationsRestrictionByPolicyApplicator& other) = delete;

 private:
  void OnPolicyPrefServiceInitialized(bool successful) {
    // If PrefService initialization was not successful, another component will
    // display an error message to the user.
    if (!successful)
      return;

    pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
    pref_change_registrar_->Init(policy_pref_service_);
    pref_change_registrar_->Add(
        prefs::kDeviceVariationsRestrictionsByPolicy,
        base::BindRepeating(&DeviceVariationsRestrictionByPolicyApplicator::
                                OnDevicePolicyChange,
                            weak_ptr_factory_.GetWeakPtr()));
    // Also process the initial value.
    OnDevicePolicyChange();
  }

  // Observes the changes in prefs::kDeviceVariationsRestrictionsByPolicy,
  // and saves and retrieve its local state value, then sets
  // prefs::kVariationsRestrictParameter with that new value. That's to
  // reflect the changes of chromeos policy into the user policy.
  // TODO(crbug.com/40121933): Remove that workaround, and make a better long
  // term solution.
  void OnDevicePolicyChange() {
    const std::string& device_policy =
        prefs::kDeviceVariationsRestrictionsByPolicy;
    const std::string& user_policy = prefs::kVariationsRestrictionsByPolicy;

    if (policy_pref_service_->IsManagedPreference(device_policy)) {
      const int device_value = policy_pref_service_->GetInteger(device_policy);
      policy_pref_service_->SetInteger(user_policy, device_value);
    } else {
      policy_pref_service_->ClearPref(user_policy);
    }
  }

  const raw_ptr<PrefService> policy_pref_service_;

  // Watch the changes of the variations prefs.
  std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;

  base::WeakPtrFactory<DeviceVariationsRestrictionByPolicyApplicator>
      weak_ptr_factory_{this};
};
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

VariationsService::VariationsService(
    std::unique_ptr<VariationsServiceClient> client,
    std::unique_ptr<web_resource::ResourceRequestAllowedNotifier> notifier,
    PrefService* local_state,
    metrics::MetricsStateManager* state_manager,
    const UIStringOverrider& ui_string_overrider,
    SyntheticTrialRegistry* synthetic_trial_registry)
    :{}

VariationsService::~VariationsService() = default;

void VariationsService::PerformPreMainMessageLoopStartup() {}

std::string VariationsService::LoadPermanentConsistencyCountry(
    const base::Version& version,
    const std::string& latest_country) {}

bool VariationsService::EncryptString(const std::string& plaintext,
                                      std::string* encrypted) {}

void VariationsService::AddObserver(Observer* observer) {}

void VariationsService::RemoveObserver(Observer* observer) {}

void VariationsService::OnAppEnterForeground() {}

void VariationsService::SetRestrictMode(const std::string& restrict_mode) {}

bool VariationsService::IsLikelyDogfoodClient() const {}

void VariationsService::SetIsLikelyDogfoodClientForTesting(
    bool is_dogfood_client) {}

GURL VariationsService::GetVariationsServerURL(HttpOptions http_options) {}

void VariationsService::EnsureLocaleEquals(const std::string& locale) {}

// static
std::string VariationsService::GetDefaultVariationsServerURLForTesting() {}

// static
void VariationsService::RegisterPrefs(PrefRegistrySimple* registry) {}

// static
void VariationsService::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* registry) {}

// static
std::unique_ptr<VariationsService> VariationsService::Create(
    std::unique_ptr<VariationsServiceClient> client,
    PrefService* local_state,
    metrics::MetricsStateManager* state_manager,
    const char* disable_network_switch,
    const UIStringOverrider& ui_string_overrider,
    web_resource::ResourceRequestAllowedNotifier::NetworkConnectionTrackerGetter
        network_connection_tracker_getter,
    SyntheticTrialRegistry* synthetic_trial_registry) {}

// static
void VariationsService::EnableFetchForTesting() {}

void VariationsService::DoActualFetch() {}

const std::string& VariationsService::GetLatestSerialNumber() {}

bool VariationsService::DoFetchFromURL(const GURL& url, bool is_http_retry) {}

void VariationsService::StoreSeed(std::string seed_data,
                                  std::string seed_signature,
                                  std::string country_code,
                                  base::Time date_fetched,
                                  bool is_delta_compressed,
                                  bool is_gzip_compressed) {}

void VariationsService::OnSeedStoreResult(bool is_delta_compressed,
                                          bool store_success,
                                          VariationsSeed seed) {}

void VariationsService::InitResourceRequestedAllowedNotifier() {}

void VariationsService::StartRepeatedVariationsSeedFetch() {}

void VariationsService::FetchVariationsSeed() {}

void VariationsService::NotifyObservers(const SeedSimulationResult& result) {}

void VariationsService::OnSimpleLoaderComplete(
    std::unique_ptr<std::string> response_body) {}

bool VariationsService::MaybeRetryOverHTTP() {}

void VariationsService::OnResourceRequestsAllowed() {}

void VariationsService::PerformSimulationWithVersion(
    const VariationsSeed& seed,
    const base::Version& version) {}

bool VariationsService::CallMaybeRetryOverHTTPForTesting() {}

void VariationsService::RecordSuccessfulFetch() {}

std::unique_ptr<ClientFilterableState>
VariationsService::GetClientFilterableStateForVersion() {}

std::string VariationsService::GetLatestCountry() const {}

bool VariationsService::SetUpFieldTrials(
    const std::vector<std::string>& variation_ids,
    const std::string& command_line_variation_ids,
    const std::vector<base::FeatureList::FeatureOverrideInfo>& extra_overrides,
    std::unique_ptr<base::FeatureList> feature_list,
    PlatformFieldTrials* platform_field_trials) {}

std::vector<StudyGroupNames> VariationsService::GetStudiesAvailableToForce() {}

SeedType VariationsService::GetSeedType() const {}

void VariationsService::OverrideCachedUIStrings() {}

void VariationsService::CancelCurrentRequestForTesting() {}

void VariationsService::StartRepeatedVariationsSeedFetchForTesting() {}

void VariationsService::OverridePlatform(
    Study::Platform platform,
    const std::string& osname_server_param_override) {}

std::string VariationsService::GetOverriddenPermanentCountry() const {}

std::string VariationsService::GetStoredPermanentCountry() const {}

bool VariationsService::OverrideStoredPermanentCountry(
    const std::string& country_override) {}

}  // namespace variations