Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(735)

Unified Diff: extensions/renderer/messaging_bindings.cc

Issue 2547753002: [Extensions] Extension Port Ids and Initialization 2.0 (Closed)
Patch Set: rkaplow Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « extensions/renderer/messaging_bindings.h ('k') | third_party/WebKit/Source/web/WebDocument.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: extensions/renderer/messaging_bindings.cc
diff --git a/extensions/renderer/messaging_bindings.cc b/extensions/renderer/messaging_bindings.cc
index b82e84b113e571242a45d951dc5e0db6c9fb67e4..c06fe1d464da2430feccf2f2d66951a831eaa369 100644
--- a/extensions/renderer/messaging_bindings.cc
+++ b/extensions/renderer/messaging_bindings.cc
@@ -22,6 +22,7 @@
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "extensions/common/api/messaging/message.h"
+#include "extensions/common/api/messaging/port_id.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/manifest_handlers/externally_connectable.h"
#include "extensions/renderer/extension_frame_helper.h"
@@ -55,7 +56,7 @@ namespace {
base::LazyInstance<std::map<ScriptContext*, MessagingBindings*>>
g_messaging_map = LAZY_INSTANCE_INITIALIZER;
-void HasMessagePort(int global_port_id,
+void HasMessagePort(const PortId& port_id,
bool* has_port,
ScriptContext* script_context) {
if (*has_port)
@@ -63,12 +64,12 @@ void HasMessagePort(int global_port_id,
MessagingBindings* bindings = g_messaging_map.Get()[script_context];
DCHECK(bindings);
- if (bindings->GetPortWithGlobalId(global_port_id))
- *has_port = true;
+ // No need for |=; we know this is false right now from above.
+ *has_port = bindings->GetPortWithId(port_id) != nullptr;
}
void DispatchOnConnectToScriptContext(
- int global_target_port_id,
+ const PortId& target_port_id,
const std::string& channel_name,
const ExtensionMsg_TabConnectionInfo* source,
const ExtensionMsg_ExternalConnectionInfo& info,
@@ -78,17 +79,17 @@ void DispatchOnConnectToScriptContext(
MessagingBindings* bindings = g_messaging_map.Get()[script_context];
DCHECK(bindings);
- int opposite_port_id = global_target_port_id ^ 1;
- if (bindings->GetPortWithGlobalId(opposite_port_id))
- return; // The channel was opened by this same context; ignore it.
+ // If the channel was opened by this same context, ignore it. This should only
+ // happen when messages are sent to an entire process (rather than a single
+ // frame) as an optimization; otherwise the browser process filters this out.
+ if (bindings->context_id() == target_port_id.context_id)
+ return;
- ExtensionPort* port =
- bindings->CreateNewPortWithGlobalId(global_target_port_id);
- int local_port_id = port->local_id();
+ ExtensionPort* port = bindings->CreateNewPortWithId(target_port_id);
// Remove the port.
base::ScopedClosureRunner remove_port(
- base::Bind(&MessagingBindings::RemovePortWithLocalId,
- bindings->GetWeakPtr(), local_port_id));
+ base::Bind(&MessagingBindings::RemovePortWithJsId, bindings->GetWeakPtr(),
+ port->js_id()));
v8::Isolate* isolate = script_context->isolate();
v8::HandleScope handle_scope(isolate);
@@ -141,7 +142,7 @@ void DispatchOnConnectToScriptContext(
v8::Local<v8::Value> arguments[] = {
// portId
- v8::Integer::New(isolate, local_port_id),
+ v8::Integer::New(isolate, port->js_id()),
// channelName
v8_channel_name,
// sourceTab
@@ -178,11 +179,11 @@ void DispatchOnConnectToScriptContext(
}
void DeliverMessageToScriptContext(const Message& message,
- int global_target_port_id,
+ const PortId& target_port_id,
ScriptContext* script_context) {
MessagingBindings* bindings = g_messaging_map.Get()[script_context];
DCHECK(bindings);
- ExtensionPort* port = bindings->GetPortWithGlobalId(global_target_port_id);
+ ExtensionPort* port = bindings->GetPortWithId(target_port_id);
if (!port)
return;
@@ -190,7 +191,7 @@ void DeliverMessageToScriptContext(const Message& message,
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> port_id_handle =
- v8::Integer::New(isolate, port->local_id());
+ v8::Integer::New(isolate, port->js_id());
v8::Local<v8::String> v8_data;
if (!ToV8String(isolate, message.data.c_str(), &v8_data))
@@ -217,12 +218,12 @@ void DeliverMessageToScriptContext(const Message& message,
"messaging", "dispatchOnMessage", &arguments);
}
-void DispatchOnDisconnectToScriptContext(int global_port_id,
+void DispatchOnDisconnectToScriptContext(const PortId& port_id,
const std::string& error_message,
ScriptContext* script_context) {
MessagingBindings* bindings = g_messaging_map.Get()[script_context];
DCHECK(bindings);
- ExtensionPort* port = bindings->GetPortWithGlobalId(global_port_id);
+ ExtensionPort* port = bindings->GetPortWithId(port_id);
if (!port)
return;
@@ -230,7 +231,7 @@ void DispatchOnDisconnectToScriptContext(int global_port_id,
v8::HandleScope handle_scope(isolate);
std::vector<v8::Local<v8::Value>> arguments;
- arguments.push_back(v8::Integer::New(isolate, port->local_id()));
+ arguments.push_back(v8::Integer::New(isolate, port->js_id()));
v8::Local<v8::String> v8_error_message;
if (!error_message.empty())
ToV8String(isolate, error_message.c_str(), &v8_error_message);
@@ -247,7 +248,9 @@ void DispatchOnDisconnectToScriptContext(int global_port_id,
} // namespace
MessagingBindings::MessagingBindings(ScriptContext* context)
- : ObjectBackedNativeHandler(context), weak_ptr_factory_(this) {
+ : ObjectBackedNativeHandler(context),
+ context_id_(base::UnguessableToken::Create()),
+ weak_ptr_factory_(this) {
g_messaging_map.Get()[context] = this;
RouteFunction("CloseChannel", base::Bind(&MessagingBindings::CloseChannel,
base::Unretained(this)));
@@ -269,49 +272,41 @@ MessagingBindings::MessagingBindings(ScriptContext* context)
MessagingBindings::~MessagingBindings() {
g_messaging_map.Get().erase(context());
- if (ports_created_normal_ > 0 || ports_created_in_before_unload_ > 0 ||
- ports_created_in_unload_ > 0) {
- UMA_HISTOGRAM_COUNTS_1000(
- "Extensions.Messaging.ExtensionPortsCreated.InBeforeUnload",
- ports_created_in_before_unload_);
- UMA_HISTOGRAM_COUNTS_1000(
- "Extensions.Messaging.ExtensionPortsCreated.InUnload",
- ports_created_in_unload_);
+ if (num_extension_ports_ > 0) {
UMA_HISTOGRAM_COUNTS_1000(
- "Extensions.Messaging.ExtensionPortsCreated.Normal",
- ports_created_normal_);
+ "Extensions.Messaging.ExtensionPortsCreated.Total", next_js_id_);
}
}
// static
void MessagingBindings::ValidateMessagePort(
const ScriptContextSet& context_set,
- int global_port_id,
+ const PortId& port_id,
content::RenderFrame* render_frame) {
int routing_id = render_frame->GetRoutingID();
bool has_port = false;
context_set.ForEach(render_frame,
- base::Bind(&HasMessagePort, global_port_id, &has_port));
+ base::Bind(&HasMessagePort, port_id, &has_port));
// A reply is only sent if the port is missing, because the port is assumed to
// exist unless stated otherwise.
if (!has_port) {
content::RenderThread::Get()->Send(
- new ExtensionHostMsg_CloseMessagePort(routing_id,
- global_port_id, false));
+ new ExtensionHostMsg_CloseMessagePort(routing_id, port_id, false));
}
}
// static
void MessagingBindings::DispatchOnConnect(
const ScriptContextSet& context_set,
- int target_port_id,
+ const PortId& target_port_id,
const std::string& channel_name,
const ExtensionMsg_TabConnectionInfo& source,
const ExtensionMsg_ExternalConnectionInfo& info,
const std::string& tls_channel_id,
content::RenderFrame* restrict_to_render_frame) {
+ DCHECK(!target_port_id.is_opener);
int routing_id = restrict_to_render_frame
? restrict_to_render_frame->GetRoutingID()
: MSG_ROUTING_NONE;
@@ -334,7 +329,7 @@ void MessagingBindings::DispatchOnConnect(
// static
void MessagingBindings::DeliverMessage(
const ScriptContextSet& context_set,
- int target_port_id,
+ const PortId& target_port_id,
const Message& message,
content::RenderFrame* restrict_to_render_frame) {
context_set.ForEach(
@@ -345,7 +340,7 @@ void MessagingBindings::DeliverMessage(
// static
void MessagingBindings::DispatchOnDisconnect(
const ScriptContextSet& context_set,
- int port_id,
+ const PortId& port_id,
const std::string& error_message,
content::RenderFrame* restrict_to_render_frame) {
context_set.ForEach(
@@ -353,27 +348,23 @@ void MessagingBindings::DispatchOnDisconnect(
base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message));
}
-ExtensionPort* MessagingBindings::GetPortWithGlobalId(int id) {
+ExtensionPort* MessagingBindings::GetPortWithId(const PortId& id) {
for (const auto& key_value : ports_) {
- if (key_value.second->global_id() == id)
+ if (key_value.second->id() == id)
return key_value.second.get();
}
return nullptr;
}
-ExtensionPort* MessagingBindings::CreateNewPortWithGlobalId(int global_id) {
- int local_id = GetNextLocalId();
- ExtensionPort* port =
- ports_
- .insert(std::make_pair(
- local_id, base::MakeUnique<ExtensionPort>(context(), local_id)))
- .first->second.get();
- port->SetGlobalId(global_id);
- return port;
+ExtensionPort* MessagingBindings::CreateNewPortWithId(const PortId& id) {
+ int js_id = GetNextJsId();
+ auto port = base::MakeUnique<ExtensionPort>(context(), id, js_id);
+ return ports_.insert(std::make_pair(js_id, std::move(port)))
+ .first->second.get();
}
-void MessagingBindings::RemovePortWithLocalId(int local_id) {
- ports_.erase(local_id);
+void MessagingBindings::RemovePortWithJsId(int js_id) {
+ ports_.erase(js_id);
}
base::WeakPtr<MessagingBindings> MessagingBindings::GetWeakPtr() {
@@ -387,8 +378,8 @@ void MessagingBindings::PostMessage(
CHECK(args[0]->IsInt32());
CHECK(args[1]->IsString());
- int port_id = args[0].As<v8::Int32>()->Value();
- auto iter = ports_.find(port_id);
+ int js_port_id = args[0].As<v8::Int32>()->Value();
+ auto iter = ports_.find(js_port_id);
if (iter != ports_.end()) {
iter->second->PostExtensionMessage(base::MakeUnique<Message>(
*v8::String::Utf8Value(args[1]),
@@ -403,9 +394,9 @@ void MessagingBindings::CloseChannel(
CHECK(args[0]->IsInt32());
CHECK(args[1]->IsBoolean());
- int port_id = args[0].As<v8::Int32>()->Value();
+ int js_port_id = args[0].As<v8::Int32>()->Value();
bool force_close = args[1].As<v8::Boolean>()->Value();
- ClosePort(port_id, force_close);
+ ClosePort(js_port_id, force_close);
}
void MessagingBindings::BindToGC(
@@ -414,16 +405,16 @@ void MessagingBindings::BindToGC(
CHECK(args[0]->IsObject());
CHECK(args[1]->IsFunction());
CHECK(args[2]->IsInt32());
- int local_port_id = args[2].As<v8::Int32>()->Value();
+ int js_port_id = args[2].As<v8::Int32>()->Value();
base::Closure fallback = base::Bind(&base::DoNothing);
- if (local_port_id >= 0) {
+ if (js_port_id >= 0) {
// TODO(robwu): Falling back to closing the port shouldn't be needed. If
// the script context is destroyed, then the frame has navigated. But that
// is already detected by the browser, so this logic is redundant. Remove
// this fallback (and move BindToGC out of messaging because it is also
// used in other places that have nothing to do with messaging...).
fallback = base::Bind(&MessagingBindings::ClosePort,
- weak_ptr_factory_.GetWeakPtr(), local_port_id,
+ weak_ptr_factory_.GetWeakPtr(), js_port_id,
false /* force_close */);
}
// Destroys itself when the object is GC'd or context is invalidated.
@@ -443,8 +434,9 @@ void MessagingBindings::OpenChannelToExtension(
CHECK(args[1]->IsString());
CHECK(args[2]->IsBoolean());
- int local_id = GetNextLocalId();
- ports_[local_id] = base::MakeUnique<ExtensionPort>(context(), local_id);
+ int js_id = GetNextJsId();
+ PortId port_id(context_id_, js_id, true);
+ ports_[js_id] = base::MakeUnique<ExtensionPort>(context(), port_id, js_id);
ExtensionMsg_ExternalConnectionInfo info;
// For messaging APIs, hosted apps should be considered a web page so hide
@@ -460,34 +452,16 @@ void MessagingBindings::OpenChannelToExtension(
bool include_tls_channel_id =
args.Length() > 2 ? args[2]->BooleanValue() : false;
- ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
- DCHECK(frame_helper);
-
- blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
- // If the frame is unloading, we need to assign the port id synchronously to
- // avoid dropping the message on the floor; see crbug.com/660706.
- // TODO(devlin): Investigate whether we need to continue supporting this long-
- // term, and, if so, find an alternative that doesn't require synchronous
- // IPCs.
- if (!web_frame->document().isNull() &&
- (web_frame->document().unloadStartedDoNotUse() ||
- web_frame->document().processingBeforeUnloadDoNotUse())) {
- ports_created_in_before_unload_ +=
- web_frame->document().processingBeforeUnloadDoNotUse() ? 1 : 0;
- ports_created_in_unload_ +=
- web_frame->document().unloadStartedDoNotUse() ? 1 : 0;
- int global_id = frame_helper->RequestSyncPortId(info, channel_name,
- include_tls_channel_id);
- ports_[local_id]->SetGlobalId(global_id);
- } else {
- ++ports_created_normal_;
- frame_helper->RequestPortId(
- info, channel_name, include_tls_channel_id,
- base::Bind(&MessagingBindings::SetGlobalPortId,
- weak_ptr_factory_.GetWeakPtr(), local_id));
+ {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "Extensions.Messaging.SetPortIdTime.Extension");
+ render_frame->Send(new ExtensionHostMsg_OpenChannelToExtension(
+ render_frame->GetRoutingID(), info, channel_name,
+ include_tls_channel_id, port_id));
}
- args.GetReturnValue().Set(static_cast<int32_t>(local_id));
+ ++num_extension_ports_;
+ args.GetReturnValue().Set(static_cast<int32_t>(js_id));
}
void MessagingBindings::OpenChannelToNativeApp(
@@ -504,16 +478,18 @@ void MessagingBindings::OpenChannelToNativeApp(
std::string native_app_name = *v8::String::Utf8Value(args[0]);
- int local_id = GetNextLocalId();
- ports_[local_id] = base::MakeUnique<ExtensionPort>(context(), local_id);
+ int js_id = GetNextJsId();
+ PortId port_id(context_id_, js_id, true);
+ ports_[js_id] = base::MakeUnique<ExtensionPort>(context(), port_id, js_id);
- ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
- DCHECK(frame_helper);
- frame_helper->RequestNativeAppPortId(
- native_app_name,
- base::Bind(&MessagingBindings::SetGlobalPortId,
- weak_ptr_factory_.GetWeakPtr(), local_id));
- args.GetReturnValue().Set(static_cast<int32_t>(local_id));
+ {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "Extensions.Messaging.SetPortIdTime.NativeApp");
+ render_frame->Send(new ExtensionHostMsg_OpenChannelToNativeApp(
+ render_frame->GetRoutingID(), native_app_name, port_id));
+ }
+
+ args.GetReturnValue().Set(static_cast<int32_t>(js_id));
}
void MessagingBindings::OpenChannelToTab(
@@ -535,8 +511,9 @@ void MessagingBindings::OpenChannelToTab(
CHECK(args[2]->IsString());
CHECK(args[3]->IsString());
- int local_id = GetNextLocalId();
- ports_[local_id] = base::MakeUnique<ExtensionPort>(context(), local_id);
+ int js_id = GetNextJsId();
+ PortId port_id(context_id_, js_id, true);
+ ports_[js_id] = base::MakeUnique<ExtensionPort>(context(), port_id, js_id);
ExtensionMsg_TabTargetConnectionInfo info;
info.tab_id = args[0]->Int32Value();
@@ -547,48 +524,30 @@ void MessagingBindings::OpenChannelToTab(
ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
DCHECK(frame_helper);
- frame_helper->RequestTabPortId(
- info, extension_id, channel_name,
- base::Bind(&MessagingBindings::SetGlobalPortId,
- weak_ptr_factory_.GetWeakPtr(), local_id));
- args.GetReturnValue().Set(static_cast<int32_t>(local_id));
+ {
+ SCOPED_UMA_HISTOGRAM_TIMER("Extensions.Messaging.SetPortIdTime.Tab");
+ render_frame->Send(new ExtensionHostMsg_OpenChannelToTab(
+ render_frame->GetRoutingID(), info, extension_id, channel_name,
+ port_id));
+ }
+
+ args.GetReturnValue().Set(static_cast<int32_t>(js_id));
}
-void MessagingBindings::ClosePort(int local_port_id, bool force_close) {
+void MessagingBindings::ClosePort(int js_port_id, bool force_close) {
// TODO(robwu): Merge this logic with CloseChannel once the TODO in BindToGC
// has been addressed.
- auto iter = ports_.find(local_port_id);
+ auto iter = ports_.find(js_port_id);
if (iter != ports_.end()) {
std::unique_ptr<ExtensionPort> port = std::move(iter->second);
ports_.erase(iter);
port->Close(force_close);
- // If the port hasn't been initialized, we can't delete it just yet, because
- // we need to wait for it to send any pending messages. This is important
- // to support the flow:
- // var port = chrome.runtime.connect();
- // port.postMessage({message});
- // port.disconnect();
- if (!port->initialized())
- disconnected_ports_[port->local_id()] = std::move(port);
}
}
-void MessagingBindings::SetGlobalPortId(int local_id, int global_id) {
- auto iter = ports_.find(local_id);
- if (iter != ports_.end()) {
- iter->second->SetGlobalId(global_id);
- return;
- }
-
- iter = disconnected_ports_.find(local_id);
- DCHECK(iter != disconnected_ports_.end());
- iter->second->SetGlobalId(global_id);
- // Setting the global id dispatches pending messages, so we can delete the
- // port now.
- disconnected_ports_.erase(iter);
+int MessagingBindings::GetNextJsId() {
+ return next_js_id_++;
}
-int MessagingBindings::GetNextLocalId() { return next_local_id_++; }
-
} // namespace extensions
« no previous file with comments | « extensions/renderer/messaging_bindings.h ('k') | third_party/WebKit/Source/web/WebDocument.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698