| // 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 "ios/web/service_manager_context.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/feature_list.h" |
| #include "base/json/json_reader.h" |
| #include "base/lazy_instance.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/process/process_handle.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "ios/web/grit/ios_web_resources.h" |
| #include "ios/web/public/service_manager_connection.h" |
| #include "ios/web/public/service_names.mojom.h" |
| #include "ios/web/public/web_client.h" |
| #include "ios/web/public/web_thread.h" |
| #include "ios/web/service_manager_connection_impl.h" |
| #include "services/catalog/manifest_provider.h" |
| #include "services/catalog/public/cpp/manifest_parsing_util.h" |
| #include "services/catalog/public/interfaces/constants.mojom.h" |
| #include "services/service_manager/connect_params.h" |
| #include "services/service_manager/embedder/manifest_utils.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| #include "services/service_manager/public/cpp/service.h" |
| #include "services/service_manager/public/interfaces/service.mojom.h" |
| #include "services/service_manager/runner/common/client_util.h" |
| #include "services/service_manager/service_manager.h" |
| |
| namespace web { |
| |
| namespace { |
| |
| struct ManifestInfo { |
| const char* name; |
| int resource_id; |
| }; |
| |
| // A ManifestProvider which resolves application names to builtin manifest |
| // resources for the catalog service to consume. |
| class BuiltinManifestProvider : public catalog::ManifestProvider { |
| public: |
| BuiltinManifestProvider() {} |
| ~BuiltinManifestProvider() override {} |
| |
| void AddServiceManifest(base::StringPiece name, int resource_id) { |
| std::string contents = |
| GetWebClient() |
| ->GetDataResource(resource_id, ui::ScaleFactor::SCALE_FACTOR_NONE) |
| .as_string(); |
| DCHECK(!contents.empty()); |
| |
| std::unique_ptr<base::Value> manifest_value = |
| base::JSONReader::Read(contents); |
| DCHECK(manifest_value); |
| |
| std::unique_ptr<base::Value> overlay_value = |
| GetWebClient()->GetServiceManifestOverlay(name); |
| |
| service_manager::MergeManifestWithOverlay(manifest_value.get(), |
| overlay_value.get()); |
| auto insertion_result = manifests_.insert( |
| std::make_pair(name.as_string(), std::move(manifest_value))); |
| DCHECK(insertion_result.second) << "Duplicate manifest entry: " << name; |
| } |
| |
| private: |
| // catalog::ManifestProvider: |
| std::unique_ptr<base::Value> GetManifest(const std::string& name) override { |
| auto it = manifests_.find(name); |
| return it != manifests_.end() ? it->second->CreateDeepCopy() : nullptr; |
| } |
| |
| std::map<std::string, std::unique_ptr<base::Value>> manifests_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BuiltinManifestProvider); |
| }; |
| |
| } // namespace |
| |
| // State which lives on the IO thread and drives the ServiceManager. |
| class ServiceManagerContext::InProcessServiceManagerContext |
| : public base::RefCountedThreadSafe<InProcessServiceManagerContext> { |
| public: |
| InProcessServiceManagerContext() {} |
| |
| void Start( |
| service_manager::mojom::ServicePtrInfo packaged_services_service_info, |
| std::unique_ptr<BuiltinManifestProvider> manifest_provider) { |
| WebThread::GetTaskRunnerForThread(WebThread::IO) |
| ->PostTask(FROM_HERE, |
| base::Bind(&InProcessServiceManagerContext::StartOnIOThread, |
| this, base::Passed(&manifest_provider), |
| base::Passed(&packaged_services_service_info))); |
| } |
| |
| void ShutDown() { |
| WebThread::GetTaskRunnerForThread(WebThread::IO) |
| ->PostTask( |
| FROM_HERE, |
| base::Bind(&InProcessServiceManagerContext::ShutDownOnIOThread, |
| this)); |
| } |
| |
| private: |
| friend class base::RefCountedThreadSafe<InProcessServiceManagerContext>; |
| |
| ~InProcessServiceManagerContext() {} |
| |
| // Creates the ServiceManager and registers the packaged services service |
| // with it, connecting the other end of the packaged services serviceto |
| // |packaged_services_service_info|. |
| void StartOnIOThread( |
| std::unique_ptr<BuiltinManifestProvider> manifest_provider, |
| service_manager::mojom::ServicePtrInfo packaged_services_service_info) { |
| manifest_provider_ = std::move(manifest_provider); |
| service_manager_ = base::MakeUnique<service_manager::ServiceManager>( |
| nullptr, nullptr, manifest_provider_.get()); |
| |
| 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::mojom::kRootUserID), |
| std::move(packaged_services_service), nullptr); |
| } |
| |
| void ShutDownOnIOThread() { |
| service_manager_.reset(); |
| manifest_provider_.reset(); |
| } |
| |
| std::unique_ptr<BuiltinManifestProvider> manifest_provider_; |
| std::unique_ptr<service_manager::ServiceManager> service_manager_; |
| |
| DISALLOW_COPY_AND_ASSIGN(InProcessServiceManagerContext); |
| }; |
| |
| ServiceManagerContext::ServiceManagerContext() { |
| service_manager::mojom::ServiceRequest packaged_services_request; |
| DCHECK(!service_manager::ServiceManagerIsRemote()); |
| std::unique_ptr<BuiltinManifestProvider> manifest_provider = |
| base::MakeUnique<BuiltinManifestProvider>(); |
| |
| const std::array<ManifestInfo, 3> manifests = {{ |
| {mojom::kBrowserServiceName, IDR_MOJO_WEB_BROWSER_MANIFEST}, |
| {mojom::kPackagedServicesServiceName, |
| IDR_MOJO_WEB_PACKAGED_SERVICES_MANIFEST}, |
| {catalog::mojom::kServiceName, IDR_MOJO_CATALOG_MANIFEST}, |
| }}; |
| for (const ManifestInfo& manifest : manifests) { |
| manifest_provider->AddServiceManifest(manifest.name, manifest.resource_id); |
| } |
| in_process_context_ = base::MakeRefCounted<InProcessServiceManagerContext>(); |
| |
| service_manager::mojom::ServicePtr packaged_services_service; |
| packaged_services_request = mojo::MakeRequest(&packaged_services_service); |
| in_process_context_->Start(packaged_services_service.PassInterface(), |
| std::move(manifest_provider)); |
| |
| packaged_services_connection_ = ServiceManagerConnection::Create( |
| std::move(packaged_services_request), |
| WebThread::GetTaskRunnerForThread(WebThread::IO)); |
| |
| service_manager::mojom::ServicePtr root_browser_service; |
| ServiceManagerConnection::Set(ServiceManagerConnection::Create( |
| mojo::MakeRequest(&root_browser_service), |
| WebThread::GetTaskRunnerForThread(WebThread::IO))); |
| auto* browser_connection = ServiceManagerConnection::Get(); |
| |
| service_manager::mojom::PIDReceiverPtr pid_receiver; |
| packaged_services_connection_->GetConnector()->StartService( |
| service_manager::Identity(mojom::kBrowserServiceName, |
| service_manager::mojom::kRootUserID), |
| std::move(root_browser_service), mojo::MakeRequest(&pid_receiver)); |
| pid_receiver->SetPID(base::GetCurrentProcId()); |
| |
| // Embed any services from //ios/web here. |
| |
| // Embed services from the client of //ios/web. |
| WebClient::StaticServiceMap services; |
| GetWebClient()->RegisterServices(&services); |
| for (const auto& entry : services) { |
| packaged_services_connection_->AddEmbeddedService(entry.first, |
| entry.second); |
| } |
| |
| packaged_services_connection_->Start(); |
| |
| browser_connection->Start(); |
| } |
| |
| ServiceManagerContext::~ServiceManagerContext() { |
| // 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:ios_web_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::Get()) |
| ServiceManagerConnection::Destroy(); |
| } |
| |
| } // namespace web |