node_service.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright (c) 2022 Microsoft, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/services/node/node_service.h"
  5. #include <sstream>
  6. #include <utility>
  7. #include "base/command_line.h"
  8. #include "base/no_destructor.h"
  9. #include "base/strings/utf_string_conversions.h"
  10. #include "electron/mas.h"
  11. #include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
  12. #include "services/network/public/mojom/host_resolver.mojom.h"
  13. #include "services/network/public/mojom/network_context.mojom.h"
  14. #include "shell/browser/javascript_environment.h"
  15. #include "shell/common/api/electron_bindings.h"
  16. #include "shell/common/gin_converters/file_path_converter.h"
  17. #include "shell/common/gin_helper/dictionary.h"
  18. #include "shell/common/node_bindings.h"
  19. #include "shell/common/node_includes.h"
  20. #include "shell/services/node/parent_port.h"
  21. #if !IS_MAS_BUILD()
  22. #include "shell/common/crash_keys.h"
  23. #endif
  24. namespace electron {
  25. mojo::Remote<node::mojom::NodeServiceClient> g_client_remote;
  26. void V8FatalErrorCallback(const char* location, const char* message) {
  27. if (g_client_remote.is_bound() && g_client_remote.is_connected()) {
  28. auto* isolate = v8::Isolate::TryGetCurrent();
  29. std::ostringstream outstream;
  30. node::GetNodeReport(isolate, message, location,
  31. v8::Local<v8::Object>() /* error */, outstream);
  32. g_client_remote->OnV8FatalError(location, outstream.str());
  33. }
  34. #if !IS_MAS_BUILD()
  35. electron::crash_keys::SetCrashKey("electron.v8-fatal.message", message);
  36. electron::crash_keys::SetCrashKey("electron.v8-fatal.location", location);
  37. #endif
  38. volatile int* zero = nullptr;
  39. *zero = 0;
  40. }
  41. URLLoaderBundle::URLLoaderBundle() = default;
  42. URLLoaderBundle::~URLLoaderBundle() = default;
  43. URLLoaderBundle* URLLoaderBundle::GetInstance() {
  44. static base::NoDestructor<URLLoaderBundle> instance;
  45. return instance.get();
  46. }
  47. void URLLoaderBundle::SetURLLoaderFactory(
  48. mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_factory,
  49. mojo::Remote<network::mojom::HostResolver> host_resolver,
  50. bool use_network_observer_from_url_loader_factory) {
  51. factory_ = network::SharedURLLoaderFactory::Create(
  52. std::make_unique<network::WrapperPendingSharedURLLoaderFactory>(
  53. std::move(pending_factory)));
  54. host_resolver_ = std::move(host_resolver);
  55. should_use_network_observer_from_url_loader_factory_ =
  56. use_network_observer_from_url_loader_factory;
  57. }
  58. scoped_refptr<network::SharedURLLoaderFactory>
  59. URLLoaderBundle::GetSharedURLLoaderFactory() {
  60. return factory_;
  61. }
  62. network::mojom::HostResolver* URLLoaderBundle::GetHostResolver() {
  63. DCHECK(host_resolver_);
  64. return host_resolver_.get();
  65. }
  66. bool URLLoaderBundle::ShouldUseNetworkObserverfromURLLoaderFactory() const {
  67. return should_use_network_observer_from_url_loader_factory_;
  68. }
  69. NodeService::NodeService(
  70. mojo::PendingReceiver<node::mojom::NodeService> receiver)
  71. : node_bindings_{NodeBindings::Create(
  72. NodeBindings::BrowserEnvironment::kUtility)},
  73. electron_bindings_{
  74. std::make_unique<ElectronBindings>(node_bindings_->uv_loop())} {
  75. if (receiver.is_valid())
  76. receiver_.Bind(std::move(receiver));
  77. }
  78. NodeService::~NodeService() {
  79. if (!node_env_stopped_) {
  80. node_env_->set_trace_sync_io(false);
  81. js_env_->DestroyMicrotasksRunner();
  82. node::Stop(node_env_.get(), node::StopFlags::kDoNotTerminateIsolate);
  83. }
  84. if (g_client_remote.is_bound()) {
  85. g_client_remote.reset();
  86. }
  87. }
  88. void NodeService::Initialize(
  89. node::mojom::NodeServiceParamsPtr params,
  90. mojo::PendingRemote<node::mojom::NodeServiceClient> client_pending_remote) {
  91. if (NodeBindings::IsInitialized())
  92. return;
  93. g_client_remote.Bind(std::move(client_pending_remote));
  94. g_client_remote.reset_on_disconnect();
  95. ParentPort::GetInstance()->Initialize(std::move(params->port));
  96. URLLoaderBundle::GetInstance()->SetURLLoaderFactory(
  97. std::move(params->url_loader_factory),
  98. mojo::Remote(std::move(params->host_resolver)),
  99. params->use_network_observer_from_url_loader_factory);
  100. js_env_ = std::make_unique<JavascriptEnvironment>(node_bindings_->uv_loop());
  101. v8::HandleScope scope(js_env_->isolate());
  102. node_bindings_->Initialize(js_env_->isolate()->GetCurrentContext());
  103. // Append program path for process.argv0
  104. auto program = base::CommandLine::ForCurrentProcess()->GetProgram();
  105. #if defined(OS_WIN)
  106. params->args.insert(params->args.begin(), base::WideToUTF8(program.value()));
  107. #else
  108. params->args.insert(params->args.begin(), program.value());
  109. #endif
  110. // Create the global environment.
  111. node_env_ = node_bindings_->CreateEnvironment(
  112. js_env_->isolate()->GetCurrentContext(), js_env_->platform(),
  113. js_env_->max_young_generation_size_in_bytes(), params->args,
  114. params->exec_args);
  115. // Override the default handler set by NodeBindings.
  116. node_env_->isolate()->SetFatalErrorHandler(V8FatalErrorCallback);
  117. node::SetProcessExitHandler(
  118. node_env_.get(), [this](node::Environment* env, int exit_code) {
  119. // Destroy node platform.
  120. env->set_trace_sync_io(false);
  121. js_env_->DestroyMicrotasksRunner();
  122. node::Stop(env, node::StopFlags::kDoNotTerminateIsolate);
  123. node_env_stopped_ = true;
  124. receiver_.ResetWithReason(exit_code, "process_exit_termination");
  125. });
  126. node_env_->set_trace_sync_io(node_env_->options()->trace_sync_io);
  127. // We do not want to crash the utility process on unhandled rejections.
  128. node_env_->options()->unhandled_rejections = "warn-with-error-code";
  129. // Add Electron extended APIs.
  130. electron_bindings_->BindTo(node_env_->isolate(), node_env_->process_object());
  131. // Add entry script to process object.
  132. gin_helper::Dictionary process(node_env_->isolate(),
  133. node_env_->process_object());
  134. process.SetHidden("_serviceStartupScript", params->script);
  135. // Setup microtask runner.
  136. js_env_->CreateMicrotasksRunner();
  137. // Wrap the uv loop with global env.
  138. node_bindings_->set_uv_env(node_env_.get());
  139. // LoadEnvironment should be called after setting up
  140. // JavaScriptEnvironment including the microtask runner
  141. // since this call will start compilation and execution
  142. // of the entry script. If there is an uncaught exception
  143. // the exit handler set above will be triggered and it expects
  144. // both Node Env and JavaScriptEnvironment are setup to perform
  145. // a clean shutdown of this process.
  146. node_bindings_->LoadEnvironment(node_env_.get());
  147. // Run entry script.
  148. node_bindings_->PrepareEmbedThread();
  149. node_bindings_->StartPolling();
  150. }
  151. } // namespace electron