910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/public/test/setup_field_trials.h"

#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "cc/base/switches.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics/metrics_state_manager.h"
#include "components/metrics/test/test_enabled_state_provider.h"
#include "components/prefs/in_memory_pref_store.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/pref_service_factory.h"
#include "components/variations/platform_field_trials.h"
#include "components/variations/pref_names.h"
#include "components/variations/scoped_variations_ids_provider.h"
#include "components/variations/service/safe_seed_manager.h"
#include "components/variations/service/variations_field_trial_creator.h"
#include "components/variations/service/variations_service.h"
#include "components/variations/service/variations_service_client.h"
#include "components/variations/variations_ids_provider.h"
#include "components/variations/variations_safe_seed_store_local_state.h"
#include "components/variations/variations_switches.h"
#include "content/public/common/content_switch_dependent_feature_overrides.h"

#if BUILDFLAG(IS_ANDROID)
#include "components/variations/android/variations_seed_bridge.h"
#endif

namespace content {
namespace {

// TODO(crbug.com/40772375): Consider not needing VariationsServiceClient just
// to use VariationsFieldTrialCreator.
class VariationServiceClient : public variations::VariationsServiceClient {
 public:
  explicit VariationServiceClient(base::FilePath user_data_dir)
      : user_data_dir_(std::move(user_data_dir)) {}
  ~VariationServiceClient() override = default;
  VariationServiceClient(const VariationServiceClient&) = delete;
  VariationServiceClient(VariationServiceClient&&) = delete;
  VariationServiceClient& operator=(const VariationServiceClient&) = delete;
  VariationServiceClient& operator=(VariationServiceClient&&) = delete;

  // variations::VariationsServiceClient:
  base::Version GetVersionForSimulation() final { return base::Version(); }
  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() final {
    return nullptr;
  }
  network_time::NetworkTimeTracker* GetNetworkTimeTracker() final {
    return nullptr;
  }
  version_info::Channel GetChannel() final {
    return version_info::Channel::UNKNOWN;
  }
  bool OverridesRestrictParameter(std::string*) final { return false; }
  base::FilePath GetVariationsSeedFileDir() final { return user_data_dir_; }
  bool IsEnterprise() final { return false; }
  // Profiles aren't supported, so nothing to do here.
  void RemoveGoogleGroupsFromPrefsForDeletedProfiles(PrefService*) final {}

 private:
  base::FilePath user_data_dir_;
};

}  // namespace

// Note that several objects, created here, are scoped to the lifetime of this
// function. They are only needed to set up field trials. It replaces the
// global base::FeatureList instance, which is the only important part.
void SetupFieldTrials() {
  // The environment requires a ThreadPool to post tasks. Create one if
  // needed. It will be torn down at the end of this function, so that it
  // doesn't interfere with tests that need their own ThreadPool.
  const bool need_thread_pool = !base::ThreadPoolInstance::Get();
  if (need_thread_pool) {
    base::ThreadPoolInstance::Create("SetupFieldTrials");
  }

  base::ScopedTempDir user_data_dir;
  CHECK(user_data_dir.CreateUniqueTempDir());
  auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
  metrics::MetricsService::RegisterPrefs(pref_registry.get());
  variations::VariationsService::RegisterPrefs(pref_registry.get());

  PrefServiceFactory factory;
  factory.set_user_prefs(base::MakeRefCounted<InMemoryPrefStore>());
  std::unique_ptr<PrefService> pref_service = factory.Create(pref_registry);
  CHECK(pref_service);

  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();

  std::vector<base::FeatureList::FeatureOverrideInfo> feature_overrides =
      GetSwitchDependentFeatureOverrides(*command_line);

  // Needed so that content_shell can use fieldtrial_testing_config.
  metrics::TestEnabledStateProvider enabled_state_provider(/*consent=*/false,
                                                           /*enabled=*/false);

  const bool force_benchmarking_mode =
      command_line->HasSwitch(switches::kEnableGpuBenchmarking);
  std::unique_ptr<metrics::MetricsStateManager> metrics_state_manager =
      metrics::MetricsStateManager::Create(
          pref_service.get(), &enabled_state_provider, std::wstring(),
          user_data_dir.GetPath(), metrics::StartupVisibility::kUnknown,
          {
              .force_benchmarking_mode = force_benchmarking_mode,
          });
  CHECK(metrics_state_manager);
  metrics_state_manager->InstantiateFieldTrialList();

  std::unique_ptr<variations::SeedResponse> initial_seed;
#if BUILDFLAG(IS_ANDROID)
  if (!pref_service.get()->HasPrefPath(
          variations::prefs::kVariationsSeedSignature)) {
    DVLOG(1) << "Importing first run seed from Java preferences.";
    initial_seed = variations::android::GetVariationsFirstRunSeed();
  }
#endif

  VariationServiceClient variations_service_client(user_data_dir.GetPath());
  variations::VariationsFieldTrialCreator field_trial_creator(
      &variations_service_client,
      std::make_unique<variations::VariationsSeedStore>(
          pref_service.get(), std::move(initial_seed),
          /*signature_verification_enabled=*/true,
          std::make_unique<variations::VariationsSafeSeedStoreLocalState>(
              pref_service.get(),
              variations_service_client.GetVariationsSeedFileDir(),
              variations_service_client.GetChannelForVariations(),
              /*entropy_providers=*/nullptr),
          variations_service_client.GetChannelForVariations(),
          variations_service_client.GetVariationsSeedFileDir()),
      variations::UIStringOverrider());

  variations::SafeSeedManager safe_seed_manager(pref_service.get());

  const std::vector<std::string> variation_ids;  // Empty for tests.
  const std::string command_line_variation_ids =
      command_line->GetSwitchValueASCII(
          variations::switches::kForceVariationIds);
  auto feature_list = std::make_unique<base::FeatureList>();

  variations::test::ScopedVariationsIdsProvider scoped_ids_provider(
      variations::VariationsIdsProvider::Mode::kUseSignedInState);

  variations::PlatformFieldTrials platform_field_trials;

  // Since this is a test-only code path, some arguments to SetUpFieldTrials are
  // not needed, and thus are set to null or empty values.
  // TODO(crbug.com/40790318): Consider passing a low entropy source.
  field_trial_creator.SetUpFieldTrials(
      variation_ids, command_line_variation_ids, feature_overrides,
      std::move(feature_list), metrics_state_manager.get(),
      &platform_field_trials, &safe_seed_manager,
      /*add_entropy_source_to_variations_ids=*/false,
      *metrics_state_manager->CreateEntropyProviders(
          /*enable_limited_entropy_mode=*/false));

  // Tear down the temporary ThreadPool, so that it doesn't interfere with
  // tests that needs their own ThreadPool.
  if (need_thread_pool) {
    // Note that `Start(..)` is needed, because one can't shutdown a thread pool
    // that hasn't been started. `Start(...)` accesses the feature flags, so
    // it can't be called before `SetUpFieldTrials()`.
    base::ThreadPoolInstance::Get()->Start({/*num_threads=*/1});

    base::ThreadPoolInstance::Get()->Shutdown();
    base::ThreadPoolInstance::Get()->JoinForTesting();
    base::ThreadPoolInstance::Set(nullptr);
  }
}

}  // namespace content