diff options
7 files changed, 107 insertions, 77 deletions
diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc index 48fb0ca..9c9a50d 100644 --- a/chrome/browser/extensions/extension_browsertests_misc.cc +++ b/chrome/browser/extensions/extension_browsertests_misc.cc @@ -286,12 +286,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MessagingExtensionTab) { .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa") .AppendASCII("1.0"))); - // Get the ExtensionHost that is hosting our background page. + // Get the ExtensionHost that is hosting our toolstrip page. ExtensionProcessManager* manager = browser()->profile()->GetExtensionProcessManager(); - ExtensionHost* host = FindHostWithPath(manager, "/background.html", 1); + ExtensionHost* host = FindHostWithPath(manager, "/toolstrip.html", 1); - // Load the tab that will communicate with our background page. + // Load the tab that will communicate with our toolstrip. ui_test_utils::NavigateToURL( browser(), GURL("chrome-extension://bjafgdebaacbbbecmhlhpofkepfkgcpa/page.html")); @@ -321,8 +321,6 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MessagingExtensionTab) { } // Tests that message passing between extensions and content scripts works. -#if 0 -// TODO(mpcomplete): re-enable this IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MessagingContentScript) { ASSERT_TRUE(LoadExtension( test_data_dir_.AppendASCII("good").AppendASCII("Extensions") @@ -339,13 +337,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MessagingContentScript) { } ASSERT_TRUE(master->ScriptsReady()); - // Get the ExtensionHost that is hosting our background page. + // Get the ExtensionHost that is hosting our toolstrip page. ExtensionProcessManager* manager = browser()->profile()->GetExtensionProcessManager(); - ExtensionHost* host = FindHostWithPath(manager, "/background.html", 1); + ExtensionHost* host = FindHostWithPath(manager, "/toolstrip.html", 1); - // Load the tab whose content script will communicate with our background - // page. + // Load the tab whose content script will communicate with our toolstrip. FilePath test_file; PathService::Get(chrome::DIR_TEST_DATA, &test_file); test_file = test_file.AppendASCII("extensions") @@ -375,4 +372,3 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MessagingContentScript) { host->render_view_host(), L"", L"testDisconnectOnClose()", &result); EXPECT_TRUE(result); } -#endif diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc index 5424ad2..d4e6d0f 100644 --- a/chrome/browser/extensions/extension_message_service.cc +++ b/chrome/browser/extensions/extension_message_service.cc @@ -130,15 +130,23 @@ void ExtensionMessageService::ProfileDestroyed() { void ExtensionMessageService::AddEventListener(std::string event_name, int render_process_id) { + DCHECK(RenderProcessHost::FromID(render_process_id)) << + "Adding event listener to a non-existant RenderProcessHost."; DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); - DCHECK(listeners_[event_name].count(render_process_id) == 0); + DCHECK_EQ(listeners_[event_name].count(render_process_id), 0u) << event_name; listeners_[event_name].insert(render_process_id); } void ExtensionMessageService::RemoveEventListener(std::string event_name, int render_process_id) { + // It is possible that this RenderProcessHost is being destroyed. If that is + // the case, we'll have already removed his listeners, so do nothing here. + RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id); + if (!rph) + return; + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); - DCHECK(listeners_[event_name].count(render_process_id) == 1); + DCHECK_EQ(listeners_[event_name].count(render_process_id), 1u) << event_name; listeners_[event_name].erase(render_process_id); } @@ -245,9 +253,15 @@ void ExtensionMessageService::OpenChannelOnUIThreadImpl( DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); // TODO(mpcomplete): notify source if reciever doesn't exist - if (!source || !receiver.sender) + if (!source) return; // Closed while in flight. + if (!receiver.sender) { + // Treat it as a disconnect. + DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL), + GET_OPPOSITE_PORT_ID(receiver_port_id)); + } + linked_ptr<MessageChannel> channel(new MessageChannel); channel->opener = MessagePort(source, MSG_ROUTING_CONTROL); channel->receiver = receiver; diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc index 863ebbf..81924cb 100644 --- a/chrome/renderer/extensions/event_bindings.cc +++ b/chrome/renderer/extensions/event_bindings.cc @@ -129,8 +129,7 @@ static void DeferredUnload(v8::Persistent<v8::Context> context) { context.Clear(); } -static void HandleContextDestroyed(ContextList::iterator context_iter, - bool in_gc) { +static void UnregisterContext(ContextList::iterator context_iter, bool in_gc) { // Notify the bindings that they're going away. if (in_gc) { // We shouldn't call back into javascript during a garbage collect. Do it @@ -154,14 +153,6 @@ static void HandleContextDestroyed(ContextList::iterator context_iter, } } - // Unload any content script contexts for this frame. - for (ContextList::iterator it = GetContexts().begin(); - it != GetContexts().end(); ) { - ContextList::iterator current = it++; - if ((*current)->parent_context == (*context_iter)->context) - HandleContextDestroyed(current, in_gc); - } - if (!(*context_iter)->parent_context.IsEmpty()) { (*context_iter)->parent_context.Dispose(); (*context_iter)->parent_context.Clear(); @@ -179,10 +170,11 @@ static void HandleContextDestroyed(ContextList::iterator context_iter, static void ContextWeakReferenceCallback(v8::Persistent<v8::Value> context, void*) { + // This should only get called for content script contexts. for (ContextList::iterator it = GetContexts().begin(); it != GetContexts().end(); ++it) { if ((*it)->context == context) { - HandleContextDestroyed(it, true); + UnregisterContext(it, true); return; } } @@ -258,7 +250,16 @@ void EventBindings::HandleContextDestroyed(WebFrame* frame) { ContextList::iterator context_iter = bindings_utils::FindContext(context); if (context_iter != GetContexts().end()) - ::HandleContextDestroyed(context_iter, false); + UnregisterContext(context_iter, false); + + // Unload any content script contexts for this frame. Note that the frame + // itself might not be registered, but can still be a parent context. + for (ContextList::iterator it = GetContexts().begin(); + it != GetContexts().end(); ) { + ContextList::iterator current = it++; + if ((*current)->parent_context == context) + UnregisterContext(current, false); + } } // static diff --git a/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/background.html b/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/background.html deleted file mode 100644 index d68d4d6..0000000 --- a/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/background.html +++ /dev/null @@ -1,38 +0,0 @@ -<script>
-chrome.extension.onConnect.addListener(function(port) {
- port.onMessage.addListener(function(msg) {
- if (msg.testPostMessageFromTab) {
- port.postMessage({success: true});
- }
- // Ignore other messages since they are from us.
- });
-});
-
-// Tests that postMessage to the tab and its response works.
-function testPostMessage() {
- var port = chrome.extension.connect();
- port.postMessage({testPostMessage: true});
- port.onMessage.addListener(function(msg) {
- window.domAutomationController.send(msg.success);
- port.disconnect();
- });
-}
-
-// Tests that we get the disconnect event when the tab disconnect.
-function testDisconnect() {
- var port = chrome.extension.connect();
- port.postMessage({testDisconnect: true});
- port.onDisconnect.addListener(function() {
- window.domAutomationController.send(true);
- });
-}
-
-// Tests that we get the disconnect event when the tab context closes.
-function testDisconnectOnClose() {
- var port = chrome.extension.connect();
- port.postMessage({testDisconnectOnClose: true});
- port.onDisconnect.addListener(function() {
- window.domAutomationController.send(true);
- });
-}
-</script>
diff --git a/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/manifest.json b/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/manifest.json index b1a24a9..6cb06ff 100644 --- a/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/manifest.json +++ b/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/manifest.json @@ -2,7 +2,7 @@ "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRS2GUBOUAO5VZ2CMRId/eRR8/e9V42nUvY5XG+0sZ+JDHEjIQdq8qQy7HqdqEpCXKPMSPuMiC2t2HE9/hpL89SblNn3mwYPtSJGQdZvAzuv6SB0oA6jZ66V7+h/k0noGD3Tcu+Ko/vfkt5wCx2uHVK29k5JR/vGr0klaoVezGlwIDAQAB", "version": "1.0", "name": "My extension 3", - "background_page": "background.html", + "toolstrips": ["toolstrip.html"], "content_scripts": [ { "matches": ["file://*"], diff --git a/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/page.js b/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/page.js index 7adb0c5..cee9476 100644 --- a/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/page.js +++ b/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/page.js @@ -3,20 +3,24 @@ if (typeof(contentWindow) != 'undefined') { win = contentWindow; } -chrome.extension.onConnect.addListener(function(port) { - console.log('connected'); - port.onMessage.addListener(function(msg) { - console.log('got ' + msg); - if (msg.testPostMessage) { - port.postMessage({success: true}); - } else if (msg.testDisconnect) { - port.disconnect(); - } else if (msg.testDisconnectOnClose) { - win.location = "about:blank"; - } - // Ignore other messages since they are from us. +win.onload = function() { + // Do this in an onload handler because I'm not sure if chrome.extension + // is available before then. + chrome.extension.onConnect.addListener(function(port) { + console.log('connected'); + port.onMessage.addListener(function(msg) { + console.log('got ' + msg); + if (msg.testPostMessage) { + port.postMessage({success: true}); + } else if (msg.testDisconnect) { + port.disconnect(); + } else if (msg.testDisconnectOnClose) { + win.location = "about:blank"; + } + // Ignore other messages since they are from us. + }); }); -}); +} // Tests that postMessage to the extension and its response works. win.testPostMessageFromTab = function() { @@ -29,3 +33,10 @@ win.testPostMessageFromTab = function() { }); console.log('posted message'); } + +// Workaround two bugs: shutdown crash if we hook 'unload', and content script +// GC if we don't register any event handlers. +// http://code.google.com/p/chromium/issues/detail?id=17410 +// http://code.google.com/p/chromium/issues/detail?id=17582 +function foo() {} +win.addEventListener('error', foo); diff --git a/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/toolstrip.html b/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/toolstrip.html new file mode 100644 index 0000000..aae7daa --- /dev/null +++ b/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/toolstrip.html @@ -0,0 +1,46 @@ +<script>
+window.onload = function() {
+ chrome.extension.onConnect.addListener(function(port) {
+ port.onMessage.addListener(function(msg) {
+ if (msg.testPostMessageFromTab) {
+ port.postMessage({success: true});
+ }
+ // Ignore other messages since they are from us.
+ });
+ });
+};
+
+// Tests that postMessage to the tab and its response works.
+function testPostMessage() {
+ chrome.tabs.getSelected(null, function(tab) {
+ var port = chrome.tabs.connect(tab.id);
+ port.postMessage({testPostMessage: true});
+ port.onMessage.addListener(function(msg) {
+ window.domAutomationController.send(msg.success);
+ port.disconnect();
+ });
+ });
+}
+
+// Tests that we get the disconnect event when the tab disconnect.
+function testDisconnect() {
+ chrome.tabs.getSelected(null, function(tab) {
+ var port = chrome.tabs.connect(tab.id);
+ port.postMessage({testDisconnect: true});
+ port.onDisconnect.addListener(function() {
+ window.domAutomationController.send(true);
+ });
+ });
+}
+
+// Tests that we get the disconnect event when the tab context closes.
+function testDisconnectOnClose() {
+ chrome.tabs.getSelected(null, function(tab) {
+ var port = chrome.tabs.connect(tab.id);
+ port.postMessage({testDisconnectOnClose: true});
+ port.onDisconnect.addListener(function() {
+ window.domAutomationController.send(true);
+ });
+ });
+}
+</script>
|