| // Copyright 2015 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 "content/browser/service_manager/service_manager_context.h" |
| |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/deferred_sequenced_task_runner.h" |
| #include "base/feature_list.h" |
| #include "base/lazy_instance.h" |
| #include "base/macros.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/no_destructor.h" |
| #include "base/process/process_handle.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/stl_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/post_task.h" |
| #include "build/build_config.h" |
| #include "content/app/strings/grit/content_strings.h" |
| #include "content/browser/browser_main_loop.h" |
| #include "content/browser/child_process_launcher.h" |
| #include "content/browser/gpu/gpu_process_host.h" |
| #include "content/browser/service_manager/common_browser_interfaces.h" |
| #include "content/browser/utility_process_host.h" |
| #include "content/browser/utility_process_host_client.h" |
| #include "content/browser/wake_lock/wake_lock_context_host.h" |
| #include "content/common/service_manager/service_manager_connection_impl.h" |
| #include "content/public/app/content_browser_manifest.h" |
| #include "content/public/app/content_gpu_manifest.h" |
| #include "content/public/app/content_packaged_services_manifest.h" |
| #include "content/public/app/content_plugin_manifest.h" |
| #include "content/public/app/content_renderer_manifest.h" |
| #include "content/public/app/content_utility_manifest.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/child_process_data.h" |
| #include "content/public/browser/content_browser_client.h" |
| #include "content/public/browser/gpu_service_registry.h" |
| #include "content/public/browser/network_service_instance.h" |
| #include "content/public/common/content_client.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/network_service_util.h" |
| #include "content/public/common/service_manager_connection.h" |
| #include "content/public/common/service_names.mojom.h" |
| #include "media/audio/audio_manager.h" |
| #include "media/media_buildflags.h" |
| #include "media/mojo/buildflags.h" |
| #include "media/mojo/interfaces/constants.mojom.h" |
| #include "mojo/public/cpp/platform/platform_channel.h" |
| #include "mojo/public/cpp/system/invitation.h" |
| #include "services/audio/public/mojom/constants.mojom.h" |
| #include "services/audio/service_factory.h" |
| #include "services/data_decoder/public/mojom/constants.mojom.h" |
| #include "services/device/device_service.h" |
| #include "services/device/public/mojom/constants.mojom.h" |
| #include "services/media_session/media_session_service.h" |
| #include "services/media_session/public/cpp/features.h" |
| #include "services/media_session/public/mojom/constants.mojom.h" |
| #include "services/metrics/metrics_mojo_service.h" |
| #include "services/metrics/public/mojom/constants.mojom.h" |
| #include "services/network/network_service.h" |
| #include "services/network/public/cpp/cross_thread_shared_url_loader_factory_info.h" |
| #include "services/network/public/cpp/features.h" |
| #include "services/network/public/mojom/network_service_test.mojom.h" |
| #include "services/resource_coordinator/public/mojom/service_constants.mojom.h" |
| #include "services/resource_coordinator/resource_coordinator_service.h" |
| #include "services/service_manager/connect_params.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| #include "services/service_manager/public/cpp/constants.h" |
| #include "services/service_manager/public/cpp/manifest.h" |
| #include "services/service_manager/public/cpp/service.h" |
| #include "services/service_manager/public/mojom/service.mojom.h" |
| #include "services/service_manager/sandbox/sandbox_type.h" |
| #include "services/service_manager/service_manager.h" |
| #include "services/service_manager/service_process_launcher.h" |
| #include "services/shape_detection/public/mojom/constants.mojom.h" |
| #include "services/tracing/public/cpp/tracing_features.h" |
| #include "services/tracing/public/mojom/constants.mojom.h" |
| #include "services/tracing/tracing_service.h" |
| #include "services/video_capture/public/mojom/constants.mojom.h" |
| #include "services/video_capture/service_impl.h" |
| #include "services/viz/public/interfaces/constants.mojom.h" |
| #include "ui/base/buildflags.h" |
| #include "ui/base/ui_base_features.h" |
| |
| #if defined(OS_ANDROID) |
| #include "base/android/jni_android.h" |
| #include "base/android/scoped_java_ref.h" |
| #include "jni/ContentNfcDelegate_jni.h" |
| #endif |
| |
| #if defined(OS_LINUX) |
| #include "components/services/font/font_service_app.h" |
| #include "components/services/font/public/interfaces/constants.mojom.h" |
| #endif |
| |
| #if defined(OS_CHROMEOS) |
| #include "chromeos/assistant/buildflags.h" // nogncheck |
| #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) |
| #include "chromeos/services/assistant/public/mojom/constants.mojom.h" // nogncheck |
| #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) |
| #endif |
| |
| namespace content { |
| |
| namespace { |
| |
| base::LazyInstance<std::unique_ptr<service_manager::Connector>>::Leaky |
| g_io_thread_connector = LAZY_INSTANCE_INITIALIZER; |
| |
| base::LazyInstance<std::map<std::string, base::WeakPtr<UtilityProcessHost>>>:: |
| Leaky g_active_process_groups; |
| |
| // If enabled, network service will run in it's own thread when running |
| // in-process, otherwise it is run on the IO thread. |
| // On ChromeOS the network service has to run on the IO thread because |
| // ProfileIOData and NetworkContext both try to set up NSS, which has has to be |
| // called from the IO thread. |
| const base::Feature kNetworkServiceDedicatedThread{ |
| "NetworkServiceDedicatedThread", |
| #if defined(OS_CHROMEOS) |
| base::FEATURE_DISABLED_BY_DEFAULT |
| #else |
| base::FEATURE_ENABLED_BY_DEFAULT |
| #endif |
| }; |
| |
| void DestroyConnectorOnIOThread() { g_io_thread_connector.Get().reset(); } |
| |
| // Launch a process for a service once its sandbox type is known. |
| void StartServiceInUtilityProcess( |
| const std::string& service_name, |
| const ContentBrowserClient::ProcessNameCallback& process_name_callback, |
| base::Optional<std::string> process_group, |
| service_manager::mojom::ServiceRequest request, |
| service_manager::mojom::PIDReceiverPtr pid_receiver, |
| service_manager::mojom::ServiceInfoPtr service_info) { |
| DCHECK(service_info); |
| service_manager::SandboxType sandbox_type = |
| service_manager::UtilitySandboxTypeFromString(service_info->sandbox_type); |
| |
| // Look for an existing process group. |
| base::WeakPtr<UtilityProcessHost>* weak_host = nullptr; |
| if (process_group) |
| weak_host = &g_active_process_groups.Get()[*process_group]; |
| |
| UtilityProcessHost* process_host = nullptr; |
| if (weak_host && *weak_host) { |
| // Start service in an existing process. |
| process_host = weak_host->get(); |
| } else { |
| // Start a new process for this service. |
| UtilityProcessHost* impl = new UtilityProcessHost(nullptr, nullptr); |
| base::string16 process_name = process_name_callback.Run(); |
| DCHECK(!process_name.empty()); |
| impl->SetName(process_name); |
| impl->SetMetricsName(service_name); |
| // NOTE: This is not the service instance's real Identity. For all current |
| // practical purposes however, only the name is relevant. |
| impl->SetServiceIdentity(service_manager::Identity( |
| service_name, service_manager::kSystemInstanceGroup, base::Token{}, |
| base::Token{1, 1})); |
| impl->SetSandboxType(sandbox_type); |
| impl->Start(); |
| impl->SetLaunchCallback( |
| base::BindOnce([](service_manager::mojom::PIDReceiverPtr pid_receiver, |
| base::ProcessId pid) { pid_receiver->SetPID(pid); }, |
| std::move(pid_receiver))); |
| if (weak_host) |
| *weak_host = impl->AsWeakPtr(); |
| process_host = impl; |
| } |
| |
| service_manager::mojom::ServiceFactoryPtr service_factory; |
| BindInterface(process_host, mojo::MakeRequest(&service_factory)); |
| |
| // CreateService expects a non-null PIDReceiverPtr, but we don't actually |
| // expect the utility process to report anything on it. Send a dead-end proxy. |
| service_manager::mojom::PIDReceiverPtr dead_pid_receiver; |
| mojo::MakeRequest(&dead_pid_receiver); |
| service_factory->CreateService(std::move(request), service_name, |
| std::move(dead_pid_receiver)); |
| } |
| |
| // Determine a sandbox type for a service and launch a process for it. |
| void QueryAndStartServiceInUtilityProcess( |
| const std::string& service_name, |
| const ContentBrowserClient::ProcessNameCallback& process_name_callback, |
| base::Optional<std::string> process_group, |
| service_manager::mojom::ServiceRequest request, |
| service_manager::mojom::PIDReceiverPtr pid_receiver) { |
| ServiceManagerContext::GetConnectorForIOThread()->QueryService( |
| service_name, |
| base::BindOnce(&StartServiceInUtilityProcess, service_name, |
| process_name_callback, std::move(process_group), |
| std::move(request), std::move(pid_receiver))); |
| } |
| |
| // Request service_manager::mojom::ServiceFactory from GPU process host. Must be |
| // called on IO thread. |
| void StartServiceInGpuProcess( |
| const std::string& service_name, |
| service_manager::mojom::ServiceRequest request, |
| service_manager::mojom::PIDReceiverPtr pid_receiver) { |
| GpuProcessHost* process_host = GpuProcessHost::Get(); |
| if (!process_host) { |
| DLOG(ERROR) << "GPU process host not available."; |
| return; |
| } |
| |
| service_manager::mojom::ServiceFactoryPtr service_factory; |
| // TODO(xhwang): It's possible that |process_host| is non-null, but the actual |
| // process is dead. In that case, |request| will be dropped and application |
| // load requests through ServiceFactory will also fail. Make sure we handle |
| // these cases correctly. |
| BindInterfaceInGpuProcess(mojo::MakeRequest(&service_factory)); |
| service_factory->CreateService(std::move(request), service_name, |
| std::move(pid_receiver)); |
| } |
| |
| class NullServiceProcessLauncherFactory |
| : public service_manager::ServiceProcessLauncherFactory { |
| public: |
| NullServiceProcessLauncherFactory() {} |
| ~NullServiceProcessLauncherFactory() override {} |
| |
| private: |
| std::unique_ptr<service_manager::ServiceProcessLauncher> Create( |
| const base::FilePath& service_path) override { |
| // There are innocuous races where browser code may attempt to connect |
| // to a specific renderer instance through the Service Manager after that |
| // renderer has been terminated. These result in this code path being hit |
| // fairly regularly and the resulting log spam causes confusion. We suppress |
| // this message only for "content_renderer". |
| const base::FilePath::StringType kRendererServiceFilename = |
| base::FilePath().AppendASCII(mojom::kRendererServiceName).value(); |
| const base::FilePath::StringType service_executable = |
| service_path.BaseName().value(); |
| if (service_executable.find(kRendererServiceFilename) == |
| base::FilePath::StringType::npos) { |
| LOG(ERROR) << "Attempting to run unsupported native service: " |
| << service_path.value(); |
| } |
| return nullptr; |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(NullServiceProcessLauncherFactory); |
| }; |
| |
| // This class is intended for tests that want to load service binaries (rather |
| // than via the utility process). Production code uses |
| // NullServiceProcessLauncherFactory. |
| class ServiceBinaryLauncherFactory |
| : public service_manager::ServiceProcessLauncherFactory { |
| public: |
| ServiceBinaryLauncherFactory() = default; |
| ~ServiceBinaryLauncherFactory() override = default; |
| |
| private: |
| std::unique_ptr<service_manager::ServiceProcessLauncher> Create( |
| const base::FilePath& service_path) override { |
| return std::make_unique<service_manager::ServiceProcessLauncher>( |
| nullptr, service_path); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(ServiceBinaryLauncherFactory); |
| }; |
| |
| // SharedURLLoaderFactory for device service, backed by |
| // GetContentClient()->browser()->GetSystemSharedURLLoaderFactory(). |
| class DeviceServiceURLLoaderFactory : public network::SharedURLLoaderFactory { |
| public: |
| DeviceServiceURLLoaderFactory() = default; |
| |
| // mojom::URLLoaderFactory implementation: |
| void CreateLoaderAndStart(network::mojom::URLLoaderRequest request, |
| int32_t routing_id, |
| int32_t request_id, |
| uint32_t options, |
| const network::ResourceRequest& url_request, |
| network::mojom::URLLoaderClientPtr client, |
| const net::MutableNetworkTrafficAnnotationTag& |
| traffic_annotation) override { |
| GetContentClient() |
| ->browser() |
| ->GetSystemSharedURLLoaderFactory() |
| ->CreateLoaderAndStart(std::move(request), routing_id, request_id, |
| options, url_request, std::move(client), |
| traffic_annotation); |
| } |
| |
| // SharedURLLoaderFactory implementation: |
| void Clone(network::mojom::URLLoaderFactoryRequest request) override { |
| GetContentClient()->browser()->GetSystemSharedURLLoaderFactory()->Clone( |
| std::move(request)); |
| } |
| |
| std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override { |
| return std::make_unique<network::CrossThreadSharedURLLoaderFactoryInfo>( |
| this); |
| } |
| |
| private: |
| friend class base::RefCounted<DeviceServiceURLLoaderFactory>; |
| ~DeviceServiceURLLoaderFactory() override = default; |
| |
| DISALLOW_COPY_AND_ASSIGN(DeviceServiceURLLoaderFactory); |
| }; |
| |
| std::unique_ptr<service_manager::Service> CreateNetworkService( |
| service_manager::mojom::ServiceRequest service_request) { |
| // The test interface doesn't need to be implemented in the in-process case. |
| auto registry = std::make_unique<service_manager::BinderRegistry>(); |
| registry->AddInterface(base::BindRepeating( |
| [](network::mojom::NetworkServiceTestRequest request) {})); |
| return std::make_unique<network::NetworkService>( |
| std::move(registry), nullptr /* request */, nullptr /* net_log */, |
| std::move(service_request)); |
| } |
| |
| bool AudioServiceOutOfProcess() { |
| // Returns true iff kAudioServiceOutOfProcess feature is enabled and if the |
| // embedder does not provide its own in-process AudioManager. |
| return base::FeatureList::IsEnabled(features::kAudioServiceOutOfProcess) && |
| !GetContentClient()->browser()->OverridesAudioManager(); |
| } |
| |
| using InProcessServiceFactory = |
| base::RepeatingCallback<std::unique_ptr<service_manager::Service>( |
| service_manager::mojom::ServiceRequest request)>; |
| |
| void LaunchInProcessServiceOnSequence( |
| const InProcessServiceFactory& factory, |
| service_manager::mojom::ServiceRequest request) { |
| service_manager::Service::RunAsyncUntilTermination( |
| factory.Run(std::move(request))); |
| } |
| |
| void LaunchInProcessService( |
| scoped_refptr<base::SequencedTaskRunner> task_runner, |
| const InProcessServiceFactory& factory, |
| service_manager::mojom::ServiceRequest request) { |
| task_runner->PostTask( |
| FROM_HERE, base::BindOnce(&LaunchInProcessServiceOnSequence, factory, |
| std::move(request))); |
| } |
| |
| void RegisterInProcessService( |
| ServiceManagerConnection* connection, |
| const std::string& service_name, |
| scoped_refptr<base::SequencedTaskRunner> task_runner, |
| const InProcessServiceFactory& factory) { |
| connection->AddServiceRequestHandler( |
| service_name, |
| base::BindRepeating(&LaunchInProcessService, task_runner, factory)); |
| } |
| |
| std::unique_ptr<service_manager::Service> CreateVideoCaptureService( |
| service_manager::mojom::ServiceRequest request) { |
| return std::make_unique<video_capture::ServiceImpl>( |
| std::move(request), base::CreateSingleThreadTaskRunnerWithTraits( |
| {content::BrowserThread::UI})); |
| } |
| |
| void CreateInProcessAudioService( |
| scoped_refptr<base::SequencedTaskRunner> task_runner, |
| service_manager::mojom::ServiceRequest request) { |
| // TODO(https://crbug.com/853254): Remove BrowserMainLoop::GetAudioManager(). |
| task_runner->PostTask( |
| FROM_HERE, base::BindOnce( |
| [](media::AudioManager* audio_manager, |
| service_manager::mojom::ServiceRequest request) { |
| service_manager::Service::RunAsyncUntilTermination( |
| audio::CreateEmbeddedService(audio_manager, |
| std::move(request))); |
| }, |
| BrowserMainLoop::GetAudioManager(), std::move(request))); |
| } |
| |
| #if defined(OS_LINUX) |
| std::unique_ptr<service_manager::Service> CreateFontService( |
| service_manager::mojom::ServiceRequest request) { |
| return std::make_unique<font_service::FontServiceApp>(std::move(request)); |
| } |
| #endif // defined(OS_LINUX) |
| |
| std::unique_ptr<service_manager::Service> CreateResourceCoordinatorService( |
| service_manager::mojom::ServiceRequest request) { |
| return std::make_unique<resource_coordinator::ResourceCoordinatorService>( |
| std::move(request)); |
| } |
| |
| std::unique_ptr<service_manager::Service> CreateTracingService( |
| service_manager::mojom::ServiceRequest request) { |
| return std::make_unique<tracing::TracingService>(std::move(request)); |
| } |
| |
| std::unique_ptr<service_manager::Service> CreateMediaSessionService( |
| service_manager::mojom::ServiceRequest request) { |
| return std::make_unique<media_session::MediaSessionService>( |
| std::move(request)); |
| } |
| |
| } // namespace |
| |
| // State which lives on the IO thread and drives the ServiceManager. |
| class ServiceManagerContext::InProcessServiceManagerContext |
| : public base::RefCountedThreadSafe<InProcessServiceManagerContext> { |
| public: |
| InProcessServiceManagerContext(scoped_refptr<base::SingleThreadTaskRunner> |
| service_manager_thread_task_runner) |
| : service_manager_thread_task_runner_( |
| service_manager_thread_task_runner) {} |
| |
| void Start( |
| service_manager::mojom::ServicePtrInfo packaged_services_service_info, |
| std::vector<service_manager::Manifest> manifests) { |
| service_manager_thread_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &InProcessServiceManagerContext::StartOnServiceManagerThread, this, |
| std::move(manifests), std::move(packaged_services_service_info), |
| base::ThreadTaskRunnerHandle::Get())); |
| } |
| |
| void ShutDown() { |
| service_manager_thread_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &InProcessServiceManagerContext::ShutDownOnServiceManagerThread, |
| this)); |
| } |
| |
| void StartServices(std::vector<std::string> service_names) { |
| service_manager_thread_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&InProcessServiceManagerContext :: |
| StartServicesOnServiceManagerThread, |
| this, std::move(service_names))); |
| } |
| |
| private: |
| friend class base::RefCountedThreadSafe<InProcessServiceManagerContext>; |
| |
| ~InProcessServiceManagerContext() {} |
| |
| void StartOnServiceManagerThread( |
| std::vector<service_manager::Manifest> manifests, |
| service_manager::mojom::ServicePtrInfo packaged_services_service_info, |
| scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner) { |
| std::unique_ptr<service_manager::ServiceProcessLauncherFactory> |
| service_process_launcher_factory; |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableServiceBinaryLauncher)) { |
| service_process_launcher_factory = |
| std::make_unique<ServiceBinaryLauncherFactory>(); |
| } else { |
| service_process_launcher_factory = |
| std::make_unique<NullServiceProcessLauncherFactory>(); |
| } |
| service_manager_ = std::make_unique<service_manager::ServiceManager>( |
| std::move(service_process_launcher_factory), std::move(manifests)); |
| |
| service_manager::mojom::ServicePtr packaged_services_service; |
| packaged_services_service.Bind(std::move(packaged_services_service_info)); |
| service_manager_->RegisterService( |
| service_manager::Identity(mojom::kPackagedServicesServiceName, |
| service_manager::kSystemInstanceGroup, |
| base::Token{}, base::Token::CreateRandom()), |
| std::move(packaged_services_service), nullptr); |
| service_manager_->SetInstanceQuitCallback( |
| base::Bind(&OnInstanceQuitOnServiceManagerThread, |
| std::move(ui_thread_task_runner))); |
| } |
| |
| static void OnInstanceQuitOnServiceManagerThread( |
| scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner, |
| const service_manager::Identity& id) { |
| ui_thread_task_runner->PostTask(FROM_HERE, |
| base::BindOnce(&OnInstanceQuit, id)); |
| } |
| |
| static void OnInstanceQuit(const service_manager::Identity& id) { |
| if (GetContentClient()->browser()->ShouldTerminateOnServiceQuit(id)) { |
| // Don't LOG(FATAL) because we don't want a browser crash report. |
| LOG(ERROR) << "Terminating because service '" << id.name() |
| << "' quit unexpectedly."; |
| // Skip shutdown to reduce the risk that other code in the browser will |
| // respond to the service pipe closing. |
| exit(1); |
| } |
| } |
| |
| void ShutDownOnServiceManagerThread() { |
| service_manager_.reset(); |
| } |
| |
| void StartServicesOnServiceManagerThread( |
| std::vector<std::string> service_names) { |
| if (!service_manager_) |
| return; |
| |
| for (const auto& service_name : service_names) |
| service_manager_->StartService(service_name); |
| } |
| |
| scoped_refptr<base::SingleThreadTaskRunner> |
| service_manager_thread_task_runner_; |
| std::unique_ptr<service_manager::ServiceManager> service_manager_; |
| |
| DISALLOW_COPY_AND_ASSIGN(InProcessServiceManagerContext); |
| }; |
| |
| ServiceManagerContext::ServiceManagerContext( |
| scoped_refptr<base::SingleThreadTaskRunner> |
| service_manager_thread_task_runner) |
| : service_manager_thread_task_runner_( |
| std::move(service_manager_thread_task_runner)) { |
| // The |service_manager_thread_task_runner_| must have been created before |
| // starting the ServiceManager. |
| DCHECK(service_manager_thread_task_runner_); |
| std::vector<service_manager::Manifest> manifests{ |
| GetContentBrowserManifest(), GetContentGpuManifest(), |
| GetContentPackagedServicesManifest(), GetContentPluginManifest(), |
| GetContentRendererManifest(), GetContentUtilityManifest(), |
| }; |
| for (auto& manifest : manifests) { |
| base::Optional<service_manager::Manifest> overlay = |
| GetContentClient()->browser()->GetServiceManifestOverlay( |
| manifest.service_name); |
| if (overlay) |
| manifest.Amend(*overlay); |
| if (!manifest.preloaded_files.empty()) { |
| std::map<std::string, base::FilePath> preloaded_files_map; |
| for (const auto& info : manifest.preloaded_files) |
| preloaded_files_map.emplace(info.key, info.path); |
| ChildProcessLauncher::SetRegisteredFilesForService( |
| manifest.service_name, std::move(preloaded_files_map)); |
| } |
| } |
| for (auto& extra_manifest : |
| GetContentClient()->browser()->GetExtraServiceManifests()) { |
| manifests.emplace_back(std::move(extra_manifest)); |
| } |
| in_process_context_ = |
| new InProcessServiceManagerContext(service_manager_thread_task_runner_); |
| |
| service_manager::mojom::ServicePtr packaged_services_service; |
| service_manager::mojom::ServiceRequest packaged_services_request = |
| mojo::MakeRequest(&packaged_services_service); |
| in_process_context_->Start(packaged_services_service.PassInterface(), |
| std::move(manifests)); |
| |
| packaged_services_connection_ = |
| ServiceManagerConnection::Create(std::move(packaged_services_request), |
| service_manager_thread_task_runner_); |
| packaged_services_connection_->SetDefaultServiceRequestHandler( |
| base::BindRepeating(&ServiceManagerContext::OnUnhandledServiceRequest, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| service_manager::mojom::ServicePtr root_browser_service; |
| ServiceManagerConnection::SetForProcess( |
| ServiceManagerConnection::Create(mojo::MakeRequest(&root_browser_service), |
| service_manager_thread_task_runner_)); |
| auto* browser_connection = ServiceManagerConnection::GetForProcess(); |
| |
| service_manager::mojom::PIDReceiverPtr pid_receiver; |
| packaged_services_connection_->GetConnector()->RegisterServiceInstance( |
| service_manager::Identity(mojom::kBrowserServiceName, |
| service_manager::kSystemInstanceGroup, |
| base::Token{}, base::Token::CreateRandom()), |
| std::move(root_browser_service), mojo::MakeRequest(&pid_receiver)); |
| pid_receiver->SetPID(base::GetCurrentProcId()); |
| |
| RegisterInProcessService( |
| packaged_services_connection_.get(), |
| resource_coordinator::mojom::kServiceName, |
| service_manager_thread_task_runner_, |
| base::BindRepeating(&CreateResourceCoordinatorService)); |
| |
| RegisterInProcessService(packaged_services_connection_.get(), |
| metrics::mojom::kMetricsServiceName, |
| service_manager_thread_task_runner_, |
| base::BindRepeating(&metrics::CreateMetricsService)); |
| |
| if (base::FeatureList::IsEnabled( |
| media_session::features::kMediaSessionService)) { |
| RegisterInProcessService(packaged_services_connection_.get(), |
| media_session::mojom::kServiceName, |
| base::SequencedTaskRunnerHandle::Get(), |
| base::BindRepeating(&CreateMediaSessionService)); |
| } |
| |
| if (features::IsVideoCaptureServiceEnabledForBrowserProcess()) { |
| RegisterInProcessService( |
| packaged_services_connection_.get(), video_capture::mojom::kServiceName, |
| #if defined(OS_WIN) |
| base::CreateCOMSTATaskRunnerWithTraits( |
| #else |
| base::CreateSingleThreadTaskRunnerWithTraits( |
| #endif |
| base::TaskTraits({base::MayBlock(), base::WithBaseSyncPrimitives(), |
| base::TaskPriority::BEST_EFFORT}), |
| base::SingleThreadTaskRunnerThreadMode::DEDICATED), |
| base::BindRepeating(&CreateVideoCaptureService)); |
| } |
| |
| #if defined(OS_LINUX) |
| RegisterInProcessService( |
| packaged_services_connection_.get(), font_service::mojom::kServiceName, |
| base::CreateSequencedTaskRunnerWithTraits( |
| base::TaskTraits({base::MayBlock(), base::WithBaseSyncPrimitives(), |
| base::TaskPriority::USER_BLOCKING})), |
| base::BindRepeating(&CreateFontService)); |
| #endif |
| |
| GetContentClient()->browser()->RegisterIOThreadServiceHandlers( |
| packaged_services_connection_.get()); |
| |
| // This is safe to assign directly from any thread, because |
| // ServiceManagerContext must be constructed before anyone can call |
| // GetConnectorForIOThread(). |
| g_io_thread_connector.Get() = browser_connection->GetConnector()->Clone(); |
| |
| ContentBrowserClient::OutOfProcessServiceMap out_of_process_services; |
| GetContentClient()->browser()->RegisterOutOfProcessServices( |
| &out_of_process_services); |
| |
| if (base::FeatureList::IsEnabled(features::kTracingServiceInProcess)) { |
| RegisterInProcessService( |
| packaged_services_connection_.get(), tracing::mojom::kServiceName, |
| base::CreateSequencedTaskRunnerWithTraits( |
| {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN, |
| base::WithBaseSyncPrimitives(), |
| base::TaskPriority::USER_BLOCKING}), |
| base::BindRepeating(&CreateTracingService)); |
| } else { |
| out_of_process_services[tracing::mojom::kServiceName] = |
| base::BindRepeating(&base::ASCIIToUTF16, "Tracing Service"); |
| } |
| |
| out_of_process_services[data_decoder::mojom::kServiceName] = |
| base::BindRepeating(&base::ASCIIToUTF16, "Data Decoder Service"); |
| |
| bool network_service_enabled = |
| base::FeatureList::IsEnabled(network::features::kNetworkService); |
| if (network_service_enabled) { |
| if (IsInProcessNetworkService()) { |
| scoped_refptr<base::SequencedTaskRunner> task_runner = |
| service_manager_thread_task_runner_; |
| if (base::FeatureList::IsEnabled(kNetworkServiceDedicatedThread)) { |
| base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); |
| network_service_thread_.StartWithOptions(options); |
| task_runner = network_service_thread_.task_runner(); |
| } |
| |
| GetNetworkTaskRunner()->StartWithTaskRunner(task_runner); |
| RegisterInProcessService(packaged_services_connection_.get(), |
| mojom::kNetworkServiceName, task_runner, |
| base::BindRepeating(&CreateNetworkService)); |
| } else { |
| out_of_process_services[mojom::kNetworkServiceName] = |
| base::BindRepeating(&base::ASCIIToUTF16, "Network Service"); |
| } |
| } |
| |
| if (AudioServiceOutOfProcess()) { |
| DCHECK(base::FeatureList::IsEnabled(features::kAudioServiceAudioStreams)); |
| out_of_process_services[audio::mojom::kServiceName] = |
| base::BindRepeating(&base::ASCIIToUTF16, "Audio Service"); |
| } else { |
| packaged_services_connection_->AddServiceRequestHandler( |
| audio::mojom::kServiceName, |
| base::BindRepeating(&CreateInProcessAudioService, |
| base::WrapRefCounted(GetAudioServiceRunner()))); |
| } |
| |
| if (features::IsVideoCaptureServiceEnabledForOutOfProcess()) { |
| out_of_process_services[video_capture::mojom::kServiceName] = |
| base::BindRepeating(&base::ASCIIToUTF16, "Video Capture Service"); |
| } |
| |
| #if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS) |
| out_of_process_services[media::mojom::kMediaServiceName] = |
| base::BindRepeating(&base::ASCIIToUTF16, "Media Service"); |
| #endif |
| |
| #if BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| out_of_process_services[media::mojom::kCdmServiceName] = base::BindRepeating( |
| &base::ASCIIToUTF16, "Content Decryption Module Service"); |
| #endif |
| |
| #if defined(OS_CHROMEOS) |
| #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) |
| out_of_process_services |
| [chromeos::assistant::mojom::kAudioDecoderServiceName] = |
| base::BindRepeating(&base::ASCIIToUTF16, |
| "Assistant Audio Decoder Service"); |
| #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) |
| #endif |
| |
| if (features::IsMultiProcessMash() && features::IsMashOopVizEnabled()) { |
| out_of_process_services[viz::mojom::kVizServiceName] = |
| base::BindRepeating(&base::ASCIIToUTF16, "Visuals Service"); |
| } |
| |
| for (const auto& service : out_of_process_services) { |
| packaged_services_connection_->AddServiceRequestHandlerWithPID( |
| service.first, |
| base::BindRepeating(&QueryAndStartServiceInUtilityProcess, |
| service.first, service.second.process_name_callback, |
| service.second.process_group)); |
| } |
| |
| #if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) |
| packaged_services_connection_->AddServiceRequestHandlerWithPID( |
| media::mojom::kMediaServiceName, |
| base::Bind(&StartServiceInGpuProcess, media::mojom::kMediaServiceName)); |
| #endif |
| |
| packaged_services_connection_->AddServiceRequestHandlerWithPID( |
| shape_detection::mojom::kServiceName, |
| base::Bind(&StartServiceInGpuProcess, |
| shape_detection::mojom::kServiceName)); |
| |
| packaged_services_connection_->Start(); |
| |
| in_process_context_->StartServices( |
| GetContentClient()->browser()->GetStartupServices()); |
| } |
| |
| ServiceManagerContext::~ServiceManagerContext() { |
| ShutDown(); |
| } |
| |
| void ServiceManagerContext::ShutDown() { |
| // NOTE: The in-process ServiceManager MUST be destroyed before the browser |
| // process-wide ServiceManagerConnection. Otherwise it's possible for the |
| // ServiceManager to receive connection requests for service:content_browser |
| // which it may attempt to service by launching a new instance of the browser. |
| if (in_process_context_) |
| in_process_context_->ShutDown(); |
| if (ServiceManagerConnection::GetForProcess()) |
| ServiceManagerConnection::DestroyForProcess(); |
| service_manager_thread_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&DestroyConnectorOnIOThread)); |
| packaged_services_connection_.reset(); |
| } |
| |
| // static |
| service_manager::Connector* ServiceManagerContext::GetConnectorForIOThread() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| return g_io_thread_connector.Get().get(); |
| } |
| |
| // static |
| bool ServiceManagerContext::HasValidProcessForProcessGroup( |
| const std::string& process_group_name) { |
| auto iter = g_active_process_groups.Get().find(process_group_name); |
| if (iter == g_active_process_groups.Get().end() || !iter->second) |
| return false; |
| return iter->second->GetData().GetProcess().IsValid(); |
| } |
| |
| // static |
| void ServiceManagerContext::StartBrowserConnection() { |
| auto* browser_connection = ServiceManagerConnection::GetForProcess(); |
| RegisterCommonBrowserInterfaces(browser_connection); |
| browser_connection->Start(); |
| |
| if (base::FeatureList::IsEnabled(network::features::kNetworkService)) |
| return; |
| |
| // Create the in-process NetworkService object so that its getter is |
| // available on the IO thread. |
| GetNetworkService(); |
| } |
| |
| // static |
| base::DeferredSequencedTaskRunner* |
| ServiceManagerContext::GetAudioServiceRunner() { |
| static base::NoDestructor<scoped_refptr<base::DeferredSequencedTaskRunner>> |
| instance(new base::DeferredSequencedTaskRunner); |
| return (*instance).get(); |
| } |
| |
| void ServiceManagerContext::OnUnhandledServiceRequest( |
| const std::string& service_name, |
| service_manager::mojom::ServiceRequest request) { |
| if (service_name == device::mojom::kServiceName) { |
| // This task runner may be used by some device service implementation bits |
| // to interface with dbus client code, which in turn imposes some subtle |
| // thread affinity on the clients. We therefore require a single-thread |
| // runner. |
| scoped_refptr<base::SingleThreadTaskRunner> device_blocking_task_runner = |
| base::CreateSingleThreadTaskRunnerWithTraits( |
| {base::MayBlock(), base::TaskPriority::BEST_EFFORT}); |
| #if defined(OS_ANDROID) |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| base::android::ScopedJavaGlobalRef<jobject> java_nfc_delegate; |
| java_nfc_delegate.Reset(Java_ContentNfcDelegate_create(env)); |
| DCHECK(!java_nfc_delegate.is_null()); |
| |
| // See the comments on wake_lock_context_host.h, content_browser_client.h |
| // and ContentNfcDelegate.java respectively for comments on those |
| // parameters. |
| auto service = device::CreateDeviceService( |
| device_blocking_task_runner, service_manager_thread_task_runner_, |
| base::MakeRefCounted<DeviceServiceURLLoaderFactory>(), |
| GetContentClient()->browser()->GetGeolocationApiKey(), |
| GetContentClient()->browser()->ShouldUseGmsCoreGeolocationProvider(), |
| base::BindRepeating(&WakeLockContextHost::GetNativeViewForContext), |
| base::BindRepeating( |
| &ContentBrowserClient::OverrideSystemLocationProvider, |
| base::Unretained(GetContentClient()->browser())), |
| std::move(java_nfc_delegate), std::move(request)); |
| #else |
| auto service = device::CreateDeviceService( |
| device_blocking_task_runner, service_manager_thread_task_runner_, |
| base::MakeRefCounted<DeviceServiceURLLoaderFactory>(), |
| GetContentClient()->browser()->GetGeolocationApiKey(), |
| base::BindRepeating( |
| &ContentBrowserClient::OverrideSystemLocationProvider, |
| base::Unretained(GetContentClient()->browser())), |
| std::move(request)); |
| #endif |
| service_manager::Service::RunAsyncUntilTermination(std::move(service)); |
| return; |
| } |
| |
| GetContentClient()->browser()->HandleServiceRequest(service_name, |
| std::move(request)); |
| } |
| |
| } // namespace content |