diff options
Diffstat (limited to 'chromium/services')
24 files changed, 481 insertions, 118 deletions
diff --git a/chromium/services/media_session/audio_focus_manager.cc b/chromium/services/media_session/audio_focus_manager.cc index e6b952fd4ab..a1eeb647078 100644 --- a/chromium/services/media_session/audio_focus_manager.cc +++ b/chromium/services/media_session/audio_focus_manager.cc @@ -98,7 +98,17 @@ class AudioFocusManager::StackRow : public mojom::AudioFocusRequestClient { } void MediaSessionInfoChanged(mojom::MediaSessionInfoPtr info) override { + bool suspended_change = + (info->state == mojom::MediaSessionInfo::SessionState::kSuspended || + IsSuspended()) && + info->state != session_info_->state; + SetSessionInfo(std::move(info)); + + // If we have transitioned to/from a suspended state then we should + // re-enforce audio focus. + if (suspended_change) + owner_->EnforceAudioFocus(); } void GetRequestId(GetRequestIdCallback callback) override { @@ -118,6 +128,11 @@ class AudioFocusManager::StackRow : public mojom::AudioFocusRequestClient { mojom::MediaSessionInfo::SessionState::kActive; } + bool IsSuspended() const { + return session_info_->state == + mojom::MediaSessionInfo::SessionState::kSuspended; + } + RequestId id() const { return id_; } const std::string& source_name() const { return source_name_; } @@ -301,7 +316,7 @@ void AudioFocusManager::AbandonAudioFocusInternal(RequestId id) { return; } - EnforceAudioFocusAbandon(); + EnforceAudioFocus(); MaybeUpdateActiveSession(); // Notify observers that we lost audio focus. @@ -400,27 +415,6 @@ void AudioFocusManager::RequestAudioFocusInternal( std::move(callback).Run(); } -void AudioFocusManager::EnforceAudioFocusAbandon() { - // Allow the top-most MediaSession having force duck to unduck even if - // it is not active. - if (enforcement_mode_ != mojom::EnforcementMode::kNone) { - for (auto iter = audio_focus_stack_.rbegin(); - iter != audio_focus_stack_.rend(); ++iter) { - if (!(*iter)->info()->force_duck) - continue; - - // TODO(beccahughes): Replace with std::rotate. - auto duck_row = std::move(*iter); - duck_row->session()->StopDucking(); - audio_focus_stack_.erase(std::next(iter).base()); - audio_focus_stack_.push_back(std::move(duck_row)); - return; - } - } - - EnforceAudioFocus(); -} - void AudioFocusManager::EnforceAudioFocus() { DCHECK_NE(mojom::EnforcementMode::kDefault, enforcement_mode_); if (audio_focus_stack_.empty()) @@ -431,16 +425,20 @@ void AudioFocusManager::EnforceAudioFocus() { for (auto& session : base::Reversed(audio_focus_stack_)) { EnforceSingleSession(session.get(), state); - // Update the flags based on the audio focus type of this session. + // Update the flags based on the audio focus type of this session. If the + // session is suspended then any transient audio focus type should not have + // an effect. switch (session->audio_focus_type()) { case mojom::AudioFocusType::kGain: state.should_stop = true; break; case mojom::AudioFocusType::kGainTransient: - state.should_suspend = true; + if (!session->IsSuspended()) + state.should_suspend = true; break; case mojom::AudioFocusType::kGainTransientMayDuck: - state.should_duck = true; + if (!session->IsSuspended()) + state.should_duck = true; break; } } diff --git a/chromium/services/media_session/audio_focus_manager.h b/chromium/services/media_session/audio_focus_manager.h index 50d72f6ad7f..fb71e664f97 100644 --- a/chromium/services/media_session/audio_focus_manager.h +++ b/chromium/services/media_session/audio_focus_manager.h @@ -107,7 +107,6 @@ class AudioFocusManager : public mojom::AudioFocusManager, base::OnceCallback<void()>); void AbandonAudioFocusInternal(RequestId); - void EnforceAudioFocusAbandon(); void EnforceAudioFocus(); void MaybeUpdateActiveSession(); diff --git a/chromium/services/media_session/audio_focus_manager_unittest.cc b/chromium/services/media_session/audio_focus_manager_unittest.cc index c8b9b49eb8d..de29923817e 100644 --- a/chromium/services/media_session/audio_focus_manager_unittest.cc +++ b/chromium/services/media_session/audio_focus_manager_unittest.cc @@ -122,9 +122,8 @@ class AudioFocusManagerTest mojom::MediaSessionInfo::SessionState state = session->GetState(); if (!IsEnforcementEnabled()) { - // If audio focus enforcement is disabled then we should never see these - // states in the tests. - EXPECT_NE(mojom::MediaSessionInfo::SessionState::kSuspended, state); + // If audio focus enforcement is disabled then we should never see ducking + // in the tests. EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, state); } @@ -676,8 +675,7 @@ TEST_P(AudioFocusManagerTest, GainDucksForceDuck) { GetState(&media_session_1)); } -TEST_P(AudioFocusManagerTest, - AbandoningGainFocusRevokesTopMostForceDuckSession) { +TEST_P(AudioFocusManagerTest, ForceDuckSessionShouldAlwaysBeDuckedFromGain) { test::MockMediaSession media_session_1(true /* force_duck */); test::MockMediaSession media_session_2; test::MockMediaSession media_session_3; @@ -698,8 +696,34 @@ TEST_P(AudioFocusManagerTest, GetState(&media_session_1)); media_session_3.AbandonAudioFocusFromClient(); - EXPECT_EQ(IsEnforcementEnabled() ? request_id_1 : request_id_2, - GetAudioFocusedSession()); + EXPECT_EQ(request_id_2, GetAudioFocusedSession()); + EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), + GetState(&media_session_1)); + + media_session_2.AbandonAudioFocusFromClient(); + EXPECT_EQ(request_id_1, GetAudioFocusedSession()); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + GetState(&media_session_1)); +} + +TEST_P(AudioFocusManagerTest, + ForceDuckSessionShouldAlwaysBeDuckedFromTransient) { + test::MockMediaSession media_session_1(true /* force_duck */); + test::MockMediaSession media_session_2; + + AudioFocusManager::RequestId request_id_1 = + RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); + RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient); + + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + GetState(&media_session_2)); + EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), + GetState(&media_session_1)); + + media_session_2.AbandonAudioFocusFromClient(); + EXPECT_EQ(request_id_1, GetAudioFocusedSession()); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + GetState(&media_session_1)); } TEST_P(AudioFocusManagerTest, AudioFocusObserver_RequestNoop) { @@ -1061,7 +1085,7 @@ TEST_P(AudioFocusManagerTest, ObserverActiveSessionChanged) { } } -TEST_P(AudioFocusManagerTest, AudioFocusGrouping_AllowDucking) { +TEST_P(AudioFocusManagerTest, AudioFocusGrouping_LayeredFocus) { test::MockMediaSession media_session_1; test::MockMediaSession media_session_2; test::MockMediaSession media_session_3; @@ -1078,11 +1102,20 @@ TEST_P(AudioFocusManagerTest, AudioFocusGrouping_AllowDucking) { EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), GetState(&media_session_1)); - RequestGroupedAudioFocus(&media_session_3, mojom::AudioFocusType::kGain, - group_id); + // When we request audio focus for media_session_3 the group will take audio + // focus and we suspend the ducking session. + RequestGroupedAudioFocus(&media_session_3, + mojom::AudioFocusType::kGainTransient, group_id); EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, GetState(&media_session_3)); - EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), + + EXPECT_EQ( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), + GetState(&media_session_2)); + EXPECT_EQ(GetStateFromParam( + IsGroupingEnabled() + ? mojom::MediaSessionInfo::SessionState::kActive + : mojom::MediaSessionInfo::SessionState::kSuspended), GetState(&media_session_1)); } @@ -1234,4 +1267,218 @@ TEST_P(AudioFocusManagerTest, GetState(&media_session_1)); } +TEST_P(AudioFocusManagerTest, GainFocusTypeHasEffectEvenIfSuspended) { + test::MockMediaSession media_session_1; + test::MockMediaSession media_session_2; + test::MockMediaSession media_session_3; + + AudioFocusManager::RequestId request_id_1 = + RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); + EXPECT_EQ(request_id_1, GetAudioFocusedSession()); + + RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); + EXPECT_EQ( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), + GetState(&media_session_1)); + + // When the second session becomes suspended and that event originated from + // the session itself then we should keep the other session suspended. + media_session_2.Suspend(mojom::MediaSession::SuspendType::kUI); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kSuspended, + GetState(&media_session_2)); + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + // When the second session is resumed then we should still keep the other + // session suspended. + media_session_2.Resume(mojom::MediaSession::SuspendType::kUI); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + GetState(&media_session_2)); + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + // If a new session takes focus then this should suspend all sessions. + RequestAudioFocus(&media_session_3, mojom::AudioFocusType::kGainTransient); + + { + test::MockMediaSessionMojoObserver observer(media_session_2); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + // If the second session regains focus then it should suspend all sessions. + RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + GetState(&media_session_2)); + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + { + test::MockMediaSessionMojoObserver observer(media_session_3); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } +} + +TEST_P(AudioFocusManagerTest, TransientFocusTypeHasNoEffectIfSuspended) { + test::MockMediaSession media_session_1; + test::MockMediaSession media_session_2; + test::MockMediaSession media_session_3; + + AudioFocusManager::RequestId request_id_1 = + RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); + EXPECT_EQ(request_id_1, GetAudioFocusedSession()); + + RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient); + EXPECT_EQ( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), + GetState(&media_session_1)); + + // When the transient session becomes suspended and that event originates from + // the session itself then we should stop pausing the other session. + media_session_2.Suspend(mojom::MediaSession::SuspendType::kUI); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kSuspended, + GetState(&media_session_2)); + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); + } + + // When the transient session is resumed then we should pause the other + // session again. + media_session_2.Resume(mojom::MediaSession::SuspendType::kUI); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + GetState(&media_session_2)); + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + // If we have a new session take focus then this should suspend all the other + // sessions and the transient session should have no effect. + RequestAudioFocus(&media_session_3, mojom::AudioFocusType::kGainTransient); + + { + test::MockMediaSessionMojoObserver observer(media_session_2); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + // If the second session regains focus then it should start pausing again. + RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + GetState(&media_session_2)); + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + { + test::MockMediaSessionMojoObserver observer(media_session_3); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } +} + +TEST_P(AudioFocusManagerTest, TransientDuckFocusTypeHasNoEffectIfSuspended) { + test::MockMediaSession media_session_1; + test::MockMediaSession media_session_2; + test::MockMediaSession media_session_3; + + AudioFocusManager::RequestId request_id_1 = + RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); + EXPECT_EQ(request_id_1, GetAudioFocusedSession()); + + RequestAudioFocus(&media_session_2, + mojom::AudioFocusType::kGainTransientMayDuck); + EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), + GetState(&media_session_1)); + + // When the ducking session becomes suspended and that event originates from + // the session itself then we should stop ducking. + media_session_2.Suspend(mojom::MediaSession::SuspendType::kUI); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kSuspended, + GetState(&media_session_2)); + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); + } + + // When the ducking session is resumed then we should resume ducking. + media_session_2.Resume(mojom::MediaSession::SuspendType::kUI); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + GetState(&media_session_2)); + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking)); + } + + // If we have a new session take focus then this should suspend all the other + // sessions and we should not have any ducking from the ducking session (since + // it is suspended). + RequestAudioFocus(&media_session_3, mojom::AudioFocusType::kGainTransient); + + { + test::MockMediaSessionMojoObserver observer(media_session_2); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended)); + } + + // If the ducking session regains focus then it should start ducking again. + RequestAudioFocus(&media_session_2, + mojom::AudioFocusType::kGainTransientMayDuck); + EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + GetState(&media_session_2)); + + { + test::MockMediaSessionMojoObserver observer(media_session_1); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking)); + } + + { + test::MockMediaSessionMojoObserver observer(media_session_3); + observer.WaitForState( + GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking)); + } +} + } // namespace media_session diff --git a/chromium/services/network/network_change_manager.cc b/chromium/services/network/network_change_manager.cc index a1ed97863de..089bce06c6a 100644 --- a/chromium/services/network/network_change_manager.cc +++ b/chromium/services/network/network_change_manager.cc @@ -9,7 +9,7 @@ #include "base/logging.h" #include "net/base/network_change_notifier.h" -#include "net/base/network_change_notifier_chromeos.h" +#include "net/base/network_change_notifier_posix.h" namespace network { @@ -44,7 +44,7 @@ void NetworkChangeManager::RequestNotifications( clients_.push_back(std::move(client_ptr)); } -#if defined(OS_CHROMEOS) +#if defined(OS_CHROMEOS) || defined(OS_ANDROID) void NetworkChangeManager::OnNetworkChanged( bool dns_changed, bool ip_address_changed, @@ -53,8 +53,8 @@ void NetworkChangeManager::OnNetworkChanged( bool connection_subtype_changed, mojom::ConnectionSubtype new_connection_subtype) { DCHECK(network_change_notifier_); - net::NetworkChangeNotifierChromeos* notifier = - static_cast<net::NetworkChangeNotifierChromeos*>( + net::NetworkChangeNotifierPosix* notifier = + static_cast<net::NetworkChangeNotifierPosix*>( network_change_notifier_.get()); if (dns_changed) notifier->OnDNSChanged(); diff --git a/chromium/services/network/network_change_manager.h b/chromium/services/network/network_change_manager.h index 6dd4dc9feee..bf975f21e58 100644 --- a/chromium/services/network/network_change_manager.h +++ b/chromium/services/network/network_change_manager.h @@ -41,7 +41,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkChangeManager void RequestNotifications( mojom::NetworkChangeManagerClientPtr client_ptr) override; -#if defined(OS_CHROMEOS) +#if defined(OS_CHROMEOS) || defined(OS_ANDROID) void OnNetworkChanged( bool dns_changed, bool ip_address_changed, diff --git a/chromium/services/network/network_service.cc b/chromium/services/network/network_service.cc index fbe344a3dd8..ffa129c237e 100644 --- a/chromium/services/network/network_service.cc +++ b/chromium/services/network/network_service.cc @@ -22,6 +22,7 @@ #include "mojo/public/cpp/bindings/type_converter.h" #include "net/base/logging_network_change_observer.h" #include "net/base/network_change_notifier.h" +#include "net/base/network_change_notifier_posix.h" #include "net/base/port_util.h" #include "net/cert/cert_database.h" #include "net/cert/ct_log_response_parser.h" @@ -83,15 +84,17 @@ net::NetLog* GetNetLog() { constexpr auto kUpdateLoadStatesInterval = base::TimeDelta::FromMilliseconds(250); -std::unique_ptr<net::NetworkChangeNotifier> -CreateNetworkChangeNotifierIfNeeded() { +std::unique_ptr<net::NetworkChangeNotifier> CreateNetworkChangeNotifierIfNeeded( + net::NetworkChangeNotifier::ConnectionType initial_connection_type, + net::NetworkChangeNotifier::ConnectionSubtype initial_connection_subtype) { // 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; +#if defined(OS_ANDROID) || defined(OS_CHROMEOS) + // On Android and ChromeOS, network change events are synced from the + // browser process. + return std::make_unique<net::NetworkChangeNotifierPosix>( + initial_connection_type, initial_connection_subtype); #elif defined(OS_IOS) || defined(OS_FUCHSIA) // iOS doesn't embed //content. Fuchsia doesn't have an implementation yet. // TODO(xunjieli): Figure out what to do for these 2 platforms. @@ -208,7 +211,8 @@ NetworkService::NetworkService( std::unique_ptr<service_manager::BinderRegistry> registry, mojom::NetworkServiceRequest request, net::NetLog* net_log, - service_manager::mojom::ServiceRequest service_request) + service_manager::mojom::ServiceRequest service_request, + bool delay_initialization_until_set_client) : registry_(std::move(registry)), binding_(this) { DCHECK(!g_network_service); g_network_service = this; @@ -229,6 +233,22 @@ NetworkService::NetworkService( Bind(std::move(request)); } + if (net_log) { + net_log_ = net_log; + } else { + net_log_ = GetNetLog(); + } + + if (!delay_initialization_until_set_client) + Initialize(mojom::NetworkServiceParams::New()); +} + +void NetworkService::Initialize(mojom::NetworkServiceParamsPtr params) { + if (initialized_) + return; + + initialized_ = true; + #if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) // Make sure OpenSSL is initialized before using it to histogram data. crypto::EnsureOpenSSLInit(); @@ -257,13 +277,11 @@ NetworkService::NetworkService( command_line->HasSwitch(switches::kIgnoreCertificateErrorsSPKIList)); network_change_manager_ = std::make_unique<NetworkChangeManager>( - CreateNetworkChangeNotifierIfNeeded()); - - if (net_log) { - net_log_ = net_log; - } else { - net_log_ = GetNetLog(); - } + CreateNetworkChangeNotifierIfNeeded( + net::NetworkChangeNotifier::ConnectionType( + params->initial_connection_type), + net::NetworkChangeNotifier::ConnectionSubtype( + params->initial_connection_subtype))); trace_net_log_observer_.WatchForTraceStart(net_log_); @@ -380,8 +398,10 @@ void NetworkService::CreateNetLogEntriesForActiveObjects( return net::CreateNetLogEntriesForActiveObjects(contexts, observer); } -void NetworkService::SetClient(mojom::NetworkServiceClientPtr client) { +void NetworkService::SetClient(mojom::NetworkServiceClientPtr client, + mojom::NetworkServiceParamsPtr params) { client_ = std::move(client); + Initialize(std::move(params)); } void NetworkService::StartNetLog(base::File file, diff --git a/chromium/services/network/network_service.h b/chromium/services/network/network_service.h index 9e398323c2d..a04970001c2 100644 --- a/chromium/services/network/network_service.h +++ b/chromium/services/network/network_service.h @@ -76,7 +76,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService std::unique_ptr<service_manager::BinderRegistry> registry, mojom::NetworkServiceRequest request = nullptr, net::NetLog* net_log = nullptr, - service_manager::mojom::ServiceRequest service_request = nullptr); + service_manager::mojom::ServiceRequest service_request = nullptr, + bool delay_initialization_until_set_client = false); ~NetworkService() override; @@ -111,6 +112,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService // constructor. void Bind(mojom::NetworkServiceRequest request); + // Allows the browser process to synchronously initialize the NetworkService. + // TODO(jam): remove this once the old path is gone. + void Initialize(mojom::NetworkServiceParamsPtr params); + // Creates a NetworkService instance on the current thread, optionally using // the passed-in NetLog. Does not take ownership of |net_log|. Must be // destroyed before |net_log|. @@ -146,7 +151,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService net::NetLog::ThreadSafeObserver* observer); // mojom::NetworkService implementation: - void SetClient(mojom::NetworkServiceClientPtr client) override; + void SetClient(mojom::NetworkServiceClientPtr client, + mojom::NetworkServiceParamsPtr params) override; void StartNetLog(base::File file, mojom::NetLogCaptureMode capture_mode, base::Value constants) override; @@ -259,6 +265,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService service_manager::ServiceBinding service_binding_{this}; + bool initialized_ = false; + net::NetLog* net_log_ = nullptr; std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_; @@ -268,13 +276,14 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService KeepaliveStatisticsRecorder keepalive_statistics_recorder_; + std::unique_ptr<NetworkChangeManager> network_change_manager_; + // Observer that logs network changes to the NetLog. Must be below the NetLog // and the NetworkChangeNotifier (Once this class creates it), so it's - // destroyed before them. + // destroyed before them. Must be below the |network_change_manager_|, which + // it references. std::unique_ptr<net::LoggingNetworkChangeObserver> network_change_observer_; - std::unique_ptr<NetworkChangeManager> network_change_manager_; - std::unique_ptr<service_manager::BinderRegistry> registry_; mojo::Binding<mojom::NetworkService> binding_; diff --git a/chromium/services/network/network_service_unittest.cc b/chromium/services/network/network_service_unittest.cc index b61dd2c1c03..9d19c198aa9 100644 --- a/chromium/services/network/network_service_unittest.cc +++ b/chromium/services/network/network_service_unittest.cc @@ -1294,12 +1294,6 @@ class NetworkChangeTest : public testing::Test { private: base::test::ScopedTaskEnvironment scoped_task_environment_; -#if defined(OS_ANDROID) - // On Android, NetworkChangeNotifier setup is more involved and needs to - // to be split between UI thread and network thread. Use a mock - // NetworkChangeNotifier in tests, so the test setup is simpler. - net::test::MockNetworkChangeNotifier network_change_notifier_; -#endif std::unique_ptr<NetworkService> service_; }; @@ -1342,12 +1336,6 @@ class NetworkServiceNetworkChangeTest : public testing::Test { std::unique_ptr<NetworkService> service_; mojom::NetworkServicePtr network_service_; -#if defined(OS_ANDROID) - // On Android, NetworkChangeNotifier setup is more involved and needs - // to be split between UI thread and network thread. Use a mock - // NetworkChangeNotifier in tests, so the test setup is simpler. - net::test::MockNetworkChangeNotifier network_change_notifier_; -#endif DISALLOW_COPY_AND_ASSIGN(NetworkServiceNetworkChangeTest); }; @@ -1525,7 +1513,8 @@ TEST_F(NetworkServiceNetworkDelegateTest, ClearSiteDataNetworkServiceCient) { mojom::NetworkServiceClientPtr client_ptr; auto client_impl = std::make_unique<ClearSiteDataNetworkServiceClient>( mojo::MakeRequest(&client_ptr)); - service()->SetClient(std::move(client_ptr)); + service()->SetClient(std::move(client_ptr), + network::mojom::NetworkServiceParams::New()); url = https_server()->GetURL("/bar"); url = AddQuery(url, "header", kClearCookiesHeader); EXPECT_EQ(0, client_impl->on_clear_site_data_counter()); @@ -1543,7 +1532,8 @@ TEST_F(NetworkServiceNetworkDelegateTest, HandleClearSiteDataHeaders) { mojom::NetworkServiceClientPtr client_ptr; auto client_impl = std::make_unique<ClearSiteDataNetworkServiceClient>( mojo::MakeRequest(&client_ptr)); - service()->SetClient(std::move(client_ptr)); + service()->SetClient(std::move(client_ptr), + network::mojom::NetworkServiceParams::New()); // |passed_header_value| are only checked if |should_call_client| is true. const struct TestCase { diff --git a/chromium/services/network/proxy_config_service_mojo_unittest.cc b/chromium/services/network/proxy_config_service_mojo_unittest.cc index ed7b315df2f..207694c930c 100644 --- a/chromium/services/network/proxy_config_service_mojo_unittest.cc +++ b/chromium/services/network/proxy_config_service_mojo_unittest.cc @@ -62,26 +62,48 @@ class TestProxyConfigServiceObserver DISALLOW_COPY_AND_ASSIGN(TestProxyConfigServiceObserver); }; +// Test fixture for notifying ProxyConfigServiceMojo of changes through the +// client interface, and watching the subsequent values it emits to registered +// net::ProxyConfigService::Observers. +class ProxyConfigServiceMojoTest : public testing::Test { + public: + ProxyConfigServiceMojoTest() + : scoped_task_environment_( + base::test::ScopedTaskEnvironment::MainThreadType::IO), + proxy_config_service_(mojo::MakeRequest(&config_client_), + base::Optional<net::ProxyConfigWithAnnotation>(), + nullptr), + observer_(&proxy_config_service_) { + proxy_config_service_.AddObserver(&observer_); + } + + ~ProxyConfigServiceMojoTest() override { + proxy_config_service_.RemoveObserver(&observer_); + } + + protected: + // After notifying a new configuration through |config_client_|, waits for the + // observers to have been notified. + void WaitForConfig() { scoped_task_environment_.RunUntilIdle(); } + + base::test::ScopedTaskEnvironment scoped_task_environment_; + mojom::ProxyConfigClientPtr config_client_; + ProxyConfigServiceMojo proxy_config_service_; + TestProxyConfigServiceObserver observer_; + + DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceMojoTest); +}; + // Most tests of this class are in network_context_unittests. // Makes sure that a ProxyConfigService::Observer is correctly notified of // changes when the ProxyConfig changes, and is not informed of them in the case // of "changes" that result in the same ProxyConfig as before. -TEST(ProxyConfigServiceMojoTest, ObserveProxyChanges) { - base::test::ScopedTaskEnvironment scoped_task_environment( - base::test::ScopedTaskEnvironment::MainThreadType::IO); - - mojom::ProxyConfigClientPtr config_client; - ProxyConfigServiceMojo proxy_config_service( - mojo::MakeRequest(&config_client), - base::Optional<net::ProxyConfigWithAnnotation>(), nullptr); - TestProxyConfigServiceObserver observer(&proxy_config_service); - proxy_config_service.AddObserver(&observer); - +TEST_F(ProxyConfigServiceMojoTest, ObserveProxyChanges) { net::ProxyConfigWithAnnotation proxy_config; // The service should start without a config. EXPECT_EQ(net::ProxyConfigService::CONFIG_PENDING, - proxy_config_service.GetLatestProxyConfig(&proxy_config)); + proxy_config_service_.GetLatestProxyConfig(&proxy_config)); net::ProxyConfig proxy_configs[3]; proxy_configs[0].proxy_rules().ParseFromString("http=foopy:80"); @@ -90,29 +112,62 @@ TEST(ProxyConfigServiceMojoTest, ObserveProxyChanges) { for (const auto& proxy_config : proxy_configs) { // Set the proxy configuration to something that does not match the old one. - config_client->OnProxyConfigUpdated(net::ProxyConfigWithAnnotation( + config_client_->OnProxyConfigUpdated(net::ProxyConfigWithAnnotation( proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)); - scoped_task_environment.RunUntilIdle(); - EXPECT_EQ(1, observer.GetAndResetConfigChanges()); - EXPECT_TRUE(proxy_config.Equals(observer.observed_config().value())); + WaitForConfig(); + EXPECT_EQ(1, observer_.GetAndResetConfigChanges()); + EXPECT_TRUE(proxy_config.Equals(observer_.observed_config().value())); net::ProxyConfigWithAnnotation retrieved_config; EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID, - proxy_config_service.GetLatestProxyConfig(&retrieved_config)); + proxy_config_service_.GetLatestProxyConfig(&retrieved_config)); EXPECT_TRUE(proxy_config.Equals(retrieved_config.value())); // Set the proxy configuration to the same value again. There should be not // be another proxy config changed notification. - config_client->OnProxyConfigUpdated(net::ProxyConfigWithAnnotation( + config_client_->OnProxyConfigUpdated(net::ProxyConfigWithAnnotation( proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)); - scoped_task_environment.RunUntilIdle(); - EXPECT_EQ(0, observer.GetAndResetConfigChanges()); - EXPECT_TRUE(proxy_config.Equals(observer.observed_config().value())); + WaitForConfig(); + EXPECT_EQ(0, observer_.GetAndResetConfigChanges()); + EXPECT_TRUE(proxy_config.Equals(observer_.observed_config().value())); EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID, - proxy_config_service.GetLatestProxyConfig(&retrieved_config)); + proxy_config_service_.GetLatestProxyConfig(&retrieved_config)); EXPECT_TRUE(proxy_config.Equals(retrieved_config.value())); } +} + +// Creates a URL that has length |url::kMaxURLChars + 1|. +GURL CreateLargeURL() { + std::string spec; + spec.reserve(url::kMaxURLChars + 1); + spec.assign("http://test.invalid/"); + spec.append(url::kMaxURLChars + 1 - spec.size(), 'x'); + return GURL(spec); +} - proxy_config_service.RemoveObserver(&observer); +// Tests what happens when ProxyConfigServiceMojo is updated to using a +// ProxyConfig with a large URL. GURL does not impose size limits, however some +// internals like url.mojom.Url do. +TEST_F(ProxyConfigServiceMojoTest, LargePacUrlNotTruncated) { + // Create a config using a large, valid, PAC URL. + net::ProxyConfig orig_config; + GURL large_url = CreateLargeURL(); + EXPECT_TRUE(large_url.is_valid()); + EXPECT_EQ(url::kMaxURLChars + 1, large_url.possibly_invalid_spec().size()); + orig_config.set_pac_url(large_url); + + // Notify the ProxyConfigServiceMojo of this URL through the client interface. + config_client_->OnProxyConfigUpdated(net::ProxyConfigWithAnnotation( + orig_config, TRAFFIC_ANNOTATION_FOR_TESTS)); + + WaitForConfig(); + + // Read back the ProxyConfig that was observed (which has been serialized + // through a Mojo pipe). + const GURL& observed_url = observer_.observed_config().value().pac_url(); + + // The URL should be unchanged, and not changed by the Mojo serialization. + EXPECT_EQ(large_url, observed_url); + EXPECT_EQ(url::kMaxURLChars + 1, observed_url.possibly_invalid_spec().size()); } } // namespace diff --git a/chromium/services/network/public/cpp/network_ipc_param_traits.h b/chromium/services/network/public/cpp/network_ipc_param_traits.h index 68e7ca593c2..a291d8405cf 100644 --- a/chromium/services/network/public/cpp/network_ipc_param_traits.h +++ b/chromium/services/network/public/cpp/network_ipc_param_traits.h @@ -132,6 +132,7 @@ IPC_STRUCT_TRAITS_BEGIN(network::URLLoaderCompletionStatus) IPC_STRUCT_TRAITS_MEMBER(cors_error_status) IPC_STRUCT_TRAITS_MEMBER(ssl_info) IPC_STRUCT_TRAITS_MEMBER(should_report_corb_blocking) + IPC_STRUCT_TRAITS_MEMBER(proxy_server) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(network::ResourceResponseInfo) diff --git a/chromium/services/network/public/cpp/proxy_config_mojom_traits.cc b/chromium/services/network/public/cpp/proxy_config_mojom_traits.cc index f0bb5ea1f36..15b58d9196e 100644 --- a/chromium/services/network/public/cpp/proxy_config_mojom_traits.cc +++ b/chromium/services/network/public/cpp/proxy_config_mojom_traits.cc @@ -109,12 +109,12 @@ bool StructTraits<network::mojom::ProxyRulesDataView, bool StructTraits<network::mojom::ProxyConfigDataView, net::ProxyConfig>::Read( network::mojom::ProxyConfigDataView data, net::ProxyConfig* out_proxy_config) { - GURL pac_url; + std::string pac_url; if (!data.ReadPacUrl(&pac_url) || !data.ReadProxyRules(&out_proxy_config->proxy_rules())) { return false; } - out_proxy_config->set_pac_url(pac_url); + out_proxy_config->set_pac_url(GURL(pac_url)); out_proxy_config->set_auto_detect(data.auto_detect()); out_proxy_config->set_pac_mandatory(data.pac_mandatory()); diff --git a/chromium/services/network/public/cpp/proxy_config_mojom_traits.h b/chromium/services/network/public/cpp/proxy_config_mojom_traits.h index 70457300a0d..6d60b0d5d24 100644 --- a/chromium/services/network/public/cpp/proxy_config_mojom_traits.h +++ b/chromium/services/network/public/cpp/proxy_config_mojom_traits.h @@ -6,6 +6,8 @@ #define SERVICES_NETWORK_PUBLIC_CPP_PROXY_CONFIG_MOJOM_TRAITS_H_ #include "base/component_export.h" +#include "mojo/public/cpp/base/big_buffer_mojom_traits.h" +#include "mojo/public/cpp/base/big_string_mojom_traits.h" #include "net/proxy_resolution/proxy_bypass_rules.h" #include "net/proxy_resolution/proxy_config.h" #include "net/proxy_resolution/proxy_list.h" @@ -93,7 +95,9 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) StructTraits<network::mojom::ProxyConfigDataView, net::ProxyConfig> { public: static bool auto_detect(const net::ProxyConfig& r) { return r.auto_detect(); } - static const GURL& pac_url(const net::ProxyConfig& r) { return r.pac_url(); } + static const std::string& pac_url(const net::ProxyConfig& r) { + return r.pac_url().possibly_invalid_spec(); + } static bool pac_mandatory(const net::ProxyConfig& r) { return r.pac_mandatory(); } diff --git a/chromium/services/network/public/cpp/simple_url_loader_unittest.cc b/chromium/services/network/public/cpp/simple_url_loader_unittest.cc index a71782b60b6..f19f1c55664 100644 --- a/chromium/services/network/public/cpp/simple_url_loader_unittest.cc +++ b/chromium/services/network/public/cpp/simple_url_loader_unittest.cc @@ -584,7 +584,8 @@ class SimpleURLLoaderTestBase { network::mojom::NetworkServiceClientPtr network_service_client_ptr; network_service_client_ = std::make_unique<TestNetworkServiceClient>( mojo::MakeRequest(&network_service_client_ptr)); - network_service_ptr->SetClient(std::move(network_service_client_ptr)); + network_service_ptr->SetClient(std::move(network_service_client_ptr), + network::mojom::NetworkServiceParams::New()); mojom::URLLoaderFactoryParamsPtr params = mojom::URLLoaderFactoryParams::New(); diff --git a/chromium/services/network/public/cpp/url_loader_completion_status.cc b/chromium/services/network/public/cpp/url_loader_completion_status.cc index 7cfe6e1af4b..f6fb2d80630 100644 --- a/chromium/services/network/public/cpp/url_loader_completion_status.cc +++ b/chromium/services/network/public/cpp/url_loader_completion_status.cc @@ -34,7 +34,8 @@ bool URLLoaderCompletionStatus::operator==( encoded_body_length == rhs.encoded_body_length && decoded_body_length == rhs.decoded_body_length && cors_error_status == rhs.cors_error_status && - should_report_corb_blocking == rhs.should_report_corb_blocking; + should_report_corb_blocking == rhs.should_report_corb_blocking && + proxy_server == rhs.proxy_server; } } // namespace network diff --git a/chromium/services/network/public/cpp/url_loader_completion_status.h b/chromium/services/network/public/cpp/url_loader_completion_status.h index 6ca5b2377be..cbc81c87d38 100644 --- a/chromium/services/network/public/cpp/url_loader_completion_status.h +++ b/chromium/services/network/public/cpp/url_loader_completion_status.h @@ -70,6 +70,9 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) URLLoaderCompletionStatus { // Set when response blocked by CORB needs to be reported to the DevTools // console. bool should_report_corb_blocking = false; + + // The proxy server used for this request, if any. + net::ProxyServer proxy_server; }; } // namespace network diff --git a/chromium/services/network/public/mojom/BUILD.gn b/chromium/services/network/public/mojom/BUILD.gn index 9f8792d3dd9..5b13c2b725e 100644 --- a/chromium/services/network/public/mojom/BUILD.gn +++ b/chromium/services/network/public/mojom/BUILD.gn @@ -141,4 +141,8 @@ mojom("mojom") { if (is_linux && !is_chromeos) { enabled_features += [ "needs_crypt_config" ] } + + if (is_android || is_chromeos) { + enabled_features += [ "network_change_notifier_in_browser" ] + } } diff --git a/chromium/services/network/public/mojom/network_change_manager.mojom b/chromium/services/network/public/mojom/network_change_manager.mojom index ed0c245bc25..269cceb8950 100644 --- a/chromium/services/network/public/mojom/network_change_manager.mojom +++ b/chromium/services/network/public/mojom/network_change_manager.mojom @@ -91,7 +91,7 @@ interface NetworkChangeManager { // changes from Shill, and currently that has to be the browser process. This // allows the browser process to forward the network changes to the network // service. - [EnableIf=is_chromeos] + [EnableIf=network_change_notifier_in_browser] OnNetworkChanged( bool dns_changed, bool ip_address_changed, diff --git a/chromium/services/network/public/mojom/network_service.mojom b/chromium/services/network/public/mojom/network_service.mojom index e991c54c613..a025436d949 100644 --- a/chromium/services/network/public/mojom/network_service.mojom +++ b/chromium/services/network/public/mojom/network_service.mojom @@ -235,12 +235,18 @@ struct CryptConfig { mojo_base.mojom.FilePath user_data_path; }; +// Parameters needed to initialize the network service. +struct NetworkServiceParams { + ConnectionType initial_connection_type = CONNECTION_UNKNOWN; + ConnectionSubtype initial_connection_subtype = SUBTYPE_UNKNOWN; +}; + // Browser interface to the network service. interface NetworkService { // Sets client used by all |NetworkContext|s creating by |NetworkService|. // Pending requests may hang if the |client| pipe is closed before they // complete. - SetClient(NetworkServiceClient client); + SetClient(NetworkServiceClient client, NetworkServiceParams params); // Starts observing the NetLog event stream and writing entries to |file|. // |constants| is a legend used for decoding constant values in the log; it diff --git a/chromium/services/network/public/mojom/proxy_config.mojom b/chromium/services/network/public/mojom/proxy_config.mojom index d728e82a72c..a1965d2022a 100644 --- a/chromium/services/network/public/mojom/proxy_config.mojom +++ b/chromium/services/network/public/mojom/proxy_config.mojom @@ -4,8 +4,7 @@ module network.mojom; -import "url/mojom/url.mojom"; - +import "mojo/public/mojom/base/big_string.mojom"; // This corresponds to the string representation of net::ProxyConfigBypassRules. struct ProxyBypassRules { array<string> rules; @@ -39,7 +38,10 @@ struct ProxyRules { // These fields mirror those of net::ProxyConfig. struct ProxyConfig { bool auto_detect; - url.mojom.Url pac_url; + // Note that a |BigString| is used rather than a |url.mojom.Url|, since + // |url.mojom.Url| imposes a smaller limit on URL size than GURL, and + // ProxyConfig::pac_url may contain large data: URLs that exceed this limit. + mojo_base.mojom.BigString pac_url; bool pac_mandatory; ProxyRules proxy_rules; -};
\ No newline at end of file +}; diff --git a/chromium/services/network/url_loader.cc b/chromium/services/network/url_loader.cc index 1121d7b3b1a..a54048b9fb2 100644 --- a/chromium/services/network/url_loader.cc +++ b/chromium/services/network/url_loader.cc @@ -842,9 +842,15 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) { corb_analyzer_->LogAllowedResponse(); } } - if ((options_ & mojom::kURLLoadOptionSniffMimeType) && - ShouldSniffContent(url_request_.get(), response_.get())) { - is_more_mime_sniffing_needed_ = true; + if ((options_ & mojom::kURLLoadOptionSniffMimeType)) { + if (ShouldSniffContent(url_request_.get(), response_.get())) { + is_more_mime_sniffing_needed_ = true; + } else if (response_->head.mime_type.empty()) { + // Ugg. The server told us not to sniff the content but didn't give us + // a mime type. What's a browser to do? Turns out, we're supposed to + // treat the response as "text/plain". This is the most secure option. + response_->head.mime_type.assign("text/plain"); + } } if (!is_more_mime_sniffing_needed_ && !is_more_corb_sniffing_needed_) { // Treat feed types as text/plain. @@ -1128,6 +1134,7 @@ void URLLoader::NotifyCompleted(int error_code) { status.encoded_data_length = url_request_->GetTotalReceivedBytes(); status.encoded_body_length = url_request_->GetRawBodyBytes(); status.decoded_body_length = total_written_bytes_; + status.proxy_server = url_request_->proxy_server(); if ((options_ & mojom::kURLLoadOptionSendSSLInfoForCertificateError) && net::IsCertStatusError(url_request_->ssl_info().cert_status) && diff --git a/chromium/services/network/url_loader_unittest.cc b/chromium/services/network/url_loader_unittest.cc index e218d8ac089..f0b7edbd3e6 100644 --- a/chromium/services/network/url_loader_unittest.cc +++ b/chromium/services/network/url_loader_unittest.cc @@ -827,7 +827,7 @@ TEST_F(URLLoaderTest, RespectNoSniff) { set_sniff(); EXPECT_EQ(net::OK, Load(test_server()->GetURL("/nosniff-test.html"))); EXPECT_FALSE(did_mime_sniff()); - ASSERT_TRUE(mime_type().empty()); + ASSERT_EQ(std::string("text/plain"), mime_type()); } TEST_F(URLLoaderTest, SniffTextPlainDoesNotResultInHTML) { diff --git a/chromium/services/network/websocket.cc b/chromium/services/network/websocket.cc index feda8658aae..16c598c706b 100644 --- a/chromium/services/network/websocket.cc +++ b/chromium/services/network/websocket.cc @@ -14,6 +14,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/single_thread_task_runner.h" +#include "base/strings/strcat.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" @@ -252,17 +253,19 @@ void WebSocket::WebSocketEventHandler::OnFinishOpeningHandshake( response_to_pass->socket_address = response->socket_address; size_t iter = 0; std::string name, value; + std::string headers_text = + base::StrCat({response->headers->GetStatusLine(), "\r\n"}); while (response->headers->EnumerateHeaderLines(&iter, &name, &value)) { if (can_read_raw_cookies || !net::HttpResponseHeaders::IsCookieResponseHeader(name)) { // We drop cookie-related headers such as "set-cookie" when the // renderer doesn't have access. response_to_pass->headers.push_back(mojom::HttpHeader::New(name, value)); + base::StrAppend(&headers_text, {name, ": ", value, "\r\n"}); } } - response_to_pass->headers_text = - net::HttpUtil::ConvertHeadersBackToHTTPResponse( - response->headers->raw_headers()); + headers_text.append("\r\n"); + response_to_pass->headers_text = headers_text; impl_->client_->OnFinishOpeningHandshake(std::move(response_to_pass)); } diff --git a/chromium/services/network/websocket_factory.cc b/chromium/services/network/websocket_factory.cc index fd21e41daec..10e053e032b 100644 --- a/chromium/services/network/websocket_factory.cc +++ b/chromium/services/network/websocket_factory.cc @@ -11,6 +11,7 @@ #include "services/network/public/mojom/network_service.mojom.h" #include "services/network/websocket.h" #include "url/origin.h" +#include "url/url_constants.h" namespace network { @@ -60,8 +61,13 @@ class WebSocketFactory::Delegate final : public WebSocket::Delegate { } bool CanReadRawCookies(const GURL& url) override { + DCHECK(url.SchemeIsWSOrWSS()); + GURL::Replacements replace_scheme; + replace_scheme.SetSchemeStr( + url.SchemeIs(url::kWssScheme) ? url::kHttpsScheme : url::kHttpScheme); + GURL url_to_check = url.ReplaceComponents(replace_scheme); return factory_->context_->network_service()->HasRawHeadersAccess( - process_id_, url); + process_id_, url_to_check); } void OnCreateURLRequest(int child_id, diff --git a/chromium/services/tracing/public/cpp/traced_process_impl.cc b/chromium/services/tracing/public/cpp/traced_process_impl.cc index daa05310fa4..e380d010dbc 100644 --- a/chromium/services/tracing/public/cpp/traced_process_impl.cc +++ b/chromium/services/tracing/public/cpp/traced_process_impl.cc @@ -7,6 +7,7 @@ #include <utility> #include "base/no_destructor.h" +#include "base/task/task_scheduler/task_scheduler.h" #include "services/tracing/public/cpp/base_agent.h" #include "services/tracing/public/cpp/perfetto/producer_client.h" #include "services/tracing/public/cpp/trace_event_agent.h" @@ -74,6 +75,12 @@ void TracedProcessImpl::ConnectToTracingService( mojom::ConnectToTracingRequestPtr request) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // Tracing requires a running TaskScheduler; disable tracing + // for processes without it. + if (!base::TaskScheduler::GetInstance()) { + return; + } + // Ensure the TraceEventAgent has been created. TraceEventAgent::GetInstance(); |