refactor: use v8 serialization for ipc (#20214)
* refactor: use v8 serialization for ipc * cloning process.env doesn't work * serialize host objects by enumerating key/values * new serialization can handle NaN, Infinity, and undefined correctly * can't allocate v8 objects during GC * backport microtasks fix * fix compile * fix node_stream_loader reentrancy * update subframe spec to expect undefined instead of null * write undefined instead of crashing when serializing host objects * fix webview spec * fix download spec * buffers are transformed into uint8arrays * can't serialize promises * fix chrome.i18n.getMessage * fix devtools tests * fix zoom test * fix debug build * fix lint * update ipcRenderer tests * fix printToPDF test * update patch * remove accidentally re-added remote-side spec * wip * don't attempt to serialize host objects * jump through different hoops to set options.webContents sometimes * whoops * fix lint * clean up error-handling logic * fix memory leak * fix lint * convert host objects using old base::Value serialization * fix lint more * fall back to base::Value-based serialization * remove commented-out code * add docs to breaking-changes.md * Update breaking-changes.md * update ipcRenderer and WebContents docs * lint * use named values for format tag * save a memcpy for ~30% speedup * get rid of calls to ShallowClone * extra debugging for paranoia * d'oh, use the correct named tags * apparently msstl doesn't like this DCHECK * funny story about that DCHECK * disable remote-related functions when enable_remote_module = false * nits * use EnableIf to disable remote methods in mojom * fix include * review comments
This commit is contained in:
parent
c250cd6e7c
commit
2fad53e66b
38 changed files with 623 additions and 169 deletions
|
@ -1017,7 +1017,7 @@ void WebContents::OnElectronBrowserConnectionError() {
|
|||
|
||||
void WebContents::Message(bool internal,
|
||||
const std::string& channel,
|
||||
base::Value arguments) {
|
||||
blink::CloneableMessage arguments) {
|
||||
// webContents.emit('-ipc-message', new Event(), internal, channel,
|
||||
// arguments);
|
||||
EmitWithSender("-ipc-message", bindings_.dispatch_context(), base::nullopt,
|
||||
|
@ -1026,7 +1026,7 @@ void WebContents::Message(bool internal,
|
|||
|
||||
void WebContents::Invoke(bool internal,
|
||||
const std::string& channel,
|
||||
base::Value arguments,
|
||||
blink::CloneableMessage arguments,
|
||||
InvokeCallback callback) {
|
||||
// webContents.emit('-ipc-invoke', new Event(), internal, channel, arguments);
|
||||
EmitWithSender("-ipc-invoke", bindings_.dispatch_context(),
|
||||
|
@ -1035,7 +1035,7 @@ void WebContents::Invoke(bool internal,
|
|||
|
||||
void WebContents::MessageSync(bool internal,
|
||||
const std::string& channel,
|
||||
base::Value arguments,
|
||||
blink::CloneableMessage arguments,
|
||||
MessageSyncCallback callback) {
|
||||
// webContents.emit('-ipc-message-sync', new Event(sender, message), internal,
|
||||
// channel, arguments);
|
||||
|
@ -1047,24 +1047,37 @@ void WebContents::MessageTo(bool internal,
|
|||
bool send_to_all,
|
||||
int32_t web_contents_id,
|
||||
const std::string& channel,
|
||||
base::Value arguments) {
|
||||
blink::CloneableMessage arguments) {
|
||||
auto* web_contents = mate::TrackableObject<WebContents>::FromWeakMapID(
|
||||
isolate(), web_contents_id);
|
||||
|
||||
if (web_contents) {
|
||||
web_contents->SendIPCMessageWithSender(internal, send_to_all, channel,
|
||||
base::ListValue(arguments.GetList()),
|
||||
ID());
|
||||
std::move(arguments), ID());
|
||||
}
|
||||
}
|
||||
|
||||
void WebContents::MessageHost(const std::string& channel,
|
||||
base::Value arguments) {
|
||||
blink::CloneableMessage arguments) {
|
||||
// webContents.emit('ipc-message-host', new Event(), channel, args);
|
||||
EmitWithSender("ipc-message-host", bindings_.dispatch_context(),
|
||||
base::nullopt, channel, std::move(arguments));
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
void WebContents::DereferenceRemoteJSObject(const std::string& context_id,
|
||||
int object_id,
|
||||
int ref_count) {
|
||||
base::ListValue args;
|
||||
args.Append(context_id);
|
||||
args.Append(object_id);
|
||||
args.Append(ref_count);
|
||||
EmitWithSender("-ipc-message", bindings_.dispatch_context(), base::nullopt,
|
||||
/* internal */ true, "ELECTRON_BROWSER_DEREFERENCE",
|
||||
std::move(args));
|
||||
}
|
||||
#endif
|
||||
|
||||
void WebContents::UpdateDraggableRegions(
|
||||
std::vector<mojom::DraggableRegionPtr> regions) {
|
||||
for (ExtendedWebContentsObserver& observer : observers_)
|
||||
|
@ -1986,14 +1999,21 @@ void WebContents::TabTraverse(bool reverse) {
|
|||
bool WebContents::SendIPCMessage(bool internal,
|
||||
bool send_to_all,
|
||||
const std::string& channel,
|
||||
const base::ListValue& args) {
|
||||
return SendIPCMessageWithSender(internal, send_to_all, channel, args);
|
||||
v8::Local<v8::Value> args) {
|
||||
blink::CloneableMessage message;
|
||||
if (!mate::ConvertFromV8(isolate(), args, &message)) {
|
||||
isolate()->ThrowException(v8::Exception::Error(
|
||||
mate::StringToV8(isolate(), "Failed to serialize arguments")));
|
||||
return false;
|
||||
}
|
||||
return SendIPCMessageWithSender(internal, send_to_all, channel,
|
||||
std::move(message));
|
||||
}
|
||||
|
||||
bool WebContents::SendIPCMessageWithSender(bool internal,
|
||||
bool send_to_all,
|
||||
const std::string& channel,
|
||||
const base::ListValue& args,
|
||||
blink::CloneableMessage args,
|
||||
int32_t sender_id) {
|
||||
std::vector<content::RenderFrameHost*> target_hosts;
|
||||
if (!send_to_all) {
|
||||
|
@ -2009,7 +2029,7 @@ bool WebContents::SendIPCMessageWithSender(bool internal,
|
|||
mojom::ElectronRendererAssociatedPtr electron_ptr;
|
||||
frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
|
||||
mojo::MakeRequest(&electron_ptr));
|
||||
electron_ptr->Message(internal, false, channel, args.Clone(), sender_id);
|
||||
electron_ptr->Message(internal, false, channel, std::move(args), sender_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -2018,7 +2038,13 @@ bool WebContents::SendIPCMessageToFrame(bool internal,
|
|||
bool send_to_all,
|
||||
int32_t frame_id,
|
||||
const std::string& channel,
|
||||
const base::ListValue& args) {
|
||||
v8::Local<v8::Value> args) {
|
||||
blink::CloneableMessage message;
|
||||
if (!mate::ConvertFromV8(isolate(), args, &message)) {
|
||||
isolate()->ThrowException(v8::Exception::Error(
|
||||
mate::StringToV8(isolate(), "Failed to serialize arguments")));
|
||||
return false;
|
||||
}
|
||||
auto frames = web_contents()->GetAllFrames();
|
||||
auto iter = std::find_if(frames.begin(), frames.end(), [frame_id](auto* f) {
|
||||
return f->GetRoutingID() == frame_id;
|
||||
|
@ -2031,7 +2057,7 @@ bool WebContents::SendIPCMessageToFrame(bool internal,
|
|||
mojom::ElectronRendererAssociatedPtr electron_ptr;
|
||||
(*iter)->GetRemoteAssociatedInterfaces()->GetInterface(
|
||||
mojo::MakeRequest(&electron_ptr));
|
||||
electron_ptr->Message(internal, send_to_all, channel, args.Clone(),
|
||||
electron_ptr->Message(internal, send_to_all, channel, std::move(message),
|
||||
0 /* sender_id */);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -220,19 +220,19 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
bool SendIPCMessage(bool internal,
|
||||
bool send_to_all,
|
||||
const std::string& channel,
|
||||
const base::ListValue& args);
|
||||
v8::Local<v8::Value> args);
|
||||
|
||||
bool SendIPCMessageWithSender(bool internal,
|
||||
bool send_to_all,
|
||||
const std::string& channel,
|
||||
const base::ListValue& args,
|
||||
blink::CloneableMessage args,
|
||||
int32_t sender_id = 0);
|
||||
|
||||
bool SendIPCMessageToFrame(bool internal,
|
||||
bool send_to_all,
|
||||
int32_t frame_id,
|
||||
const std::string& channel,
|
||||
const base::ListValue& args);
|
||||
v8::Local<v8::Value> args);
|
||||
|
||||
// Send WebInputEvent to the page.
|
||||
void SendInputEvent(v8::Isolate* isolate, v8::Local<v8::Value> input_event);
|
||||
|
@ -491,21 +491,27 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
// mojom::ElectronBrowser
|
||||
void Message(bool internal,
|
||||
const std::string& channel,
|
||||
base::Value arguments) override;
|
||||
blink::CloneableMessage arguments) override;
|
||||
void Invoke(bool internal,
|
||||
const std::string& channel,
|
||||
base::Value arguments,
|
||||
blink::CloneableMessage arguments,
|
||||
InvokeCallback callback) override;
|
||||
void MessageSync(bool internal,
|
||||
const std::string& channel,
|
||||
base::Value arguments,
|
||||
blink::CloneableMessage arguments,
|
||||
MessageSyncCallback callback) override;
|
||||
void MessageTo(bool internal,
|
||||
bool send_to_all,
|
||||
int32_t web_contents_id,
|
||||
const std::string& channel,
|
||||
base::Value arguments) override;
|
||||
void MessageHost(const std::string& channel, base::Value arguments) override;
|
||||
blink::CloneableMessage arguments) override;
|
||||
void MessageHost(const std::string& channel,
|
||||
blink::CloneableMessage arguments) override;
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
void DereferenceRemoteJSObject(const std::string& context_id,
|
||||
int object_id,
|
||||
int ref_count) override;
|
||||
#endif
|
||||
void UpdateDraggableRegions(
|
||||
std::vector<mojom::DraggableRegionPtr> regions) override;
|
||||
void SetTemporaryZoomLevel(double level) override;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <utility>
|
||||
|
||||
#include "native_mate/object_template_builder_deprecated.h"
|
||||
#include "shell/common/native_mate_converters/value_converter.h"
|
||||
#include "shell/common/native_mate_converters/blink_converter.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
|
@ -17,7 +17,7 @@ Event::Event(v8::Isolate* isolate) {
|
|||
|
||||
Event::~Event() = default;
|
||||
|
||||
void Event::SetCallback(base::Optional<MessageSyncCallback> callback) {
|
||||
void Event::SetCallback(base::Optional<InvokeCallback> callback) {
|
||||
DCHECK(!callback_);
|
||||
callback_ = std::move(callback);
|
||||
}
|
||||
|
@ -29,11 +29,16 @@ void Event::PreventDefault(v8::Isolate* isolate) {
|
|||
.Check();
|
||||
}
|
||||
|
||||
bool Event::SendReply(const base::Value& result) {
|
||||
bool Event::SendReply(v8::Isolate* isolate, v8::Local<v8::Value> result) {
|
||||
if (!callback_)
|
||||
return false;
|
||||
|
||||
std::move(*callback_).Run(result.Clone());
|
||||
blink::CloneableMessage message;
|
||||
if (!ConvertFromV8(isolate, result, &message)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::move(*callback_).Run(std::move(message));
|
||||
callback_.reset();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -18,22 +18,21 @@ namespace mate {
|
|||
|
||||
class Event : public Wrappable<Event> {
|
||||
public:
|
||||
using MessageSyncCallback =
|
||||
electron::mojom::ElectronBrowser::MessageSyncCallback;
|
||||
using InvokeCallback = electron::mojom::ElectronBrowser::InvokeCallback;
|
||||
static Handle<Event> Create(v8::Isolate* isolate);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
|
||||
// Pass the callback to be invoked.
|
||||
void SetCallback(base::Optional<MessageSyncCallback> callback);
|
||||
void SetCallback(base::Optional<InvokeCallback> callback);
|
||||
|
||||
// event.PreventDefault().
|
||||
void PreventDefault(v8::Isolate* isolate);
|
||||
|
||||
// event.sendReply(value), used for replying to synchronous messages and
|
||||
// `invoke` calls.
|
||||
bool SendReply(const base::Value& result);
|
||||
bool SendReply(v8::Isolate* isolate, v8::Local<v8::Value> result);
|
||||
|
||||
protected:
|
||||
explicit Event(v8::Isolate* isolate);
|
||||
|
@ -41,7 +40,7 @@ class Event : public Wrappable<Event> {
|
|||
|
||||
private:
|
||||
// Replyer for the synchronous messages.
|
||||
base::Optional<MessageSyncCallback> callback_;
|
||||
base::Optional<InvokeCallback> callback_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Event);
|
||||
};
|
||||
|
|
|
@ -82,8 +82,7 @@ class EventEmitter : public Wrappable<T> {
|
|||
bool EmitWithSender(
|
||||
base::StringPiece name,
|
||||
content::RenderFrameHost* sender,
|
||||
base::Optional<electron::mojom::ElectronBrowser::MessageSyncCallback>
|
||||
callback,
|
||||
base::Optional<electron::mojom::ElectronBrowser::InvokeCallback> callback,
|
||||
Args&&... args) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
v8::Locker locker(isolate());
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import("//mojo/public/tools/bindings/mojom.gni")
|
||||
import("../../../buildflags/buildflags.gni")
|
||||
|
||||
mojom("mojo") {
|
||||
sources = [
|
||||
|
@ -7,6 +8,12 @@ mojom("mojo") {
|
|||
|
||||
public_deps = [
|
||||
"//mojo/public/mojom/base",
|
||||
"//third_party/blink/public/mojom:mojom_core",
|
||||
"//ui/gfx/geometry/mojom",
|
||||
]
|
||||
|
||||
enabled_features = []
|
||||
if (enable_remote_module) {
|
||||
enabled_features += [ "enable_remote_module" ]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,26 @@
|
|||
module electron.mojom;
|
||||
|
||||
import "mojo/public/mojom/base/values.mojom";
|
||||
import "mojo/public/mojom/base/string16.mojom";
|
||||
import "ui/gfx/geometry/mojom/geometry.mojom";
|
||||
import "third_party/blink/public/mojom/messaging/cloneable_message.mojom";
|
||||
|
||||
interface ElectronRenderer {
|
||||
Message(
|
||||
bool internal,
|
||||
bool send_to_all,
|
||||
string channel,
|
||||
mojo_base.mojom.ListValue arguments,
|
||||
blink.mojom.CloneableMessage arguments,
|
||||
int32 sender_id);
|
||||
|
||||
UpdateCrashpadPipeName(string pipe_name);
|
||||
|
||||
// This is an API specific to the "remote" module, and will ultimately be
|
||||
// replaced by generic IPC once WeakRef is generally available.
|
||||
[EnableIf=enable_remote_module]
|
||||
DereferenceRemoteJSCallback(
|
||||
string context_id,
|
||||
int32 object_id);
|
||||
|
||||
TakeHeapSnapshot(handle file) => (bool success);
|
||||
};
|
||||
|
||||
|
@ -37,14 +44,14 @@ interface ElectronBrowser {
|
|||
Message(
|
||||
bool internal,
|
||||
string channel,
|
||||
mojo_base.mojom.ListValue arguments);
|
||||
blink.mojom.CloneableMessage arguments);
|
||||
|
||||
// Emits an event on |channel| from the ipcMain JavaScript object in the main
|
||||
// process, and returns the response.
|
||||
Invoke(
|
||||
bool internal,
|
||||
string channel,
|
||||
mojo_base.mojom.ListValue arguments) => (mojo_base.mojom.Value result);
|
||||
blink.mojom.CloneableMessage arguments) => (blink.mojom.CloneableMessage result);
|
||||
|
||||
// Emits an event on |channel| from the ipcMain JavaScript object in the main
|
||||
// process, and waits synchronously for a response.
|
||||
|
@ -55,7 +62,7 @@ interface ElectronBrowser {
|
|||
MessageSync(
|
||||
bool internal,
|
||||
string channel,
|
||||
mojo_base.mojom.ListValue arguments) => (mojo_base.mojom.Value result);
|
||||
blink.mojom.CloneableMessage arguments) => (blink.mojom.CloneableMessage result);
|
||||
|
||||
// Emits an event from the |ipcRenderer| JavaScript object in the target
|
||||
// WebContents's main frame, specified by |web_contents_id|.
|
||||
|
@ -64,11 +71,19 @@ interface ElectronBrowser {
|
|||
bool send_to_all,
|
||||
int32 web_contents_id,
|
||||
string channel,
|
||||
mojo_base.mojom.ListValue arguments);
|
||||
blink.mojom.CloneableMessage arguments);
|
||||
|
||||
MessageHost(
|
||||
string channel,
|
||||
mojo_base.mojom.ListValue arguments);
|
||||
blink.mojom.CloneableMessage arguments);
|
||||
|
||||
// This is an API specific to the "remote" module, and will ultimately be
|
||||
// replaced by generic IPC once WeakRef is generally available.
|
||||
[EnableIf=enable_remote_module]
|
||||
DereferenceRemoteJSObject(
|
||||
string context_id,
|
||||
int32 object_id,
|
||||
int32 ref_count);
|
||||
|
||||
UpdateDraggableRegions(
|
||||
array<DraggableRegion> regions);
|
||||
|
|
|
@ -35,18 +35,12 @@ RemoteCallbackFreer::RemoteCallbackFreer(v8::Isolate* isolate,
|
|||
RemoteCallbackFreer::~RemoteCallbackFreer() = default;
|
||||
|
||||
void RemoteCallbackFreer::RunDestructor() {
|
||||
auto* channel = "ELECTRON_RENDERER_RELEASE_CALLBACK";
|
||||
base::ListValue args;
|
||||
int32_t sender_id = 0;
|
||||
args.AppendString(context_id_);
|
||||
args.AppendInteger(object_id_);
|
||||
auto* frame_host = web_contents()->GetMainFrame();
|
||||
if (frame_host) {
|
||||
mojom::ElectronRendererAssociatedPtr electron_ptr;
|
||||
frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
|
||||
mojo::MakeRequest(&electron_ptr));
|
||||
electron_ptr->Message(true /* internal */, false /* send_to_all */, channel,
|
||||
args.Clone(), sender_id);
|
||||
electron_ptr->DereferenceRemoteJSCallback(context_id_, object_id_);
|
||||
}
|
||||
|
||||
Observe(nullptr);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "base/values.h"
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
#include "electron/shell/common/api/api.mojom.h"
|
||||
#include "electron/shell/common/native_mate_converters/blink_converter.h"
|
||||
#include "electron/shell/common/native_mate_converters/value_converter.h"
|
||||
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
|
||||
#include "third_party/blink/public/web/web_local_frame.h"
|
||||
|
||||
|
@ -80,17 +82,10 @@ void RemoteObjectFreer::RunDestructor() {
|
|||
ref_mapper_.erase(objects_it);
|
||||
}
|
||||
|
||||
auto* channel = "ELECTRON_BROWSER_DEREFERENCE";
|
||||
|
||||
base::ListValue args;
|
||||
args.AppendString(context_id_);
|
||||
args.AppendInteger(object_id_);
|
||||
args.AppendInteger(ref_count);
|
||||
|
||||
mojom::ElectronBrowserAssociatedPtr electron_ptr;
|
||||
render_frame->GetRemoteAssociatedInterfaces()->GetInterface(
|
||||
mojo::MakeRequest(&electron_ptr));
|
||||
electron_ptr->Message(true, channel, args.Clone());
|
||||
electron_ptr->DereferenceRemoteJSObject(context_id_, object_id_, ref_count);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
|
30
shell/common/gin_converters/blink_converter_gin_adapter.h
Normal file
30
shell/common/gin_converters/blink_converter_gin_adapter.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2019 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_COMMON_GIN_CONVERTERS_BLINK_CONVERTER_GIN_ADAPTER_H_
|
||||
#define SHELL_COMMON_GIN_CONVERTERS_BLINK_CONVERTER_GIN_ADAPTER_H_
|
||||
|
||||
#include "gin/converter.h"
|
||||
#include "shell/common/native_mate_converters/blink_converter.h"
|
||||
|
||||
// TODO(zcbenz): Move the implementations from native_mate_converters to here.
|
||||
|
||||
namespace gin {
|
||||
|
||||
template <>
|
||||
struct Converter<blink::CloneableMessage> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::CloneableMessage* out) {
|
||||
return mate::ConvertFromV8(isolate, val, out);
|
||||
}
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const blink::CloneableMessage& val) {
|
||||
return mate::ConvertToV8(isolate, val);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gin
|
||||
|
||||
#endif // SHELL_COMMON_GIN_CONVERTERS_BLINK_CONVERTER_GIN_ADAPTER_H_
|
|
@ -6,14 +6,19 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "gin/converter.h"
|
||||
#include "mojo/public/cpp/base/values_mojom_traits.h"
|
||||
#include "mojo/public/mojom/base/values.mojom.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "shell/common/deprecate_util.h"
|
||||
#include "shell/common/keyboard_util.h"
|
||||
#include "shell/common/native_mate_converters/value_converter.h"
|
||||
#include "third_party/blink/public/platform/web_input_event.h"
|
||||
#include "third_party/blink/public/platform/web_mouse_event.h"
|
||||
#include "third_party/blink/public/platform/web_mouse_wheel_event.h"
|
||||
|
@ -527,4 +532,184 @@ bool Converter<network::mojom::ReferrerPolicy>::FromV8(
|
|||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
constexpr uint8_t kNewSerializationTag = 0;
|
||||
constexpr uint8_t kOldSerializationTag = 1;
|
||||
|
||||
class V8Serializer : public v8::ValueSerializer::Delegate {
|
||||
public:
|
||||
explicit V8Serializer(v8::Isolate* isolate,
|
||||
bool use_old_serialization = false)
|
||||
: isolate_(isolate),
|
||||
serializer_(isolate, this),
|
||||
use_old_serialization_(use_old_serialization) {}
|
||||
~V8Serializer() override = default;
|
||||
|
||||
bool Serialize(v8::Local<v8::Value> value, blink::CloneableMessage* out) {
|
||||
serializer_.WriteHeader();
|
||||
if (use_old_serialization_) {
|
||||
WriteTag(kOldSerializationTag);
|
||||
if (!WriteBaseValue(value)) {
|
||||
isolate_->ThrowException(
|
||||
mate::StringToV8(isolate_, "An object could not be cloned."));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
WriteTag(kNewSerializationTag);
|
||||
bool wrote_value;
|
||||
v8::TryCatch try_catch(isolate_);
|
||||
if (!serializer_.WriteValue(isolate_->GetCurrentContext(), value)
|
||||
.To(&wrote_value)) {
|
||||
try_catch.Reset();
|
||||
if (!V8Serializer(isolate_, true).Serialize(value, out)) {
|
||||
try_catch.ReThrow();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
DCHECK(wrote_value);
|
||||
}
|
||||
|
||||
std::pair<uint8_t*, size_t> buffer = serializer_.Release();
|
||||
DCHECK_EQ(buffer.first, data_.data());
|
||||
out->encoded_message = base::make_span(buffer.first, buffer.second);
|
||||
out->owned_encoded_message = std::move(data_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteBaseValue(v8::Local<v8::Value> object) {
|
||||
node::Environment* env = node::Environment::GetCurrent(isolate_);
|
||||
if (env) {
|
||||
electron::EmitDeprecationWarning(
|
||||
env,
|
||||
"Passing functions, DOM objects and other non-cloneable JavaScript "
|
||||
"objects to IPC methods is deprecated and will throw an exception "
|
||||
"beginning with Electron 9.",
|
||||
"DeprecationWarning");
|
||||
}
|
||||
base::Value value;
|
||||
if (!ConvertFromV8(isolate_, object, &value)) {
|
||||
return false;
|
||||
}
|
||||
mojo::Message message = mojo_base::mojom::Value::SerializeAsMessage(&value);
|
||||
|
||||
serializer_.WriteUint32(message.data_num_bytes());
|
||||
serializer_.WriteRawBytes(message.data(), message.data_num_bytes());
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriteTag(uint8_t tag) { serializer_.WriteRawBytes(&tag, 1); }
|
||||
|
||||
// v8::ValueSerializer::Delegate
|
||||
void* ReallocateBufferMemory(void* old_buffer,
|
||||
size_t size,
|
||||
size_t* actual_size) override {
|
||||
DCHECK_EQ(old_buffer, data_.data());
|
||||
data_.resize(size);
|
||||
*actual_size = data_.capacity();
|
||||
return data_.data();
|
||||
}
|
||||
|
||||
void FreeBufferMemory(void* buffer) override {
|
||||
DCHECK_EQ(buffer, data_.data());
|
||||
data_ = {};
|
||||
}
|
||||
|
||||
void ThrowDataCloneError(v8::Local<v8::String> message) override {
|
||||
isolate_->ThrowException(v8::Exception::Error(message));
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Isolate* isolate_;
|
||||
std::vector<uint8_t> data_;
|
||||
v8::ValueSerializer serializer_;
|
||||
bool use_old_serialization_;
|
||||
};
|
||||
|
||||
class V8Deserializer : public v8::ValueDeserializer::Delegate {
|
||||
public:
|
||||
V8Deserializer(v8::Isolate* isolate, const blink::CloneableMessage& message)
|
||||
: isolate_(isolate),
|
||||
deserializer_(isolate,
|
||||
message.encoded_message.data(),
|
||||
message.encoded_message.size(),
|
||||
this) {}
|
||||
|
||||
v8::Local<v8::Value> Deserialize() {
|
||||
v8::EscapableHandleScope scope(isolate_);
|
||||
auto context = isolate_->GetCurrentContext();
|
||||
bool read_header;
|
||||
if (!deserializer_.ReadHeader(context).To(&read_header))
|
||||
return v8::Null(isolate_);
|
||||
DCHECK(read_header);
|
||||
uint8_t tag;
|
||||
if (!ReadTag(&tag))
|
||||
return v8::Null(isolate_);
|
||||
switch (tag) {
|
||||
case kNewSerializationTag: {
|
||||
v8::Local<v8::Value> value;
|
||||
if (!deserializer_.ReadValue(context).ToLocal(&value)) {
|
||||
return v8::Null(isolate_);
|
||||
}
|
||||
return scope.Escape(value);
|
||||
}
|
||||
case kOldSerializationTag: {
|
||||
v8::Local<v8::Value> value;
|
||||
if (!ReadBaseValue(&value)) {
|
||||
return v8::Null(isolate_);
|
||||
}
|
||||
return scope.Escape(value);
|
||||
}
|
||||
default:
|
||||
NOTREACHED() << "Invalid tag: " << tag;
|
||||
return v8::Null(isolate_);
|
||||
}
|
||||
}
|
||||
|
||||
bool ReadTag(uint8_t* tag) {
|
||||
const void* tag_bytes;
|
||||
if (!deserializer_.ReadRawBytes(1, &tag_bytes))
|
||||
return false;
|
||||
*tag = *reinterpret_cast<const uint8_t*>(tag_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadBaseValue(v8::Local<v8::Value>* value) {
|
||||
uint32_t length;
|
||||
const void* data;
|
||||
if (!deserializer_.ReadUint32(&length) ||
|
||||
!deserializer_.ReadRawBytes(length, &data)) {
|
||||
return false;
|
||||
}
|
||||
mojo::Message message(
|
||||
base::make_span(reinterpret_cast<const uint8_t*>(data), length), {});
|
||||
base::Value out;
|
||||
if (!mojo_base::mojom::Value::DeserializeFromMessage(std::move(message),
|
||||
&out)) {
|
||||
return false;
|
||||
}
|
||||
*value = ConvertToV8(isolate_, out);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Isolate* isolate_;
|
||||
v8::ValueDeserializer deserializer_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
v8::Local<v8::Value> Converter<blink::CloneableMessage>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const blink::CloneableMessage& in) {
|
||||
return V8Deserializer(isolate, in).Deserialize();
|
||||
}
|
||||
|
||||
bool Converter<blink::CloneableMessage>::FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
blink::CloneableMessage* out) {
|
||||
return V8Serializer(isolate).Serialize(val, out);
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define SHELL_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_
|
||||
|
||||
#include "native_mate/converter.h"
|
||||
#include "third_party/blink/public/common/messaging/cloneable_message.h"
|
||||
#include "third_party/blink/public/platform/web_cache.h"
|
||||
#include "third_party/blink/public/platform/web_input_event.h"
|
||||
#include "third_party/blink/public/web/web_context_menu_data.h"
|
||||
|
@ -131,6 +132,15 @@ struct Converter<network::mojom::ReferrerPolicy> {
|
|||
network::mojom::ReferrerPolicy* out);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<blink::CloneableMessage> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const blink::CloneableMessage& in);
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
blink::CloneableMessage* out);
|
||||
};
|
||||
|
||||
v8::Local<v8::Value> EditFlagsToV8(v8::Isolate* isolate, int editFlags);
|
||||
v8::Local<v8::Value> MediaFlagsToV8(v8::Isolate* isolate, int mediaFlags);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "gin/wrappable.h"
|
||||
#include "services/service_manager/public/cpp/interface_provider.h"
|
||||
#include "shell/common/api/api.mojom.h"
|
||||
#include "shell/common/gin_converters/blink_converter_gin_adapter.h"
|
||||
#include "shell/common/gin_converters/value_converter_gin_adapter.h"
|
||||
#include "shell/common/node_bindings.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
|
@ -69,45 +70,71 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer> {
|
|||
const char* GetTypeName() override { return "IPCRenderer"; }
|
||||
|
||||
private:
|
||||
void Send(bool internal,
|
||||
void Send(v8::Isolate* isolate,
|
||||
bool internal,
|
||||
const std::string& channel,
|
||||
const base::ListValue& arguments) {
|
||||
electron_browser_ptr_->get()->Message(internal, channel, arguments.Clone());
|
||||
v8::Local<v8::Value> arguments) {
|
||||
blink::CloneableMessage message;
|
||||
if (!mate::ConvertFromV8(isolate, arguments, &message)) {
|
||||
return;
|
||||
}
|
||||
electron_browser_ptr_->get()->Message(internal, channel,
|
||||
std::move(message));
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> Invoke(v8::Isolate* isolate,
|
||||
bool internal,
|
||||
const std::string& channel,
|
||||
const base::Value& arguments) {
|
||||
electron::util::Promise<base::Value> p(isolate);
|
||||
v8::Local<v8::Value> arguments) {
|
||||
blink::CloneableMessage message;
|
||||
if (!mate::ConvertFromV8(isolate, arguments, &message)) {
|
||||
return v8::Local<v8::Promise>();
|
||||
}
|
||||
electron::util::Promise<blink::CloneableMessage> p(isolate);
|
||||
auto handle = p.GetHandle();
|
||||
|
||||
electron_browser_ptr_->get()->Invoke(
|
||||
internal, channel, arguments.Clone(),
|
||||
base::BindOnce([](electron::util::Promise<base::Value> p,
|
||||
base::Value result) { p.ResolveWithGin(result); },
|
||||
std::move(p)));
|
||||
internal, channel, std::move(message),
|
||||
base::BindOnce(
|
||||
[](electron::util::Promise<blink::CloneableMessage> p,
|
||||
blink::CloneableMessage result) { p.ResolveWithGin(result); },
|
||||
std::move(p)));
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void SendTo(bool internal,
|
||||
void SendTo(v8::Isolate* isolate,
|
||||
bool internal,
|
||||
bool send_to_all,
|
||||
int32_t web_contents_id,
|
||||
const std::string& channel,
|
||||
const base::ListValue& arguments) {
|
||||
v8::Local<v8::Value> arguments) {
|
||||
blink::CloneableMessage message;
|
||||
if (!mate::ConvertFromV8(isolate, arguments, &message)) {
|
||||
return;
|
||||
}
|
||||
electron_browser_ptr_->get()->MessageTo(
|
||||
internal, send_to_all, web_contents_id, channel, arguments.Clone());
|
||||
internal, send_to_all, web_contents_id, channel, std::move(message));
|
||||
}
|
||||
|
||||
void SendToHost(const std::string& channel,
|
||||
const base::ListValue& arguments) {
|
||||
electron_browser_ptr_->get()->MessageHost(channel, arguments.Clone());
|
||||
void SendToHost(v8::Isolate* isolate,
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> arguments) {
|
||||
blink::CloneableMessage message;
|
||||
if (!mate::ConvertFromV8(isolate, arguments, &message)) {
|
||||
return;
|
||||
}
|
||||
electron_browser_ptr_->get()->MessageHost(channel, std::move(message));
|
||||
}
|
||||
|
||||
base::Value SendSync(bool internal,
|
||||
const std::string& channel,
|
||||
const base::ListValue& arguments) {
|
||||
blink::CloneableMessage SendSync(v8::Isolate* isolate,
|
||||
bool internal,
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> arguments) {
|
||||
blink::CloneableMessage message;
|
||||
if (!mate::ConvertFromV8(isolate, arguments, &message)) {
|
||||
return blink::CloneableMessage();
|
||||
}
|
||||
// We aren't using a true synchronous mojo call here. We're calling an
|
||||
// asynchronous method and blocking on the result. The reason we're doing
|
||||
// this is a little complicated, so buckle up.
|
||||
|
@ -154,7 +181,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer> {
|
|||
//
|
||||
// Phew. If you got this far, here's a gold star: ⭐️
|
||||
|
||||
base::Value result;
|
||||
blink::CloneableMessage result;
|
||||
|
||||
// A task is posted to a worker thread to execute the request so that
|
||||
// this thread may block on a waitable event. It is safe to pass raw
|
||||
|
@ -167,16 +194,16 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer> {
|
|||
base::Unretained(this),
|
||||
base::Unretained(&response_received_event),
|
||||
base::Unretained(&result), internal, channel,
|
||||
arguments.Clone()));
|
||||
std::move(message)));
|
||||
response_received_event.Wait();
|
||||
return result;
|
||||
}
|
||||
|
||||
void SendMessageSyncOnWorkerThread(base::WaitableEvent* event,
|
||||
base::Value* result,
|
||||
blink::CloneableMessage* result,
|
||||
bool internal,
|
||||
const std::string& channel,
|
||||
base::Value arguments) {
|
||||
blink::CloneableMessage arguments) {
|
||||
electron_browser_ptr_->get()->MessageSync(
|
||||
internal, channel, std::move(arguments),
|
||||
base::BindOnce(&IPCRenderer::ReturnSyncResponseToMainThread,
|
||||
|
@ -184,8 +211,8 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer> {
|
|||
}
|
||||
|
||||
static void ReturnSyncResponseToMainThread(base::WaitableEvent* event,
|
||||
base::Value* result,
|
||||
base::Value response) {
|
||||
blink::CloneableMessage* result,
|
||||
blink::CloneableMessage response) {
|
||||
*result = std::move(response);
|
||||
event->Signal();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "base/threading/thread_restrictions.h"
|
||||
#include "mojo/public/cpp/system/platform_handle.h"
|
||||
#include "shell/common/atom_constants.h"
|
||||
#include "shell/common/gin_converters/blink_converter_gin_adapter.h"
|
||||
#include "shell/common/gin_converters/value_converter_gin_adapter.h"
|
||||
#include "shell/common/heap_snapshot.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
|
@ -73,7 +74,7 @@ void InvokeIpcCallback(v8::Local<v8::Context> context,
|
|||
void EmitIPCEvent(v8::Local<v8::Context> context,
|
||||
bool internal,
|
||||
const std::string& channel,
|
||||
const std::vector<base::Value>& args,
|
||||
v8::Local<v8::Value> args,
|
||||
int32_t sender_id) {
|
||||
auto* isolate = context->GetIsolate();
|
||||
|
||||
|
@ -84,7 +85,7 @@ void EmitIPCEvent(v8::Local<v8::Context> context,
|
|||
|
||||
std::vector<v8::Local<v8::Value>> argv = {
|
||||
gin::ConvertToV8(isolate, internal), gin::ConvertToV8(isolate, channel),
|
||||
gin::ConvertToV8(isolate, args), gin::ConvertToV8(isolate, sender_id)};
|
||||
args, gin::ConvertToV8(isolate, sender_id)};
|
||||
|
||||
InvokeIpcCallback(context, "onMessage", argv);
|
||||
}
|
||||
|
@ -128,7 +129,7 @@ void ElectronApiServiceImpl::OnConnectionError() {
|
|||
void ElectronApiServiceImpl::Message(bool internal,
|
||||
bool send_to_all,
|
||||
const std::string& channel,
|
||||
base::Value arguments,
|
||||
blink::CloneableMessage arguments,
|
||||
int32_t sender_id) {
|
||||
// Don't handle browser messages before document element is created.
|
||||
//
|
||||
|
@ -157,8 +158,11 @@ void ElectronApiServiceImpl::Message(bool internal,
|
|||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
v8::Local<v8::Context> context = renderer_client_->GetContext(frame, isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
EmitIPCEvent(context, internal, channel, arguments.GetList(), sender_id);
|
||||
v8::Local<v8::Value> args = gin::ConvertToV8(isolate, arguments);
|
||||
|
||||
EmitIPCEvent(context, internal, channel, args, sender_id);
|
||||
|
||||
// Also send the message to all sub-frames.
|
||||
// TODO(MarshallOfSound): Completely move this logic to the main process
|
||||
|
@ -168,12 +172,38 @@ void ElectronApiServiceImpl::Message(bool internal,
|
|||
if (child->IsWebLocalFrame()) {
|
||||
v8::Local<v8::Context> child_context =
|
||||
renderer_client_->GetContext(child->ToWebLocalFrame(), isolate);
|
||||
EmitIPCEvent(child_context, internal, channel, arguments.GetList(),
|
||||
sender_id);
|
||||
EmitIPCEvent(child_context, internal, channel, args, sender_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
void ElectronApiServiceImpl::DereferenceRemoteJSCallback(
|
||||
const std::string& context_id,
|
||||
int32_t object_id) {
|
||||
const auto* channel = "ELECTRON_RENDERER_RELEASE_CALLBACK";
|
||||
if (!document_created_)
|
||||
return;
|
||||
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
v8::Isolate* isolate = blink::MainThreadIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
v8::Local<v8::Context> context = renderer_client_->GetContext(frame, isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
base::ListValue args;
|
||||
args.AppendString(context_id);
|
||||
args.AppendInteger(object_id);
|
||||
|
||||
v8::Local<v8::Value> v8_args = gin::ConvertToV8(isolate, args);
|
||||
EmitIPCEvent(context, true /* internal */, channel, v8_args,
|
||||
0 /* sender_id */);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ElectronApiServiceImpl::UpdateCrashpadPipeName(
|
||||
const std::string& pipe_name) {
|
||||
#if defined(OS_WIN)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "base/memory/weak_ptr.h"
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
#include "content/public/renderer/render_frame_observer.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "electron/shell/common/api/api.mojom.h"
|
||||
#include "mojo/public/cpp/bindings/associated_binding.h"
|
||||
|
||||
|
@ -28,8 +29,12 @@ class ElectronApiServiceImpl : public mojom::ElectronRenderer,
|
|||
void Message(bool internal,
|
||||
bool send_to_all,
|
||||
const std::string& channel,
|
||||
base::Value arguments,
|
||||
blink::CloneableMessage arguments,
|
||||
int32_t sender_id) override;
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
void DereferenceRemoteJSCallback(const std::string& context_id,
|
||||
int32_t object_id) override;
|
||||
#endif
|
||||
void UpdateCrashpadPipeName(const std::string& pipe_name) override;
|
||||
void TakeHeapSnapshot(mojo::ScopedHandle file,
|
||||
TakeHeapSnapshotCallback callback) override;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue