Browse Source

refactor: process event emitting for sandboxed renderers (#37109)

Co-authored-by: Milan Burda <[email protected]>
Milan Burda 2 years ago
parent
commit
446c7809cc

+ 6 - 21
lib/sandboxed_renderer/init.ts

@@ -41,25 +41,15 @@ const loadableModules = new Map<string, Function>([
   ['url', () => require('url')]
 ]);
 
-// ElectronSandboxedRendererClient will look for the "lifecycle" hidden object when
-v8Util.setHiddenValue(global, 'lifecycle', {
-  onLoaded () {
-    (process as events.EventEmitter).emit('loaded');
-  },
-  onExit () {
-    (process as events.EventEmitter).emit('exit');
-  },
-  onDocumentStart () {
-    (process as events.EventEmitter).emit('document-start');
-  },
-  onDocumentEnd () {
-    (process as events.EventEmitter).emit('document-end');
-  }
-});
-
 // Pass different process object to the preload script.
 const preloadProcess: NodeJS.Process = new EventEmitter() as any;
 
+// InvokeEmitProcessEvent in ElectronSandboxedRendererClient will look for this
+v8Util.setHiddenValue(global, 'emit-process-event', (event: string) => {
+  (process as events.EventEmitter).emit(event);
+  (preloadProcess as events.EventEmitter).emit(event);
+});
+
 Object.assign(preloadProcess, binding.process);
 Object.assign(preloadProcess, processProps);
 
@@ -79,11 +69,6 @@ Object.defineProperty(preloadProcess, 'noDeprecation', {
   }
 });
 
-process.on('loaded', () => (preloadProcess as events.EventEmitter).emit('loaded'));
-process.on('exit', () => (preloadProcess as events.EventEmitter).emit('exit'));
-(process as events.EventEmitter).on('document-start', () => (preloadProcess as events.EventEmitter).emit('document-start'));
-(process as events.EventEmitter).on('document-end', () => (preloadProcess as events.EventEmitter).emit('document-end'));
-
 // This is the `require` function that will be visible to the preload script
 function preloadRequire (module: string) {
   if (loadedModules.has(module)) {

+ 38 - 44
shell/renderer/electron_sandboxed_renderer_client.cc

@@ -4,11 +4,13 @@
 
 #include "shell/renderer/electron_sandboxed_renderer_client.h"
 
+#include <iterator>
 #include <tuple>
 #include <vector>
 
 #include "base/base_paths.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
 #include "base/process/process_handle.h"
@@ -33,7 +35,7 @@ namespace electron {
 
 namespace {
 
-const char kLifecycleKey[] = "lifecycle";
+const char kEmitProcessEventKey[] = "emit-process-event";
 const char kModuleCacheKey[] = "native-module-cache";
 
 v8::Local<v8::Object> GetModuleCache(v8::Isolate* isolate) {
@@ -94,27 +96,25 @@ double Uptime() {
       .InSecondsF();
 }
 
-void InvokeHiddenCallback(v8::Handle<v8::Context> context,
-                          const std::string& hidden_key,
-                          const std::string& callback_name) {
+void InvokeEmitProcessEvent(v8::Handle<v8::Context> context,
+                            const std::string& event_name) {
   auto* isolate = context->GetIsolate();
-  auto binding_key =
-      gin::ConvertToV8(isolate, hidden_key)->ToString(context).ToLocalChecked();
+  // set by sandboxed_renderer/init.js
+  auto binding_key = gin::ConvertToV8(isolate, kEmitProcessEventKey)
+                         ->ToString(context)
+                         .ToLocalChecked();
   auto private_binding_key = v8::Private::ForApi(isolate, binding_key);
   auto global_object = context->Global();
-  v8::Local<v8::Value> value;
-  if (!global_object->GetPrivate(context, private_binding_key).ToLocal(&value))
+  v8::Local<v8::Value> callback_value;
+  if (!global_object->GetPrivate(context, private_binding_key)
+           .ToLocal(&callback_value))
     return;
-  if (value.IsEmpty() || !value->IsObject())
+  if (callback_value.IsEmpty() || !callback_value->IsFunction())
     return;
-  auto binding = value->ToObject(context).ToLocalChecked();
-  auto callback_key = gin::ConvertToV8(isolate, callback_name)
-                          ->ToString(context)
-                          .ToLocalChecked();
-  auto callback_value = binding->Get(context, callback_key).ToLocalChecked();
-  DCHECK(callback_value->IsFunction());  // set by sandboxed_renderer/init.js
   auto callback = callback_value.As<v8::Function>();
-  std::ignore = callback->Call(context, binding, 0, nullptr);
+  v8::Local<v8::Value> args[] = {gin::ConvertToV8(isolate, event_name)};
+  std::ignore =
+      callback->Call(context, callback, std::size(args), std::data(args));
 }
 
 }  // namespace
@@ -158,37 +158,13 @@ void ElectronSandboxedRendererClient::RenderFrameCreated(
 void ElectronSandboxedRendererClient::RunScriptsAtDocumentStart(
     content::RenderFrame* render_frame) {
   RendererClientBase::RunScriptsAtDocumentStart(render_frame);
-  if (injected_frames_.find(render_frame) == injected_frames_.end())
-    return;
-
-  auto* isolate = blink::MainThreadIsolate();
-  v8::HandleScope handle_scope(isolate);
-  v8::Local<v8::Context> context =
-      GetContext(render_frame->GetWebFrame(), isolate);
-  gin_helper::MicrotasksScope microtasks_scope(
-      isolate, context->GetMicrotaskQueue(),
-      v8::MicrotasksScope::kDoNotRunMicrotasks);
-  v8::Context::Scope context_scope(context);
-
-  InvokeHiddenCallback(context, kLifecycleKey, "onDocumentStart");
+  EmitProcessEvent(render_frame, "document-start");
 }
 
 void ElectronSandboxedRendererClient::RunScriptsAtDocumentEnd(
     content::RenderFrame* render_frame) {
   RendererClientBase::RunScriptsAtDocumentEnd(render_frame);
-  if (injected_frames_.find(render_frame) == injected_frames_.end())
-    return;
-
-  auto* isolate = blink::MainThreadIsolate();
-  v8::HandleScope handle_scope(isolate);
-  v8::Local<v8::Context> context =
-      GetContext(render_frame->GetWebFrame(), isolate);
-  gin_helper::MicrotasksScope microtasks_scope(
-      isolate, context->GetMicrotaskQueue(),
-      v8::MicrotasksScope::kDoNotRunMicrotasks);
-  v8::Context::Scope context_scope(context);
-
-  InvokeHiddenCallback(context, kLifecycleKey, "onDocumentEnd");
+  EmitProcessEvent(render_frame, "document-end");
 }
 
 void ElectronSandboxedRendererClient::DidCreateScriptContext(
@@ -219,7 +195,7 @@ void ElectronSandboxedRendererClient::DidCreateScriptContext(
 
   v8::HandleScope handle_scope(isolate);
   v8::Context::Scope context_scope(context);
-  InvokeHiddenCallback(context, kLifecycleKey, "onLoaded");
+  InvokeEmitProcessEvent(context, "loaded");
 }
 
 void ElectronSandboxedRendererClient::WillReleaseScriptContext(
@@ -234,7 +210,25 @@ void ElectronSandboxedRendererClient::WillReleaseScriptContext(
       v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::HandleScope handle_scope(isolate);
   v8::Context::Scope context_scope(context);
-  InvokeHiddenCallback(context, kLifecycleKey, "onExit");
+  InvokeEmitProcessEvent(context, "exit");
+}
+
+void ElectronSandboxedRendererClient::EmitProcessEvent(
+    content::RenderFrame* render_frame,
+    const char* event_name) {
+  if (injected_frames_.find(render_frame) == injected_frames_.end())
+    return;
+
+  auto* isolate = blink::MainThreadIsolate();
+  v8::HandleScope handle_scope(isolate);
+  v8::Local<v8::Context> context =
+      GetContext(render_frame->GetWebFrame(), isolate);
+  gin_helper::MicrotasksScope microtasks_scope(
+      isolate, context->GetMicrotaskQueue(),
+      v8::MicrotasksScope::kDoNotRunMicrotasks);
+  v8::Context::Scope context_scope(context);
+
+  InvokeEmitProcessEvent(context, event_name);
 }
 
 }  // namespace electron

+ 3 - 0
shell/renderer/electron_sandboxed_renderer_client.h

@@ -45,6 +45,9 @@ class ElectronSandboxedRendererClient : public RendererClientBase {
   void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) override;
 
  private:
+  void EmitProcessEvent(content::RenderFrame* render_frame,
+                        const char* event_name);
+
   std::unique_ptr<base::ProcessMetrics> metrics_;
 
   // Getting main script context from web frame would lazily initializes