Browse Source

fix: don't hang on SendSync if ElectronBrowser receiver is destroyed (6-0-x) (#20547)

loc 5 years ago
parent
commit
6a07825c47
1 changed files with 40 additions and 11 deletions
  1. 40 11
      atom/renderer/api/atom_api_renderer_ipc.cc

+ 40 - 11
atom/renderer/api/atom_api_renderer_ipc.cc

@@ -82,6 +82,7 @@ class IPCRenderer : public mate::Wrappable<IPCRenderer> {
                        bool internal,
                        const std::string& channel,
                        const base::ListValue& arguments) {
+    std::string error;
     base::Value result;
 
     // A task is posted to a separate thread to execute the request so that
@@ -98,43 +99,71 @@ class IPCRenderer : public mate::Wrappable<IPCRenderer> {
     // interface.
     auto interface_info = electron_browser_ptr_.PassInterface();
     task_runner->PostTask(
-        FROM_HERE, base::BindOnce(&IPCRenderer::SendMessageSyncOnWorkerThread,
-                                  base::Unretained(&interface_info),
-                                  base::Unretained(&response_received_event),
-                                  base::Unretained(&result), internal, channel,
-                                  base::Unretained(&arguments)));
+        FROM_HERE,
+        base::BindOnce(&IPCRenderer::SendMessageSyncOnWorkerThread,
+                       base::Unretained(this),
+                       base::Unretained(&interface_info),
+                       base::Unretained(&response_received_event),
+                       base::Unretained(&result), internal, channel,
+                       base::Unretained(&arguments), base::Unretained(&error)));
     response_received_event.Wait();
     electron_browser_ptr_.Bind(std::move(interface_info));
+    if (!error.empty()) {
+      args->ThrowError(error);
+    }
     return result;
   }
 
  private:
-  static void SendMessageSyncOnWorkerThread(
+  void SendMessageSyncOnWorkerThread(
       atom::mojom::ElectronBrowserPtrInfo* interface_info,
       base::WaitableEvent* event,
       base::Value* result,
       bool internal,
       const std::string& channel,
-      const base::ListValue* arguments) {
+      const base::ListValue* arguments,
+      std::string* error) {
     atom::mojom::ElectronBrowserPtr browser_ptr(std::move(*interface_info));
-    browser_ptr->MessageSync(
+    electron_browser_ptr_ = std::move(browser_ptr);
+
+    electron_browser_ptr_.set_connection_error_handler(
+        base::BindOnce(&IPCRenderer::HandleMojoConnectionErrorOnWorkerThread,
+                       base::Unretained(&electron_browser_ptr_),
+                       base::Unretained(interface_info),
+                       base::Unretained(event), base::Unretained(error)));
+    electron_browser_ptr_->MessageSync(
         internal, channel, arguments->Clone(),
         base::BindOnce(&IPCRenderer::ReturnSyncResponseToMainThread,
-                       std::move(browser_ptr), base::Unretained(interface_info),
+                       base::Unretained(&electron_browser_ptr_),
+                       base::Unretained(interface_info),
                        base::Unretained(event), base::Unretained(result)));
   }
   static void ReturnSyncResponseToMainThread(
-      atom::mojom::ElectronBrowserPtr ptr,
+      atom::mojom::ElectronBrowserPtr* ptr,
       atom::mojom::ElectronBrowserPtrInfo* interface_info,
       base::WaitableEvent* event,
       base::Value* result,
       base::Value response) {
     *result = std::move(response);
-    *interface_info = ptr.PassInterface();
+    *interface_info = ptr->PassInterface();
+    event->Signal();
+  }
+  // If the other end of the message pipe disconnects, ensure we don't hang the
+  // main thread forever.
+  static void HandleMojoConnectionErrorOnWorkerThread(
+      atom::mojom::ElectronBrowserPtr* ptr,
+      atom::mojom::ElectronBrowserPtrInfo* interface_info,
+      base::WaitableEvent* event,
+      std::string* error) {
+    LOG(INFO) << "Mojo connection interuppted, likely due to the Mojo receiver "
+                 "process crashing.";
+    *error = "IPC connection fatally interrupted.";
+    *interface_info = ptr->PassInterface();
     event->Signal();
   }
 
   atom::mojom::ElectronBrowserPtr electron_browser_ptr_;
+  atom::mojom::ElectronBrowserPtr worker_thread_electron_browser_ptr_;
 };
 
 void Initialize(v8::Local<v8::Object> exports,