web_content_runner.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "fuchsia_web/runners/common/web_content_runner.h"
  5. #include <fuchsia/sys/cpp/fidl.h>
  6. #include <lib/fdio/directory.h>
  7. #include <lib/fidl/cpp/binding_set.h>
  8. #include <lib/sys/cpp/component_context.h>
  9. #include <lib/sys/cpp/service_directory.h>
  10. #include <utility>
  11. #include "base/bind.h"
  12. #include "base/command_line.h"
  13. #include "base/files/file.h"
  14. #include "base/files/file_util.h"
  15. #include "base/fuchsia/file_utils.h"
  16. #include "base/fuchsia/fuchsia_logging.h"
  17. #include "base/fuchsia/process_context.h"
  18. #include "base/fuchsia/scoped_service_binding.h"
  19. #include "base/fuchsia/startup_context.h"
  20. #include "base/logging.h"
  21. #include "base/strings/stringprintf.h"
  22. #include "fuchsia_web/runners/buildflags.h"
  23. #include "fuchsia_web/runners/common/web_component.h"
  24. #include "fuchsia_web/webinstance_host/web_instance_host.h"
  25. #include "url/gurl.h"
  26. namespace {
  27. bool IsChannelClosed(const zx::channel& channel) {
  28. zx_signals_t observed = 0u;
  29. zx_status_t status =
  30. channel.wait_one(ZX_ERR_PEER_CLOSED, zx::time(), &observed);
  31. return status == ZX_OK;
  32. }
  33. std::string CreateUniqueComponentName() {
  34. static int last_component_id_ = 0;
  35. return base::StringPrintf("web-component:%d", ++last_component_id_);
  36. }
  37. } // namespace
  38. WebContentRunner::WebInstanceConfig::WebInstanceConfig()
  39. : extra_args(base::CommandLine::NO_PROGRAM) {}
  40. WebContentRunner::WebInstanceConfig::~WebInstanceConfig() = default;
  41. WebContentRunner::WebInstanceConfig::WebInstanceConfig(WebInstanceConfig&&) =
  42. default;
  43. WebContentRunner::WebInstanceConfig&
  44. WebContentRunner::WebInstanceConfig::operator=(WebInstanceConfig&&) = default;
  45. WebContentRunner::WebContentRunner(
  46. WebInstanceHost* web_instance_host,
  47. GetWebInstanceConfigCallback get_web_instance_config_callback)
  48. : web_instance_host_(web_instance_host),
  49. get_web_instance_config_callback_(
  50. std::move(get_web_instance_config_callback)) {
  51. DCHECK(web_instance_host_);
  52. DCHECK(get_web_instance_config_callback_);
  53. }
  54. WebContentRunner::WebContentRunner(WebInstanceHost* web_instance_host,
  55. WebInstanceConfig web_instance_config)
  56. : web_instance_host_(web_instance_host) {
  57. CreateWebInstanceAndContext(std::move(web_instance_config));
  58. }
  59. WebContentRunner::~WebContentRunner() = default;
  60. fidl::InterfaceRequestHandler<fuchsia::web::FrameHost>
  61. WebContentRunner::GetFrameHostRequestHandler() {
  62. return [this](fidl::InterfaceRequest<fuchsia::web::FrameHost> request) {
  63. EnsureWebInstanceAndContext();
  64. fdio_service_connect_at(web_instance_services_.channel().get(),
  65. fuchsia::web::FrameHost::Name_,
  66. request.TakeChannel().release());
  67. };
  68. }
  69. void WebContentRunner::CreateFrameWithParams(
  70. fuchsia::web::CreateFrameParams params,
  71. fidl::InterfaceRequest<fuchsia::web::Frame> request) {
  72. EnsureWebInstanceAndContext();
  73. context_->CreateFrameWithParams(std::move(params), std::move(request));
  74. }
  75. void WebContentRunner::StartComponent(
  76. fuchsia::sys::Package package,
  77. fuchsia::sys::StartupInfo startup_info,
  78. fidl::InterfaceRequest<fuchsia::sys::ComponentController>
  79. controller_request) {
  80. GURL url(package.resolved_url);
  81. if (!url.is_valid()) {
  82. LOG(ERROR) << "Rejected invalid URL: " << url;
  83. return;
  84. }
  85. std::unique_ptr<WebComponent> component = std::make_unique<WebComponent>(
  86. CreateUniqueComponentName(), this,
  87. std::make_unique<base::StartupContext>(std::move(startup_info)),
  88. std::move(controller_request));
  89. #if BUILDFLAG(WEB_RUNNER_REMOTE_DEBUGGING_PORT) != 0
  90. component->EnableRemoteDebugging();
  91. #endif
  92. component->StartComponent();
  93. component->LoadUrl(url, std::vector<fuchsia::net::http::Header>());
  94. RegisterComponent(std::move(component));
  95. }
  96. WebComponent* WebContentRunner::GetAnyComponent() {
  97. if (components_.empty())
  98. return nullptr;
  99. return components_.begin()->get();
  100. }
  101. void WebContentRunner::DestroyComponent(WebComponent* component) {
  102. components_.erase(components_.find(component));
  103. if (components_.empty() && on_empty_callback_)
  104. std::move(on_empty_callback_).Run();
  105. }
  106. void WebContentRunner::RegisterComponent(
  107. std::unique_ptr<WebComponent> component) {
  108. components_.insert(std::move(component));
  109. }
  110. void WebContentRunner::SetOnEmptyCallback(base::OnceClosure on_empty) {
  111. on_empty_callback_ = std::move(on_empty);
  112. }
  113. void WebContentRunner::DestroyWebContext() {
  114. DCHECK(get_web_instance_config_callback_);
  115. context_ = nullptr;
  116. }
  117. void WebContentRunner::EnsureWebInstanceAndContext() {
  118. // Synchronously check whether the web.Context channel has closed, to reduce
  119. // the chance of issuing CreateFrameWithParams() to an already-closed channel.
  120. // This avoids potentially flaking a test - see crbug.com/1173418.
  121. if (context_ && IsChannelClosed(context_.channel()))
  122. context_.Unbind();
  123. if (!context_) {
  124. DCHECK(get_web_instance_config_callback_);
  125. CreateWebInstanceAndContext(get_web_instance_config_callback_.Run());
  126. }
  127. }
  128. void WebContentRunner::CreateWebInstanceAndContext(WebInstanceConfig config) {
  129. web_instance_host_->CreateInstanceForContextWithCopiedArgs(
  130. std::move(config.params), web_instance_services_.NewRequest(),
  131. config.extra_args);
  132. zx_status_t result = fdio_service_connect_at(
  133. web_instance_services_.channel().get(), fuchsia::web::Context::Name_,
  134. context_.NewRequest().TakeChannel().release());
  135. ZX_LOG_IF(ERROR, result != ZX_OK, result)
  136. << "fdio_service_connect_at(web.Context)";
  137. context_.set_error_handler([](zx_status_t status) {
  138. ZX_LOG(ERROR, status) << "Connection to web.Context lost.";
  139. });
  140. }