// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/aw_feature_list_creator.h"
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "android_webview/browser/aw_browser_context.h"
#include "android_webview/browser/aw_browser_context_store.h"
#include "android_webview/browser/aw_browser_process.h"
#include "android_webview/browser/aw_feature_entries.h"
#include "android_webview/browser/aw_metrics_service_client_delegate.h"
#include "android_webview/browser/metrics/android_metrics_provider.h"
#include "android_webview/browser/metrics/aw_metrics_service_client.h"
#include "android_webview/browser/supervised_user/aw_supervised_user_url_classifier.h"
#include "android_webview/browser/tracing/aw_tracing_delegate.h"
#include "android_webview/browser/variations/variations_seed_loader.h"
#include "android_webview/common/aw_switches.h"
#include "android_webview/proto/aw_variations_seed.pb.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/metrics/field_trial.h"
#include "base/path_service.h"
#include "base/strings/string_split.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/embedder_support/android/metrics/android_metrics_service_client.h"
#include "components/embedder_support/origin_trials/origin_trial_prefs.h"
#include "components/embedder_support/origin_trials/pref_names.h"
#include "components/metrics/android_metrics_helper.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/persistent_histograms.h"
#include "components/policy/core/browser/configuration_policy_pref_store.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/in_memory_pref_store.h"
#include "components/prefs/json_pref_store.h"
#include "components/prefs/pref_name_set.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/pref_service_factory.h"
#include "components/prefs/segregated_pref_store.h"
#include "components/tracing/common/pref_names.h"
#include "components/variations/entropy_provider.h"
#include "components/variations/pref_names.h"
#include "components/variations/service/safe_seed_manager.h"
#include "components/variations/service/variations_service.h"
#include "components/variations/synthetic_trial_registry.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"
#include "net/base/features.h"
#include "net/nqe/pref_names.h"
namespace android_webview {
namespace {
bool g_signature_verification_enabled = true;
// These prefs go in the JsonPrefStore, and will persist across runs. Other
// prefs go in the InMemoryPrefStore, and will be lost when the process ends.
const char* const kPersistentPrefsAllowlist[] = {
// Restricted content blocking.
android_webview::prefs::kShouldBlockRestrictedContent,
// Origin Trial config overrides.
embedder_support::prefs::kOriginTrialPublicKey,
embedder_support::prefs::kOriginTrialDisabledFeatures,
embedder_support::prefs::kOriginTrialDisabledTokens,
// Randomly-generated GUID which pseudonymously identifies uploaded metrics.
metrics::prefs::kMetricsClientID,
// Random seed value for variation's entropy providers. Used to assign
// experiment groups.
metrics::prefs::kMetricsLowEntropySource,
// File metrics metadata.
metrics::prefs::kMetricsFileMetricsMetadata,
// Logged directly in the ChromeUserMetricsExtension proto.
metrics::prefs::kInstallDate,
metrics::prefs::kMetricsReportingEnabledTimestamp,
metrics::prefs::kMetricsSessionID,
// Logged in system_profile.stability fields.
metrics::prefs::kStabilityFileMetricsUnsentFilesCount,
metrics::prefs::kStabilityFileMetricsUnsentSamplesCount,
metrics::prefs::kStabilityLaunchCount,
metrics::prefs::kStabilityPageLoadCount,
metrics::prefs::kStabilityRendererLaunchCount,
// Unsent logs.
metrics::prefs::kMetricsInitialLogs,
metrics::prefs::kMetricsOngoingLogs,
// Unsent logs metadata.
metrics::prefs::kMetricsInitialLogsMetadata,
metrics::prefs::kMetricsOngoingLogsMetadata,
net::nqe::kNetworkQualities,
// Current and past country codes, to filter variations studies by country.
variations::prefs::kVariationsCountry,
variations::prefs::kVariationsPermanentConsistencyCountry,
// Last variations seed fetch date/time, used for histograms and to
// determine if the seed is expired.
variations::prefs::kVariationsLastFetchTime,
variations::prefs::kVariationsSeedDate,
// The state of the previous background tracing session.
tracing::kBackgroundTracingSessionState,
// System-level info.
metrics::prefs::kVersionCodePref,
prefs::kPrimaryCpuAbiBitnessPref,
// Records about profiles/contexts and their stored data
prefs::kProfileListPref,
prefs::kProfileCounterPref,
};
void HandleReadError(PersistentPrefStore::PrefReadError error) {}
base::FilePath GetPrefStorePath() {
base::FilePath path;
base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path);
path = path.Append(FILE_PATH_LITERAL("pref_store"));
return path;
}
// Adds WebView-specific switch-dependent feature overrides on top of the ones
// from the content layer.
std::vector<base::FeatureList::FeatureOverrideInfo>
GetSwitchDependentFeatureOverrides(const base::CommandLine& command_line) {
std::vector<base::FeatureList::FeatureOverrideInfo> feature_overrides =
content::GetSwitchDependentFeatureOverrides(command_line);
return feature_overrides;
}
} // namespace
AwFeatureListCreator::AwFeatureListCreator()
: aw_field_trials_(std::make_unique<AwFieldTrials>()) {}
AwFeatureListCreator::~AwFeatureListCreator() {}
void AwFeatureListCreator::CreateFeatureListAndFieldTrials() {
TRACE_EVENT0("startup",
"AwFeatureListCreator::CreateFeatureListAndFieldTrials");
CreateLocalState();
AwMetricsServiceClient::SetInstance(std::make_unique<AwMetricsServiceClient>(
std::make_unique<AwMetricsServiceClientDelegate>()));
AwMetricsServiceClient::GetInstance()->Initialize(local_state_.get());
SetUpFieldTrials();
}
void AwFeatureListCreator::CreateLocalState() {
browser_policy_connector_ = std::make_unique<AwBrowserPolicyConnector>();
local_state_ = CreatePrefService();
}
void AwFeatureListCreator::DisableSignatureVerificationForTesting() {
g_signature_verification_enabled = false;
}
std::unique_ptr<PrefService> AwFeatureListCreator::CreatePrefService() {
auto pref_registry = base::MakeRefCounted<user_prefs::PrefRegistrySyncable>();
AwMetricsServiceClient::RegisterMetricsPrefs(pref_registry.get());
variations::VariationsService::RegisterPrefs(pref_registry.get());
embedder_support::OriginTrialPrefs::RegisterPrefs(pref_registry.get());
AwBrowserProcess::RegisterNetworkContextLocalStatePrefs(pref_registry.get());
AwBrowserProcess::RegisterEnterpriseAuthenticationAppLinkPolicyPref(
pref_registry.get());
AwTracingDelegate::RegisterPrefs(pref_registry.get());
AwBrowserContextStore::RegisterPrefs(pref_registry.get());
AwSupervisedUserUrlClassifier::RegisterPrefs(pref_registry.get());
PrefServiceFactory pref_service_factory;
PrefNameSet persistent_prefs;
for (const char* const pref_name : kPersistentPrefsAllowlist)
persistent_prefs.insert(pref_name);
persistent_prefs.insert(std::string(metrics::prefs::kMetricsLastSeenPrefix) +
kBrowserMetricsName);
persistent_prefs.insert(std::string(metrics::prefs::kMetricsLastSeenPrefix) +
metrics::kCrashpadHistogramAllocatorName);
// SegregatedPrefStore may be validated with a MAC (message authentication
// code). On Android, the store is protected by app sandboxing, so validation
// is unnnecessary. Thus validation_delegate is null.
pref_service_factory.set_user_prefs(base::MakeRefCounted<SegregatedPrefStore>(
base::MakeRefCounted<InMemoryPrefStore>(),
base::MakeRefCounted<JsonPrefStore>(GetPrefStorePath()),
std::move(persistent_prefs)));
pref_service_factory.set_managed_prefs(
base::MakeRefCounted<policy::ConfigurationPolicyPrefStore>(
browser_policy_connector_.get(),
browser_policy_connector_->GetPolicyService(),
browser_policy_connector_->GetHandlerList(),
policy::POLICY_LEVEL_MANDATORY));
pref_service_factory.set_read_error_callback(
base::BindRepeating(&HandleReadError));
return pref_service_factory.Create(pref_registry);
}
void AwFeatureListCreator::SetUpFieldTrials() {
// The FieldTrialList should have been instantiated in
// AndroidMetricsServiceClient::Initialize().
DCHECK(base::FieldTrialList::GetInstance());
// Convert the AwVariationsSeed proto to a SeedResponse object.
std::unique_ptr<AwVariationsSeed> seed_proto = TakeSeed();
std::unique_ptr<variations::SeedResponse> seed;
base::Time seed_date; // Initializes to null time.
if (seed_proto) {
// We set the seed fetch time to when the service downloaded the seed rather
// than base::Time::Now() because we want to compute seed freshness based on
// the initial download time, which happened in the service at some earlier
// point.
seed_date = base::Time::FromMillisecondsSinceUnixEpoch(seed_proto->date());
seed = std::make_unique<variations::SeedResponse>();
seed->data = seed_proto->seed_data();
seed->signature = seed_proto->signature();
seed->country = seed_proto->country();
seed->date = seed_date;
seed->is_gzip_compressed = seed_proto->is_gzip_compressed();
}
client_ = std::make_unique<AwVariationsServiceClient>();
auto seed_store = std::make_unique<variations::VariationsSeedStore>(
local_state_.get(), /*initial_seed=*/std::move(seed),
/*signature_verification_enabled=*/g_signature_verification_enabled,
std::make_unique<variations::VariationsSafeSeedStoreLocalState>(
local_state_.get()),
/*use_first_run_prefs=*/false);
if (!seed_date.is_null())
seed_store->RecordLastFetchTime(seed_date);
variations::UIStringOverrider ui_string_overrider;
variations_field_trial_creator_ =
std::make_unique<variations::VariationsFieldTrialCreator>(
client_.get(), std::move(seed_store), ui_string_overrider,
// Limited entropy field trials are not supported on WebView.
/*limited_entropy_synthetic_trial=*/nullptr);
variations_field_trial_creator_->OverrideVariationsPlatform(
variations::Study::PLATFORM_ANDROID_WEBVIEW);
// Safe Mode is a feature which reverts to a previous variations seed if the
// current one is suspected to be causing crashes, or preventing new seeds
// from being downloaded. It's not implemented for WebView because 1) it's
// difficult for WebView to implement Safe Mode's crash detection, and 2)
// downloading and disseminating seeds is handled by the WebView service,
// which itself doesn't support variations; therefore a bad seed shouldn't be
// able to break seed downloads. See https://crbug.com/801771 for more info.
variations::SafeSeedManager ignored_safe_seed_manager(local_state_.get());
base::Time fetchTime =
variations_field_trial_creator_->CalculateSeedFreshness();
long seedFreshnessMinutes = (base::Time::Now() - fetchTime).InMinutes();
CacheSeedFreshness(seedFreshnessMinutes);
auto feature_list = std::make_unique<base::FeatureList>();
std::vector<std::string> variation_ids =
aw_feature_entries::RegisterEnabledFeatureEntries(feature_list.get());
auto* metrics_client = AwMetricsServiceClient::GetInstance();
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
// Populate FieldTrialList.
// If you update this, consider whether "WebViewEnvironment" in
// components/variations/variations_seed_processor_unittest.cc needs updates.
// TODO(b/263797385): Re-evaluate if we can add entropy source id to
// variations ids for WebView or not.
variations_field_trial_creator_->SetUpFieldTrials(
variation_ids,
command_line->GetSwitchValueASCII(
variations::switches::kForceVariationIds),
GetSwitchDependentFeatureOverrides(*command_line),
std::move(feature_list), metrics_client->metrics_state_manager(),
metrics_client->GetSyntheticTrialRegistry(), aw_field_trials_.get(),
&ignored_safe_seed_manager,
/*add_entropy_source_to_variations_ids=*/false);
}
} // namespace android_webview