node_service.cc 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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 <utility>
  6. #include "base/command_line.h"
  7. #include "base/strings/utf_string_conversions.h"
  8. #include "shell/browser/javascript_environment.h"
  9. #include "shell/common/api/electron_bindings.h"
  10. #include "shell/common/gin_converters/file_path_converter.h"
  11. #include "shell/common/gin_helper/dictionary.h"
  12. #include "shell/common/node_bindings.h"
  13. #include "shell/common/node_includes.h"
  14. #include "shell/services/node/parent_port.h"
  15. namespace electron {
  16. NodeService::NodeService(
  17. mojo::PendingReceiver<node::mojom::NodeService> receiver)
  18. : node_bindings_{NodeBindings::Create(
  19. NodeBindings::BrowserEnvironment::kUtility)},
  20. electron_bindings_{
  21. std::make_unique<ElectronBindings>(node_bindings_->uv_loop())} {
  22. if (receiver.is_valid())
  23. receiver_.Bind(std::move(receiver));
  24. }
  25. NodeService::~NodeService() {
  26. if (!node_env_stopped_) {
  27. node_env_->set_trace_sync_io(false);
  28. js_env_->DestroyMicrotasksRunner();
  29. node::Stop(node_env_.get(), node::StopFlags::kDoNotTerminateIsolate);
  30. }
  31. }
  32. void NodeService::Initialize(node::mojom::NodeServiceParamsPtr params) {
  33. if (NodeBindings::IsInitialized())
  34. return;
  35. ParentPort::GetInstance()->Initialize(std::move(params->port));
  36. js_env_ = std::make_unique<JavascriptEnvironment>(node_bindings_->uv_loop());
  37. v8::HandleScope scope(js_env_->isolate());
  38. node_bindings_->Initialize(js_env_->isolate()->GetCurrentContext());
  39. // Append program path for process.argv0
  40. auto program = base::CommandLine::ForCurrentProcess()->GetProgram();
  41. #if defined(OS_WIN)
  42. params->args.insert(params->args.begin(), base::WideToUTF8(program.value()));
  43. #else
  44. params->args.insert(params->args.begin(), program.value());
  45. #endif
  46. // Create the global environment.
  47. node_env_ = node_bindings_->CreateEnvironment(
  48. js_env_->isolate()->GetCurrentContext(), js_env_->platform(),
  49. params->args, params->exec_args);
  50. node::SetProcessExitHandler(
  51. node_env_.get(), [this](node::Environment* env, int exit_code) {
  52. // Destroy node platform.
  53. env->set_trace_sync_io(false);
  54. js_env_->DestroyMicrotasksRunner();
  55. node::Stop(env, node::StopFlags::kDoNotTerminateIsolate);
  56. node_env_stopped_ = true;
  57. receiver_.ResetWithReason(exit_code, "");
  58. });
  59. node_env_->set_trace_sync_io(node_env_->options()->trace_sync_io);
  60. // Add Electron extended APIs.
  61. electron_bindings_->BindTo(node_env_->isolate(), node_env_->process_object());
  62. // Add entry script to process object.
  63. gin_helper::Dictionary process(node_env_->isolate(),
  64. node_env_->process_object());
  65. process.SetHidden("_serviceStartupScript", params->script);
  66. // Setup microtask runner.
  67. js_env_->CreateMicrotasksRunner();
  68. // Wrap the uv loop with global env.
  69. node_bindings_->set_uv_env(node_env_.get());
  70. // LoadEnvironment should be called after setting up
  71. // JavaScriptEnvironment including the microtask runner
  72. // since this call will start compilation and execution
  73. // of the entry script. If there is an uncaught exception
  74. // the exit handler set above will be triggered and it expects
  75. // both Node Env and JavaScriptEnviroment are setup to perform
  76. // a clean shutdown of this process.
  77. node_bindings_->LoadEnvironment(node_env_.get());
  78. // Run entry script.
  79. node_bindings_->PrepareEmbedThread();
  80. node_bindings_->StartPolling();
  81. }
  82. } // namespace electron