blob: e9d423ae08ed63a21ba85385c6d78b9eca409761 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/network_service.h"
#include <map>
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial_params.h"
#include "base/task_scheduler/post_task.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/certificate_transparency/sth_distributor.h"
#include "components/certificate_transparency/sth_observer.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/base/logging_network_change_observer.h"
#include "net/base/network_change_notifier.h"
#include "net/cert/ct_log_response_parser.h"
#include "net/cert/signed_tree_head.h"
#include "net/dns/host_resolver.h"
#include "net/dns/mapped_host_resolver.h"
#include "net/log/net_log.h"
#include "net/log/net_log_util.h"
#include "net/nqe/network_quality_estimator.h"
#include "net/nqe/network_quality_estimator_params.h"
#include "net/url_request/url_request_context_builder.h"
#include "services/network/mojo_net_log.h"
#include "services/network/network_context.h"
#include "services/network/network_usage_accumulator.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/network/url_request_context_builder_mojo.h"
namespace network {
namespace {
// Field trial for network quality estimator. Seeds RTT and downstream
// throughput observations with values that correspond to the connection type
// determined by the operating system.
const char kNetworkQualityEstimatorFieldTrialName[] = "NetworkQualityEstimator";
std::unique_ptr<net::NetworkChangeNotifier>
CreateNetworkChangeNotifierIfNeeded() {
// There is a global singleton net::NetworkChangeNotifier if NetworkService
// is running inside of the browser process.
if (!net::NetworkChangeNotifier::HasNetworkChangeNotifier()) {
#if defined(OS_ANDROID)
// On Android, NetworkChangeNotifier objects are always set up in process
// before NetworkService is run.
return nullptr;
#elif defined(OS_CHROMEOS) || defined(OS_IOS) || defined(OS_FUCHSIA)
// ChromeOS has its own implementation of NetworkChangeNotifier that lives
// outside of //net. iOS doesn't embed //content. Fuchsia doesn't have an
// implementation yet.
// TODO(xunjieli): Figure out what to do for these 3 platforms.
NOTIMPLEMENTED();
return nullptr;
#endif
return base::WrapUnique(net::NetworkChangeNotifier::Create());
}
return nullptr;
}
std::unique_ptr<net::HostResolver> CreateHostResolver() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
if (!command_line.HasSwitch(network::switches::kHostResolverRules))
return nullptr;
std::unique_ptr<net::HostResolver> host_resolver(
net::HostResolver::CreateDefaultResolver(nullptr));
std::unique_ptr<net::MappedHostResolver> remapped_host_resolver(
new net::MappedHostResolver(std::move(host_resolver)));
remapped_host_resolver->SetRulesFromString(
command_line.GetSwitchValueASCII(switches::kHostResolverRules));
return std::move(remapped_host_resolver);
}
} // namespace
NetworkService::NetworkService(
std::unique_ptr<service_manager::BinderRegistry> registry,
mojom::NetworkServiceRequest request,
net::NetLog* net_log)
: registry_(std::move(registry)), binding_(this) {
// |registry_| is nullptr when an in-process NetworkService is
// created directly. The latter is done in concert with using
// CreateNetworkContextWithBuilder to ease the transition to using the
// network service.
if (registry_) {
DCHECK(!request.is_pending());
registry_->AddInterface<mojom::NetworkService>(
base::BindRepeating(&NetworkService::Bind, base::Unretained(this)));
} else if (request.is_pending()) {
Bind(std::move(request));
}
network_change_manager_ = std::make_unique<NetworkChangeManager>(
CreateNetworkChangeNotifierIfNeeded());
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (net_log) {
net_log_ = net_log;
} else {
owned_net_log_ = std::make_unique<MojoNetLog>();
// Note: The command line switches are only checked when not using the
// embedder's NetLog, as it may already be writing to the destination log
// file.
owned_net_log_->ProcessCommandLine(*command_line);
net_log_ = owned_net_log_.get();
}
// Add an observer that will emit network change events to the ChromeNetLog.
// Assuming NetworkChangeNotifier dispatches in FIFO order, we should be
// logging the network change before other IO thread consumers respond to it.
network_change_observer_.reset(
new net::LoggingNetworkChangeObserver(net_log_));
std::map<std::string, std::string> network_quality_estimator_params;
base::GetFieldTrialParams(kNetworkQualityEstimatorFieldTrialName,
&network_quality_estimator_params);
if (command_line->HasSwitch(switches::kForceEffectiveConnectionType)) {
const std::string force_ect_value = command_line->GetSwitchValueASCII(
switches::kForceEffectiveConnectionType);
if (!force_ect_value.empty()) {
// If the effective connection type is forced using command line switch,
// it overrides the one set by field trial.
network_quality_estimator_params[net::kForceEffectiveConnectionType] =
force_ect_value;
}
}
// Pass ownership.
network_quality_estimator_ = std::make_unique<net::NetworkQualityEstimator>(
std::make_unique<net::NetworkQualityEstimatorParams>(
network_quality_estimator_params),
net_log_);
#if defined(OS_CHROMEOS)
// Set a task runner for the get network id call for NetworkQualityEstimator
// to workaround https://crbug.com/821607 where AddressTrackerLinux stucks
// with a recv() call and blocks IO thread. Using SingleThreadTaskRunner so
// that task scheduler does not create too many worker threads when the
// problem happens.
// TODO(https://crbug.com/821607): Remove after the bug is resolved.
network_quality_estimator_->set_get_network_id_task_runner(
base::CreateSingleThreadTaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}));
#endif
host_resolver_ = CreateHostResolver();
network_usage_accumulator_ = std::make_unique<NetworkUsageAccumulator>();
sth_distributor_ =
std::make_unique<certificate_transparency::STHDistributor>();
}
NetworkService::~NetworkService() {
// Destroy owned network contexts.
owned_network_contexts_.clear();
// All NetworkContexts (Owned and unowned) must have been deleted by this
// point.
DCHECK(network_contexts_.empty());
}
std::unique_ptr<NetworkService> NetworkService::Create(
mojom::NetworkServiceRequest request,
net::NetLog* net_log) {
return std::make_unique<NetworkService>(nullptr, std::move(request), net_log);
}
std::unique_ptr<mojom::NetworkContext>
NetworkService::CreateNetworkContextWithBuilder(
mojom::NetworkContextRequest request,
mojom::NetworkContextParamsPtr params,
std::unique_ptr<URLRequestContextBuilderMojo> builder,
net::URLRequestContext** url_request_context) {
std::unique_ptr<NetworkContext> network_context =
std::make_unique<NetworkContext>(this, std::move(request),
std::move(params), std::move(builder));
*url_request_context = network_context->url_request_context();
return network_context;
}
std::unique_ptr<NetworkService> NetworkService::CreateForTesting() {
return base::WrapUnique(
new NetworkService(std::make_unique<service_manager::BinderRegistry>()));
}
void NetworkService::RegisterNetworkContext(NetworkContext* network_context) {
DCHECK_EQ(0u, network_contexts_.count(network_context));
network_contexts_.insert(network_context);
if (quic_disabled_)
network_context->DisableQuic();
}
void NetworkService::DeregisterNetworkContext(NetworkContext* network_context) {
DCHECK_EQ(1u, network_contexts_.count(network_context));
network_contexts_.erase(network_context);
}
void NetworkService::CreateNetLogEntriesForActiveObjects(
net::NetLog::ThreadSafeObserver* observer) {
std::set<net::URLRequestContext*> contexts;
for (NetworkContext* nc : network_contexts_)
contexts.insert(nc->url_request_context());
return net::CreateNetLogEntriesForActiveObjects(contexts, observer);
}
void NetworkService::SetClient(mojom::NetworkServiceClientPtr client) {
client_ = std::move(client);
}
void NetworkService::CreateNetworkContext(
mojom::NetworkContextRequest request,
mojom::NetworkContextParamsPtr params) {
owned_network_contexts_.emplace(std::make_unique<NetworkContext>(
this, std::move(request), std::move(params),
base::BindOnce(&NetworkService::OnNetworkContextConnectionClosed,
base::Unretained(this))));
}
void NetworkService::DisableQuic() {
quic_disabled_ = true;
for (auto* network_context : network_contexts_) {
network_context->DisableQuic();
}
}
void NetworkService::SetRawHeadersAccess(uint32_t process_id, bool allow) {
DCHECK(process_id);
if (allow)
processes_with_raw_headers_access_.insert(process_id);
else
processes_with_raw_headers_access_.erase(process_id);
}
bool NetworkService::HasRawHeadersAccess(uint32_t process_id) const {
// Allow raw headers for browser-initiated requests.
if (!process_id)
return true;
return processes_with_raw_headers_access_.find(process_id) !=
processes_with_raw_headers_access_.end();
}
net::NetLog* NetworkService::net_log() const {
return net_log_;
}
void NetworkService::GetNetworkChangeManager(
mojom::NetworkChangeManagerRequest request) {
network_change_manager_->AddRequest(std::move(request));
}
void NetworkService::GetTotalNetworkUsages(
mojom::NetworkService::GetTotalNetworkUsagesCallback callback) {
std::move(callback).Run(network_usage_accumulator_->GetTotalNetworkUsages());
}
void NetworkService::UpdateSignedTreeHead(const net::ct::SignedTreeHead& sth) {
sth_distributor_->NewSTHObserved(sth);
}
certificate_transparency::STHReporter* NetworkService::sth_reporter() {
return sth_distributor_.get();
}
void NetworkService::OnBindInterface(
const service_manager::BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
registry_->BindInterface(interface_name, std::move(interface_pipe));
}
void NetworkService::OnNetworkContextConnectionClosed(
NetworkContext* network_context) {
auto it = owned_network_contexts_.find(network_context);
DCHECK(it != owned_network_contexts_.end());
owned_network_contexts_.erase(it);
}
void NetworkService::Bind(mojom::NetworkServiceRequest request) {
DCHECK(!binding_.is_bound());
binding_.Bind(std::move(request));
}
} // namespace network