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

Unified Diff: chrome/browser/extensions/api/messaging/extension_message_port.cc

Issue 1413543005: Use FrameTreeNode ID as frameId in extension APIs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Improve port lifetime management, add tests Created 5 years, 2 months 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
Index: chrome/browser/extensions/api/messaging/extension_message_port.cc
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.cc b/chrome/browser/extensions/api/messaging/extension_message_port.cc
index 1e4f87f901d6234975f9d3a6dccfcf139172fd3b..caaca145a5aa8da2e4fd30f95c5d6ce8753a6a02 100644
--- a/chrome/browser/extensions/api/messaging/extension_message_port.cc
+++ b/chrome/browser/extensions/api/messaging/extension_message_port.cc
@@ -5,36 +5,136 @@
#include "chrome/browser/extensions/api/messaging/extension_message_port.h"
#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/process_manager.h"
+#include "extensions/browser/process_manager_observer.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/manifest_handlers/background_info.h"
namespace extensions {
-ExtensionMessagePort::ExtensionMessagePort(content::RenderProcessHost* process,
- int routing_id,
- const std::string& extension_id)
- : process_(process),
- routing_id_(routing_id),
- extension_id_(extension_id),
- background_host_ptr_(NULL) {
+const char kReceivingEndDoesntExistError[] =
+ "Could not establish connection. Receiving end does not exist.";
+
+// Helper class to detect when frames are destroyed.
+class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver,
+ public ProcessManagerObserver {
+ public:
+ // Watch all frames in an extension process.
+ explicit FrameTracker(ExtensionMessagePort* port) : port_(port) {
+ ProcessManager::Get(port_->browser_context_)->AddObserver(this);
+ }
+ // Watch all frames in a tab.
+ // TODO(robwu): Check whether this includes background pages and <webview>s.
+ FrameTracker(ExtensionMessagePort* port, content::WebContents* tab)
+ : content::WebContentsObserver(tab), port_(port) {
+ }
+ ~FrameTracker() override {
+ ProcessManager::Get(port_->browser_context_)->RemoveObserver(this);
+ }
Devlin 2015/10/30 01:49:39 nit: newline
robwu 2015/11/02 19:08:34 Done.
+ private:
+ // content::WebContentsObserver overrides:
+ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host)
Devlin 2015/10/30 01:49:39 I would have thought FrameDeleted here - are you s
robwu 2015/10/31 00:10:45 I initially used FrameDeleted (as you can see in p
Devlin 2015/10/31 00:19:56 Interesting. I defer to Charlie's judgment for wh
Charlie Reis 2015/11/03 00:23:49 RenderFrameDeleted is for cases where you care whe
+ override {
+ port_->UnregisterFrame(render_frame_host);
+ }
+ void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host,
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams&) override {
+ if (!details.is_in_page)
+ port_->UnregisterFrame(render_frame_host);
+ }
+
+ // extensions::ProcessManagerObserver overrides:
+ void OnExtensionFrameUnregistered(
+ const std::string& extension_id,
+ content::RenderFrameHost* render_frame_host) override {
+ if (extension_id == port_->extension_id_)
+ {
Devlin 2015/10/30 01:49:39 bracket
robwu 2015/11/02 19:08:33 Done.
+ DVLOG(2) << "OnExtensionFrameUnregistered " << port_->port_id_ << " for "
Devlin 2015/10/30 01:49:39 We don't usually like to commit logs (even [D]VLOG
robwu 2015/10/31 00:10:45 Oops, I did not intend to commit this one. I usual
Devlin 2015/10/31 00:19:56 Probably all of them, but if there's one or two yo
robwu 2015/11/02 19:08:34 Done.
+ << "frame " << render_frame_host << " " << " in extension "
+ << extension_id;
+ port_->UnregisterFrame(render_frame_host);
+ }
+ }
+
+ ExtensionMessagePort* port_;
+ DISALLOW_COPY_AND_ASSIGN(FrameTracker);
+};
+
+ExtensionMessagePort::ExtensionMessagePort(
+ base::WeakPtr<MessageService> message_service,
+ int port_id,
+ const std::string& extension_id,
+ content::RenderProcessHost* extension_process)
+ : weak_message_service_(message_service),
+ port_id_(port_id),
+ extension_id_(extension_id),
+ did_create_port_(false),
+ browser_context_(extension_process->GetBrowserContext()),
+ frames_(ProcessManager::Get(browser_context_)->
+ GetRenderFrameHostsForExtension(extension_id)),
+ extension_process_(extension_process),
+ background_host_ptr_(nullptr),
+ frame_tracker_(new FrameTracker(this)) {
+ DVLOG(2) << "Created ExtensionMessagePort " << port_id_ << " for extension "
+ << extension_id_ << " with " << frames_.size() << " frame(s).";
+}
+
+bool ExtensionMessagePort::IsValidPort() {
+ return !frames_.empty();
+}
+
+ExtensionMessagePort::ExtensionMessagePort(
+ base::WeakPtr<MessageService> message_service,
+ int port_id,
+ const std::string& extension_id,
+ content::RenderFrameHost* rfh,
+ bool include_child_frames)
+ : weak_message_service_(message_service),
+ port_id_(port_id),
+ extension_id_(extension_id),
+ did_create_port_(false),
+ browser_context_(rfh->GetProcess()->GetBrowserContext()),
+ frames_(),
+ extension_process_(nullptr),
+ background_host_ptr_(nullptr),
+ frame_tracker_() {
+ content::WebContents* tab = content::WebContents::FromRenderFrameHost(rfh);
+ DCHECK(tab);
+ frame_tracker_.reset(new FrameTracker(this, tab));
+ if (include_child_frames) {
+ tab->ForEachFrame(base::Bind(&ExtensionMessagePort::RegisterFrame,
+ base::Unretained(this)));
+ } else {
+ RegisterFrame(rfh);
+ }
+ DVLOG(2) << "Created ExtensionMessagePort " << port_id_ << " for "
+ << frames_.size() << " frame(s).";
+}
+
+ExtensionMessagePort::~ExtensionMessagePort() {
+ frame_tracker_.reset();
+ DVLOG(2) << "Destroyed ExtensionMessagePort " << port_id_;
}
void ExtensionMessagePort::DispatchOnConnect(
- int dest_port_id,
const std::string& channel_name,
scoped_ptr<base::DictionaryValue> source_tab,
int source_frame_id,
- int target_tab_id,
- int target_frame_id,
int guest_process_id,
int guest_render_frame_routing_id,
const std::string& source_extension_id,
const std::string& target_extension_id,
const GURL& source_url,
const std::string& tls_channel_id) {
+ DVLOG(2) << "ExtensionMessagePort::DispatchOnConnect " << port_id_;
+
ExtensionMsg_TabConnectionInfo source;
if (source_tab)
source.tab.Swap(source_tab.get());
@@ -44,32 +144,30 @@ void ExtensionMessagePort::DispatchOnConnect(
info.target_id = target_extension_id;
info.source_id = source_extension_id;
info.source_url = source_url;
- info.target_tab_id = target_tab_id;
- info.target_frame_id = target_frame_id;
info.guest_process_id = guest_process_id;
info.guest_render_frame_routing_id = guest_render_frame_routing_id;
- process_->Send(new ExtensionMsg_DispatchOnConnect(
- routing_id_, dest_port_id, channel_name, source, info, tls_channel_id));
+ SendToPort(new ExtensionMsg_DispatchOnConnect(
+ MSG_ROUTING_NONE, port_id_, channel_name, source, info, tls_channel_id));
}
void ExtensionMessagePort::DispatchOnDisconnect(
- int source_port_id,
const std::string& error_message) {
- process_->Send(new ExtensionMsg_DispatchOnDisconnect(
- routing_id_, source_port_id, error_message));
+ DVLOG(2) << "ExtensionMessagePort::DispatchOnDisconnect " << port_id_;
+
+ SendToPort(new ExtensionMsg_DispatchOnDisconnect(
+ MSG_ROUTING_NONE, port_id_, error_message));
}
-void ExtensionMessagePort::DispatchOnMessage(const Message& message,
- int target_port_id) {
- process_->Send(new ExtensionMsg_DeliverMessage(
- routing_id_, target_port_id, message));
+void ExtensionMessagePort::DispatchOnMessage(const Message& message) {
+ DVLOG(2) << "ExtensionMessagePort::DispatchOnMessage " << port_id_;
+
+ SendToPort(new ExtensionMsg_DeliverMessage(
+ MSG_ROUTING_NONE, port_id_, message));
}
void ExtensionMessagePort::IncrementLazyKeepaliveCount() {
- Profile* profile =
- Profile::FromBrowserContext(process_->GetBrowserContext());
- extensions::ProcessManager* pm = ProcessManager::Get(profile);
+ ProcessManager* pm = ProcessManager::Get(browser_context_);
ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_);
if (host && BackgroundInfo::HasLazyBackgroundPage(host->extension()))
pm->IncrementLazyKeepaliveCount(host->extension());
@@ -80,16 +178,77 @@ void ExtensionMessagePort::IncrementLazyKeepaliveCount() {
}
void ExtensionMessagePort::DecrementLazyKeepaliveCount() {
- Profile* profile =
- Profile::FromBrowserContext(process_->GetBrowserContext());
- extensions::ProcessManager* pm = ProcessManager::Get(profile);
+ ProcessManager* pm = ProcessManager::Get(browser_context_);
ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_);
if (host && host == background_host_ptr_)
pm->DecrementLazyKeepaliveCount(host->extension());
}
-content::RenderProcessHost* ExtensionMessagePort::GetRenderProcessHost() {
- return process_;
+void ExtensionMessagePort::OpenPort(int process_id, int routing_id) {
+ DCHECK(routing_id != MSG_ROUTING_NONE || extension_process_);
+ DVLOG_IF(2, !extension_process_) << "ExtensionMessagePort::OpenPort "
+ << port_id_ << " from frame "
+ << content::RenderFrameHost::FromID(process_id, routing_id);
+ DVLOG_IF(2, extension_process_) << "ExtensionMessagePort::OpenPort "
+ << port_id_ << " from extension " << extension_id_;
+
+ // Mark port as active, so we can distinguish abnormal port closure from
+ // explicit port closure via disconnect().
+ did_create_port_ = true;
+}
+
+void ExtensionMessagePort::ClosePort(int process_id, int routing_id) {
+ if (routing_id == MSG_ROUTING_NONE) {
+ // The only non-frame-specific message is the response to an unhandled
+ // onConnect event in the extension process.
+ DCHECK(extension_process_);
+ DVLOG(2) << "ExtensionMessagePort::ClosePort " << port_id_ << " from "
+ << "extension " << extension_id_;
+
+ frames_.clear();
+ CloseChannel();
+ return;
+ }
+
+ content::RenderFrameHost* rfh =
+ content::RenderFrameHost::FromID(process_id, routing_id);
+ DVLOG(2) << "ExtensionMessagePort::ClosePort " << port_id_ << " for frame "
+ << rfh;
+ if (rfh)
+ UnregisterFrame(rfh);
+}
+
+void ExtensionMessagePort::CloseChannel() {
+ DVLOG(2) << "ExtensionMessagePort::CloseChannel " << port_id_;
+
+ std::string error_message = did_create_port_ ? std::string() :
+ kReceivingEndDoesntExistError;
+ if (weak_message_service_)
+ weak_message_service_->CloseChannel(port_id_, error_message);
+}
+
+void ExtensionMessagePort::RegisterFrame(content::RenderFrameHost* rfh) {
+ frames_.insert(rfh);
+}
+
+void ExtensionMessagePort::UnregisterFrame(content::RenderFrameHost* rfh) {
+ if (frames_.erase(rfh) != 0 && frames_.empty())
+ CloseChannel();
+}
+
+void ExtensionMessagePort::SendToPort(IPC::Message* msg) {
+ DCHECK_GT(frames_.size(), 0UL);
+ if (extension_process_) {
+ msg->set_routing_id(MSG_ROUTING_CONTROL);
+ extension_process_->Send(msg);
+ return;
+ }
+ for (content::RenderFrameHost* rfh : frames_) {
+ IPC::Message* msg_copy = new IPC::Message(*msg);
+ msg_copy->set_routing_id(rfh->GetRoutingID());
+ rfh->Send(msg_copy);
+ }
+ delete msg;
}
} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698