diff options
25 files changed, 284 insertions, 30 deletions
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 67a8da0..b5e0f6c 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -457,6 +457,7 @@ void ChromeContentBrowserClient::AppendExtraCommandLineSwitches( switches::kEnableExperimentalExtensionApis, switches::kEnableInBrowserThumbnailing, switches::kEnableIPCFuzzing, + switches::kEnableLazyBackgroundPages, switches::kEnableNaCl, switches::kEnablePrintPreview, switches::kEnableSearchProviderApiV2, diff --git a/chrome/browser/extensions/alert_apitest.cc b/chrome/browser/extensions/alert_apitest.cc index 24fe043..fe026b6 100644 --- a/chrome/browser/extensions/alert_apitest.cc +++ b/chrome/browser/extensions/alert_apitest.cc @@ -9,6 +9,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h" #include "chrome/browser/ui/browser.h" +#include "chrome/common/extensions/extension.h" #include "chrome/test/base/ui_test_utils.h" #include "content/browser/renderer_host/render_view_host.h" @@ -17,7 +18,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, AlertBasic) { const Extension* extension = GetSingleLoadedExtension(); ExtensionHost* host = browser()->profile()->GetExtensionProcessManager()-> - GetBackgroundHostForExtension(extension); + GetBackgroundHostForExtension(extension->id()); ASSERT_TRUE(host); host->render_view_host()->ExecuteJavascriptInWebFrame(string16(), ASCIIToUTF16("alert('This should not crash.');")); diff --git a/chrome/browser/extensions/browser_action_apitest.cc b/chrome/browser/extensions/browser_action_apitest.cc index bf6fbf1..39b6f9c 100644 --- a/chrome/browser/extensions/browser_action_apitest.cc +++ b/chrome/browser/extensions/browser_action_apitest.cc @@ -392,7 +392,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, DISABLED_CloseBackgroundPage) { // There is a background page and a browser action with no badge text. ExtensionProcessManager* manager = browser()->profile()->GetExtensionProcessManager(); - ASSERT_TRUE(manager->GetBackgroundHostForExtension(extension)); + ASSERT_TRUE(manager->GetBackgroundHostForExtension(extension->id())); ExtensionAction* action = extension->browser_action(); ASSERT_EQ("", action->GetBadgeText(ExtensionAction::kDefaultTabId)); @@ -409,6 +409,6 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, DISABLED_CloseBackgroundPage) { // so we wait for the notification before checking that it's really gone // and the badge text has been set. host_destroyed_observer.Wait(); - ASSERT_FALSE(manager->GetBackgroundHostForExtension(extension)); + ASSERT_FALSE(manager->GetBackgroundHostForExtension(extension->id())); ASSERT_EQ("X", action->GetBadgeText(ExtensionAction::kDefaultTabId)); } diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc index a4cf4a9..3898d87 100644 --- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc +++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc @@ -67,8 +67,8 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { GetExtensionService()->extensions()->at(index); ASSERT_TRUE(extension); std::string extension_id(extension->id()); - ExtensionHost* extension_host = - GetExtensionProcessManager()->GetBackgroundHostForExtension(extension); + ExtensionHost* extension_host = GetExtensionProcessManager()-> + GetBackgroundHostForExtension(extension_id); ASSERT_TRUE(extension_host); RenderProcessHost* extension_rph = @@ -76,8 +76,8 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { base::KillProcess(extension_rph->GetHandle(), content::RESULT_CODE_KILLED, false); ASSERT_TRUE(WaitForExtensionCrash(extension_id)); - ASSERT_FALSE( - GetExtensionProcessManager()->GetBackgroundHostForExtension(extension)); + ASSERT_FALSE(GetExtensionProcessManager()-> + GetBackgroundHostForExtension(extension_id)); } void CheckExtensionConsistency(size_t index) { @@ -85,8 +85,8 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { const Extension* extension = GetExtensionService()->extensions()->at(index); ASSERT_TRUE(extension); - ExtensionHost* extension_host = - GetExtensionProcessManager()->GetBackgroundHostForExtension(extension); + ExtensionHost* extension_host = GetExtensionProcessManager()-> + GetBackgroundHostForExtension(extension->id()); ASSERT_TRUE(extension_host); ASSERT_TRUE(GetExtensionProcessManager()->HasExtensionHost(extension_host)); ASSERT_TRUE(extension_host->IsRenderViewLive()); diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc index 74dd20a..8f18685 100644 --- a/chrome/browser/extensions/extension_event_router.cc +++ b/chrome/browser/extensions/extension_event_router.cc @@ -217,7 +217,7 @@ bool ExtensionEventRouter::CanDispatchEventNow( GetExtensionById(extension_id, false); // exclude disabled extensions if (extension && extension->background_url().is_valid()) { ExtensionProcessManager* pm = profile_->GetExtensionProcessManager(); - if (!pm->GetBackgroundHostForExtension(extension)) { + if (!pm->GetBackgroundHostForExtension(extension_id)) { pm->CreateBackgroundHost(extension, extension->background_url()); return false; } diff --git a/chrome/browser/extensions/extension_management_browsertest.cc b/chrome/browser/extensions/extension_management_browsertest.cc index 1bae8ee..feddcdc 100644 --- a/chrome/browser/extensions/extension_management_browsertest.cc +++ b/chrome/browser/extensions/extension_management_browsertest.cc @@ -40,7 +40,8 @@ class ExtensionManagementTest : public ExtensionBrowserTest { // sync with the Extension. ExtensionProcessManager* manager = browser()->profile()-> GetExtensionProcessManager(); - ExtensionHost* ext_host = manager->GetBackgroundHostForExtension(extension); + ExtensionHost* ext_host = + manager->GetBackgroundHostForExtension(extension->id()); EXPECT_TRUE(ext_host); if (!ext_host) return false; @@ -205,26 +206,26 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DisableEnable) { const size_t size_before = service->extensions()->size(); // Load an extension, expect the background page to be available. + std::string extension_id = "bjafgdebaacbbbecmhlhpofkepfkgcpa"; ASSERT_TRUE(LoadExtension( test_data_dir_.AppendASCII("good").AppendASCII("Extensions") - .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa") + .AppendASCII(extension_id) .AppendASCII("1.0"))); ASSERT_EQ(size_before + 1, service->extensions()->size()); EXPECT_EQ(0u, service->disabled_extensions()->size()); - const Extension* extension = service->extensions()->at(size_before); - EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension)); + EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension_id)); // After disabling, the background page should go away. - service->DisableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa"); + service->DisableExtension(extension_id); EXPECT_EQ(size_before, service->extensions()->size()); EXPECT_EQ(1u, service->disabled_extensions()->size()); - EXPECT_FALSE(manager->GetBackgroundHostForExtension(extension)); + EXPECT_FALSE(manager->GetBackgroundHostForExtension(extension_id)); // And bring it back. - service->EnableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa"); + service->EnableExtension(extension_id); EXPECT_EQ(size_before + 1, service->extensions()->size()); EXPECT_EQ(0u, service->disabled_extensions()->size()); - EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension)); + EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension_id)); } // Used for testing notifications sent during extension updates. diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc index df68f78..c2a61d8 100644 --- a/chrome/browser/extensions/extension_process_manager.cc +++ b/chrome/browser/extensions/extension_process_manager.cc @@ -191,7 +191,7 @@ void ExtensionProcessManager::CreateBackgroundHost( return; // Don't create multiple background hosts for an extension. - if (GetBackgroundHostForExtension(extension)) + if (GetBackgroundHostForExtension(extension->id())) return; ExtensionHost* host = @@ -227,14 +227,15 @@ void ExtensionProcessManager::OpenOptionsPage(const Extension* extension, } ExtensionHost* ExtensionProcessManager::GetBackgroundHostForExtension( - const Extension* extension) { + const std::string& extension_id) { for (ExtensionHostSet::iterator iter = background_hosts_.begin(); iter != background_hosts_.end(); ++iter) { ExtensionHost* host = *iter; - if (host->extension() == extension) + if (host->extension_id() == extension_id) return host; } return NULL; + } std::set<RenderViewHost*> @@ -417,6 +418,27 @@ bool ExtensionProcessManager::HasExtensionHost(ExtensionHost* host) const { return all_hosts_.find(host) != all_hosts_.end(); } +void ExtensionProcessManager::OnExtensionIdle(const std::string& extension_id) { + ExtensionHost* host = GetBackgroundHostForExtension(extension_id); + if (host && !HasVisibleViews(extension_id)) + CloseBackgroundHost(host); +} + +bool ExtensionProcessManager::HasVisibleViews(const std::string& extension_id) { + const std::set<RenderViewHost*>& views = + GetRenderViewHostsForExtension(extension_id); + for (std::set<RenderViewHost*>::const_iterator it = views.begin(); + it != views.end(); ++it) { + const RenderViewHost* host = *it; + if (host->site_instance()->site().host() == extension_id && + host->delegate()->GetRenderViewType() != + chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { + return true; + } + } + return false; +} + void ExtensionProcessManager::Observe( int type, const content::NotificationSource& source, @@ -447,9 +469,7 @@ void ExtensionProcessManager::Observe( iter != background_hosts_.end(); ++iter) { ExtensionHost* host = *iter; if (host->extension_id() == extension->id()) { - delete host; - // |host| should deregister itself from our structures. - DCHECK(background_hosts_.find(host) == background_hosts_.end()); + CloseBackgroundHost(host); break; } } @@ -473,9 +493,7 @@ void ExtensionProcessManager::Observe( ExtensionHost* host = content::Details<ExtensionHost>(details).ptr(); if (host->extension_host_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { - delete host; - // |host| should deregister itself from our structures. - CHECK(background_hosts_.find(host) == background_hosts_.end()); + CloseBackgroundHost(host); } break; } @@ -506,6 +524,14 @@ void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host, content::Details<ExtensionHost>(host)); } +void ExtensionProcessManager::CloseBackgroundHost(ExtensionHost* host) { + CHECK(host->extension_host_type() == + chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); + delete host; + // |host| should deregister itself from our structures. + CHECK(background_hosts_.find(host) == background_hosts_.end()); +} + void ExtensionProcessManager::CloseBackgroundHosts() { for (ExtensionHostSet::iterator iter = background_hosts_.begin(); iter != background_hosts_.end(); ) { diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h index 6ecd784..41d0bbb 100644 --- a/chrome/browser/extensions/extension_process_manager.h +++ b/chrome/browser/extensions/extension_process_manager.h @@ -65,7 +65,7 @@ class ExtensionProcessManager : public content::NotificationObserver { // Gets the ExtensionHost for the background page for an extension, or NULL if // the extension isn't running or doesn't have a background page. - ExtensionHost* GetBackgroundHostForExtension(const Extension* extension); + ExtensionHost* GetBackgroundHostForExtension(const std::string& extension_id); // Returns the SiteInstance that the given URL belongs to. virtual SiteInstance* GetSiteInstanceForURL(const GURL& url); @@ -107,6 +107,10 @@ class ExtensionProcessManager : public content::NotificationObserver { // Returns true if |host| is managed by this process manager. bool HasExtensionHost(ExtensionHost* host) const; + // Called when the render reports that the extension is idle (only if + // lazy background pages are enabled). + void OnExtensionIdle(const std::string& extension_id); + typedef std::set<ExtensionHost*> ExtensionHostSet; typedef ExtensionHostSet::const_iterator const_iterator; const_iterator begin() const { return all_hosts_.begin(); } @@ -158,6 +162,13 @@ class ExtensionProcessManager : public content::NotificationObserver { typedef std::set<RenderViewHost*> RenderViewHostSet; RenderViewHostSet all_extension_views_; + private: + // Close the given |host| iff it's a background page. + void CloseBackgroundHost(ExtensionHost* host); + + // Excludes background page. + bool HasVisibleViews(const std::string& extension_id); + DISALLOW_COPY_AND_ASSIGN(ExtensionProcessManager); }; diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 2e990da..7c71eb1 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -838,8 +838,7 @@ void ExtensionService::ReloadExtension(const std::string& extension_id) { // the inspector and hang onto a cookie for it, so that we can reattach // later. ExtensionProcessManager* manager = profile_->GetExtensionProcessManager(); - ExtensionHost* host = manager->GetBackgroundHostForExtension( - current_extension); + ExtensionHost* host = manager->GetBackgroundHostForExtension(extension_id); if (host) { // Look for an open inspector for the background page. int devtools_cookie = DevToolsManager::GetInstance()->DetachClientHost( diff --git a/chrome/browser/extensions/lazy_background_page_apitest.cc b/chrome/browser/extensions/lazy_background_page_apitest.cc new file mode 100644 index 0000000..db3e7c5 --- /dev/null +++ b/chrome/browser/extensions/lazy_background_page_apitest.cc @@ -0,0 +1,128 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" +#include "base/file_path.h" +#include "chrome/browser/extensions/browser_action_test_util.h" +#include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/omnibox/location_bar.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/public/browser/notification_service.h" + +#include "googleurl/src/gurl.h" + +class LazyBackgroundPageApiTest : public ExtensionApiTest { +public: + void SetUpCommandLine(CommandLine* command_line) { + ExtensionApiTest::SetUpCommandLine(command_line); + command_line->AppendSwitch(switches::kEnableLazyBackgroundPages); + } +}; + +IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, BrowserActionCreateTab) { + ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableLazyBackgroundPages)); + + FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page"). + AppendASCII("browser_action_create_tab"); + ASSERT_TRUE(LoadExtension(extdir)); + + // Lazy Background Page doesn't exist yet. + ExtensionProcessManager* pm = + browser()->profile()->GetExtensionProcessManager(); + EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); + int num_tabs_before = browser()->tab_count(); + + // Observe background page being created and closed after + // the browser action is clicked. + ui_test_utils::WindowedNotificationObserver bg_pg_created( + chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, + content::NotificationService::AllSources()); + ui_test_utils::WindowedNotificationObserver bg_pg_closed( + chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, + content::NotificationService::AllSources()); + BrowserActionTestUtil(browser()).Press(0); + bg_pg_created.Wait(); + bg_pg_closed.Wait(); + + // Background page created a new tab before it closed. + EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); + EXPECT_EQ(num_tabs_before + 1, browser()->tab_count()); + EXPECT_EQ("chrome://extensions/", + browser()->GetSelectedTabContents()->GetURL().spec()); +} + +IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, + BrowserActionCreateTabAfterCallback) { + ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableLazyBackgroundPages)); + + FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page"). + AppendASCII("browser_action_with_callback"); + ASSERT_TRUE(LoadExtension(extdir)); + + // Lazy Background Page doesn't exist yet. + ExtensionProcessManager* pm = + browser()->profile()->GetExtensionProcessManager(); + EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); + int num_tabs_before = browser()->tab_count(); + + // Observe background page being created and closed after + // the browser action is clicked. + ui_test_utils::WindowedNotificationObserver bg_pg_created( + chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, + content::NotificationService::AllSources()); + ui_test_utils::WindowedNotificationObserver bg_pg_closed( + chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, + content::NotificationService::AllSources()); + BrowserActionTestUtil(browser()).Press(0); + bg_pg_created.Wait(); + bg_pg_closed.Wait(); + + // Background page is closed before it created a new tab. + // TODO(tessamac): Implement! Close background page after callback. + EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); + EXPECT_EQ(num_tabs_before, browser()->tab_count()); +} + +IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, + BroadcastEvent) { + ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableLazyBackgroundPages)); + + FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page"). + AppendASCII("broadcast_event"); + ASSERT_TRUE(LoadExtension(extdir)); + + // Lazy Background Page doesn't exist yet. + ExtensionProcessManager* pm = + browser()->profile()->GetExtensionProcessManager(); + EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); + int num_page_actions = browser()->window()->GetLocationBar()-> + GetLocationBarForTesting()->PageActionVisibleCount(); + + // Open a tab to a URL that will trigger the page action to show. + // stegosaurus.html doesn't actually exist but that doesn't seem to matter. + GURL stego_url = GURL("stegosaurus.html"); + ui_test_utils::NavigateToURL(browser(), stego_url); + + // New page action is never shown because background page is never created. + // TODO(tessamac): Implement! Broadcast events (like tab updates) should + // cause lazy background pages to be created. + EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_)); + EXPECT_EQ(num_page_actions, // should be + 1 + browser()->window()->GetLocationBar()-> + GetLocationBarForTesting()->PageActionVisibleCount()); +} + +// TODO: background page with timer. +// TODO: background page that interacts with popup. +// TODO: background page with menu. diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc index 9097e94..6e8f263 100644 --- a/chrome/browser/renderer_host/chrome_render_message_filter.cc +++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc @@ -5,6 +5,7 @@ #include "chrome/browser/renderer_host/chrome_render_message_filter.h" #include "base/bind.h" +#include "base/command_line.h" #include "base/file_util.h" #include "base/metrics/histogram.h" #include "chrome/browser/automation/automation_resource_message_filter.h" @@ -16,6 +17,7 @@ #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_info_map.h" #include "chrome/browser/extensions/extension_message_service.h" +#include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/nacl_host/nacl_process_host.h" #include "chrome/browser/net/chrome_url_request_context.h" @@ -28,6 +30,7 @@ #include "chrome/common/extensions/extension_messages.h" #include "chrome/common/pref_names.h" #include "chrome/common/render_messages.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" #include "content/browser/plugin_service.h" #include "content/browser/plugin_service_filter.h" @@ -124,6 +127,7 @@ bool ChromeRenderMessageFilter::OnMessageReceived(const IPC::Message& message, IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddListener, OnExtensionAddListener) IPC_MESSAGE_HANDLER(ExtensionHostMsg_RemoveListener, OnExtensionRemoveListener) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExtensionIdle, OnExtensionIdle) IPC_MESSAGE_HANDLER(ExtensionHostMsg_CloseChannel, OnExtensionCloseChannel) IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestForIOThread, OnExtensionRequestForIOThread) @@ -185,6 +189,7 @@ void ChromeRenderMessageFilter::OverrideThreadForMessage( #endif case ExtensionHostMsg_AddListener::ID: case ExtensionHostMsg_RemoveListener::ID: + case ExtensionHostMsg_ExtensionIdle::ID: case ExtensionHostMsg_CloseChannel::ID: case ChromeViewHostMsg_UpdatedCacheStats::ID: *thread = BrowserThread::UI; @@ -368,6 +373,12 @@ void ChromeRenderMessageFilter::OnExtensionRemoveListener( event_name, process, extension_id); } +void ChromeRenderMessageFilter::OnExtensionIdle( + const std::string& extension_id) { + if (profile_->GetExtensionProcessManager()) + profile_->GetExtensionProcessManager()->OnExtensionIdle(extension_id); +} + void ChromeRenderMessageFilter::OnExtensionCloseChannel(int port_id) { if (!RenderProcessHost::FromID(render_process_id_)) return; // To guard against crash in browser_tests shutdown. diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.h b/chrome/browser/renderer_host/chrome_render_message_filter.h index ad6a162..2bb8949 100644 --- a/chrome/browser/renderer_host/chrome_render_message_filter.h +++ b/chrome/browser/renderer_host/chrome_render_message_filter.h @@ -91,6 +91,7 @@ class ChromeRenderMessageFilter : public BrowserMessageFilter { const std::string& event_name); void OnExtensionRemoveListener(const std::string& extension_id, const std::string& event_name); + void OnExtensionIdle(const std::string& extension_id); void OnExtensionCloseChannel(int port_id); void OnExtensionRequestForIOThread( int routing_id, diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index adab58a..8409d00 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -2427,6 +2427,7 @@ 'browser/extensions/extension_websocket_apitest.cc', 'browser/extensions/extension_webstore_private_apitest.cc', 'browser/extensions/isolated_app_browsertest.cc', + 'browser/extensions/lazy_background_page_apitest.cc', 'browser/extensions/notifications_apitest.cc', 'browser/extensions/page_action_apitest.cc', 'browser/extensions/permissions_apitest.cc', diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h index f11ea16..352b454 100644 --- a/chrome/common/extensions/extension_messages.h +++ b/chrome/common/extensions/extension_messages.h @@ -262,6 +262,11 @@ IPC_MESSAGE_CONTROL2(ExtensionHostMsg_RemoveListener, std::string /* extension_id */, std::string /* name */) +// Notify the browser that the extension is idle so it's lazy background page +// can be closed. +IPC_MESSAGE_CONTROL1(ExtensionHostMsg_ExtensionIdle, + std::string /* extension_id */) + // Open a channel to all listening contexts owned by the extension with // the given ID. This always returns a valid port ID which can be used for // sending messages. If an error occurred, the opener will be notified diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc index f0ac09e..03f6393 100644 --- a/chrome/renderer/extensions/extension_dispatcher.cc +++ b/chrome/renderer/extensions/extension_dispatcher.cc @@ -149,6 +149,12 @@ void ExtensionDispatcher::OnMessageInvoke(const std::string& extension_id, RenderThread::Get()->ScheduleIdleHandler( kInitialExtensionIdleHandlerDelayS); } + + // Tell the browser process that we're idle. + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableLazyBackgroundPages) && + function_name == "Event.dispatchJSON") // may always be true + RenderThread::Get()->Send(new ExtensionHostMsg_ExtensionIdle(extension_id)); } void ExtensionDispatcher::OnDeliverMessage(int target_port_id, diff --git a/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/background.html b/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/background.html new file mode 100644 index 0000000..7cee993 --- /dev/null +++ b/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/background.html @@ -0,0 +1,9 @@ +<script> +chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { + // TODO: look for 'stegosaurus' in the page contents. + if (tab.url.search("stegosaurus")) + chrome.pageAction.show(tabId); + else + chrome.pageAction.hide(tabId); +}); +</script> diff --git a/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/icon19.png b/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/icon19.png Binary files differnew file mode 100755 index 0000000..23ce1ac --- /dev/null +++ b/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/icon19.png diff --git a/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/icon48.png b/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/icon48.png Binary files differnew file mode 100755 index 0000000..5e876f3 --- /dev/null +++ b/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/icon48.png diff --git a/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/manifest.json b/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/manifest.json new file mode 100644 index 0000000..8cccb1e --- /dev/null +++ b/chrome/test/data/extensions/api_test/lazy_background_page/broadcast_event/manifest.json @@ -0,0 +1,12 @@ +{ + "name": "Stegosaurus!", + "description": "Warn the user when a stegosaurus might be present.", + "version": "1", + "permissions": ["tabs"], + "background_page": "background.html", + "icons": {"48": "icon48.png"}, + "page_action": { + "default_icon": "icon19.png", + "default_title": "Lookout for the stegosaurus!" + } +} diff --git a/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_create_tab/background.html b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_create_tab/background.html new file mode 100644 index 0000000..f499f27 --- /dev/null +++ b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_create_tab/background.html @@ -0,0 +1,5 @@ +<script> +chrome.browserAction.onClicked.addListener(function(tab) { + chrome.tabs.create({url: "chrome://extensions/", selected: true}); +}); +</script> diff --git a/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_create_tab/ext_icon.png b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_create_tab/ext_icon.png Binary files differnew file mode 100644 index 0000000..e3cdb8a --- /dev/null +++ b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_create_tab/ext_icon.png diff --git a/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_create_tab/manifest.json b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_create_tab/manifest.json new file mode 100644 index 0000000..8588d23 --- /dev/null +++ b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_create_tab/manifest.json @@ -0,0 +1,11 @@ +{ + "name": "Extensions Button", + "description": "Access the Extensions window directly from the toolbar", + "version": "1", + "permissions" : ["tabs"], + "background_page": "background.html", + "browser_action": { + "default_icon" : "ext_icon.png", + "default_title": "Open Extensions window" + } +} diff --git a/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_with_callback/background.html b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_with_callback/background.html new file mode 100644 index 0000000..28ffb18 --- /dev/null +++ b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_with_callback/background.html @@ -0,0 +1,15 @@ +<script> +chrome.browserAction.onClicked.addListener(function(tab) { + // Look for an existing tab for the extensions page before opening a new one. + chrome.tabs.getAllInWindow(null, function(tabs) { + var chromeExtUrl = "chrome://extensions/"; + for (var i = 0; i < tabs.length; i++) { + if (tabs[i].url == chromeExtUrl){ + chrome.tabs.update(tabs[i].id, {selected: true}); + return; + } + } + chrome.tabs.create({url: chromeExtUrl, selected: true}); + }); +}); +</script> diff --git a/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_with_callback/ext_icon.png b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_with_callback/ext_icon.png Binary files differnew file mode 100644 index 0000000..e3cdb8a --- /dev/null +++ b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_with_callback/ext_icon.png diff --git a/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_with_callback/manifest.json b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_with_callback/manifest.json new file mode 100644 index 0000000..5d7399f --- /dev/null +++ b/chrome/test/data/extensions/api_test/lazy_background_page/browser_action_with_callback/manifest.json @@ -0,0 +1,11 @@ +{ + "name": "Extensions Button", + "description": "Access the Extensions window directly from the toolbar. Will not open a duplicate extensions tab.", + "version": "1.1", + "permissions" : ["tabs"], + "background_page": "background.html", + "browser_action": { + "default_icon" : "ext_icon.png", + "default_title": "Open Extensions window" + } +} |