diff options
author | nick <nick@chromium.org> | 2014-12-01 14:49:03 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-12-01 22:49:27 +0000 |
commit | 2644f688b10594e42df1ed4f38eee931159f7661 (patch) | |
tree | 404e26ac0aee35cb99b0593b98e4045a43d6cf8b | |
parent | b05cf256962eaeda358a515f132379cbf270ad7b (diff) | |
download | chromium_src-2644f688b10594e42df1ed4f38eee931159f7661.zip chromium_src-2644f688b10594e42df1ed4f38eee931159f7661.tar.gz chromium_src-2644f688b10594e42df1ed4f38eee931159f7661.tar.bz2 |
Task manager: watch processes for destruction using RenderProcessHostObserver directly.
When subframe processes die, their rows now disappear from the task manager.
Lots of new tests exercising task manager subframe cases under --site-per-process. Not all of these tests work, because of oopif bugs.
BUG=425789
TEST=browser_tests
Review URL: https://codereview.chromium.org/741843002
Cr-Commit-Position: refs/heads/master@{#306279}
-rw-r--r-- | chrome/browser/task_manager/task_manager_browsertest.cc | 277 | ||||
-rw-r--r-- | chrome/browser/task_manager/task_manager_browsertest_util.cc | 9 | ||||
-rw-r--r-- | chrome/browser/task_manager/task_manager_browsertest_util.h | 2 | ||||
-rw-r--r-- | chrome/browser/task_manager/web_contents_resource_provider.cc | 126 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/task_manager_mac.mm | 2 | ||||
-rw-r--r-- | chrome/test/data/iframe.html | 2 | ||||
-rw-r--r-- | chrome/test/data/iframe_cross_site.html | 7 |
7 files changed, 390 insertions, 35 deletions
diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc index 2cd34c2..6a17cf0 100644 --- a/chrome/browser/task_manager/task_manager_browsertest.cc +++ b/chrome/browser/task_manager/task_manager_browsertest.cc @@ -35,8 +35,11 @@ #include "components/infobars/core/confirm_infobar_delegate.h" #include "components/infobars/core/infobar.h" #include "content/public/browser/notification_service.h" +#include "content/public/browser/page_navigator.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/content_browser_test_utils.h" #include "extensions/browser/extension_system.h" #include "extensions/common/extension.h" #include "net/dns/mock_host_resolver.h" @@ -49,9 +52,11 @@ using content::WebContents; using task_manager::browsertest_util::MatchAboutBlankTab; using task_manager::browsertest_util::MatchAnyApp; using task_manager::browsertest_util::MatchAnyExtension; +using task_manager::browsertest_util::MatchAnySubframe; using task_manager::browsertest_util::MatchAnyTab; using task_manager::browsertest_util::MatchApp; using task_manager::browsertest_util::MatchExtension; +using task_manager::browsertest_util::MatchSubframe; using task_manager::browsertest_util::MatchTab; using task_manager::browsertest_util::WaitForTaskManagerRows; @@ -78,6 +83,13 @@ class TaskManagerBrowserTest : public ExtensionBrowserTest { chrome::ShowTaskManager(browser()); } + void HideTaskManager() { + // Hide the task manager, and wait for the model to be depopulated. + chrome::HideTaskManager(); + base::RunLoop().RunUntilIdle(); // OnWindowClosed happens asynchronously. + EXPECT_EQ(0, model()->ResourceCount()); + } + void Refresh() { model()->Refresh(); } @@ -112,6 +124,31 @@ class TaskManagerBrowserTest : public ExtensionBrowserTest { DISALLOW_COPY_AND_ASSIGN(TaskManagerBrowserTest); }; +// Parameterized variant of TaskManagerBrowserTest which runs with/without +// --site-per-process, which enables out of process iframes (OOPIFs). +class TaskManagerOOPIFBrowserTest : public TaskManagerBrowserTest, + public testing::WithParamInterface<bool> { + public: + TaskManagerOOPIFBrowserTest() {} + + protected: + void SetUpCommandLine(CommandLine* command_line) override { + TaskManagerBrowserTest::SetUpCommandLine(command_line); + if (GetParam()) + command_line->AppendSwitch(switches::kSitePerProcess); + } + + bool ShouldExpectSubframes() { + return CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSitePerProcess); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TaskManagerOOPIFBrowserTest); +}; + +INSTANTIATE_TEST_CASE_P(, TaskManagerOOPIFBrowserTest, ::testing::Bool()); + #if defined(OS_MACOSX) || defined(OS_LINUX) #define MAYBE_ShutdownWhileOpen DISABLED_ShutdownWhileOpen #else @@ -765,3 +802,243 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, DevToolsOldUnockedWindow) { ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(3, MatchAnyTab())); DevToolsWindowTesting::CloseDevToolsWindowSync(devtools); } + +IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, KillSubframe) { + ShowTaskManager(); + + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + content::SetupCrossSiteRedirector(embedded_test_server()); + + GURL main_url(embedded_test_server()->GetURL( + "/cross-site/a.com/iframe_cross_site.html")); + browser()->OpenURL(content::OpenURLParams(main_url, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); + int subframe_b = FindResourceIndex(MatchSubframe("http://b.com/")); + ASSERT_NE(-1, subframe_b); + ASSERT_TRUE(model()->GetResourceWebContents(subframe_b) != NULL); + ASSERT_TRUE(model()->CanActivate(subframe_b)); + + TaskManager::GetInstance()->KillProcess(subframe_b); + + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(0, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + } + + HideTaskManager(); + ShowTaskManager(); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(0, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + } +} + +// Tests what happens when a tab navigates to a site (a.com) that it previously +// has a cross-process subframe into (b.com). +// +// TODO(nick): Disabled because the second navigation hits an ASSERT(frame()) in +// WebLocalFrameImpl::loadRequest under --site-per-process. +IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, + DISABLED_NavigateToSubframeProcess) { + ShowTaskManager(); + + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + content::SetupCrossSiteRedirector(embedded_test_server()); + + // Navigate the tab to a page on a.com with cross-process subframes to + // b.com and c.com. + GURL a_dotcom(embedded_test_server()->GetURL( + "/cross-site/a.com/iframe_cross_site.html")); + browser()->OpenURL(content::OpenURLParams(a_dotcom, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); + } + + // Now navigate to a page on b.com with a simple (same-site) iframe. + // This should not show any subframe resources in the task manager. + GURL b_dotcom( + embedded_test_server()->GetURL("/cross-site/b.com/iframe.html")); + + browser()->OpenURL(content::OpenURLParams(b_dotcom, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + HideTaskManager(); + ShowTaskManager(); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); +} + +// TODO(nick): Fails flakily under OOPIF due to a ASSERT_NOT_REACHED in +// WebRemoteFrame, at least under debug OSX. http://crbug.com/437956 +IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, + DISABLED_NavigateToSiteWithSubframeToOriginalSite) { + ShowTaskManager(); + + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + content::SetupCrossSiteRedirector(embedded_test_server()); + + // Navigate to a page on b.com with a simple (same-site) iframe. + // This should not show any subframe resources in the task manager. + GURL b_dotcom( + embedded_test_server()->GetURL("/cross-site/b.com/iframe.html")); + + browser()->OpenURL(content::OpenURLParams(b_dotcom, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + + // Now navigate the tab to a page on a.com with cross-process subframes to + // b.com and c.com. + GURL a_dotcom(embedded_test_server()->GetURL( + "/cross-site/a.com/iframe_cross_site.html")); + browser()->OpenURL(content::OpenURLParams(a_dotcom, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); + } + + HideTaskManager(); + ShowTaskManager(); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); + } +} + +// Tests what happens when a tab navigates a cross-frame iframe (to b.com) +// back to the site of the parent document (a.com). +// +// TODO(nick): Disabled because the second navigation crashes the renderer +// under --site-per-process during blink::Frame::detach(). +IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, + DISABLED_CrossSiteIframeBecomesSameSite) { + ShowTaskManager(); + + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + content::SetupCrossSiteRedirector(embedded_test_server()); + + // Navigate the tab to a page on a.com with cross-process subframes to + // b.com and c.com. + GURL a_dotcom(embedded_test_server()->GetURL( + "/cross-site/a.com/iframe_cross_site.html")); + browser()->OpenURL(content::OpenURLParams(a_dotcom, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); + } + + // Navigate the b.com frame back to a.com. It is no longer a cross-site iframe + ASSERT_TRUE(content::ExecuteScript( + browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(), + "document.getElementById('frame1').src='/title1.html';" + "document.title='aac';")); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(0, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); + } + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + + HideTaskManager(); + ShowTaskManager(); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(0, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); + } + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); +} diff --git a/chrome/browser/task_manager/task_manager_browsertest_util.cc b/chrome/browser/task_manager/task_manager_browsertest_util.cc index 6ece5a4..cc575bc 100644 --- a/chrome/browser/task_manager/task_manager_browsertest_util.cc +++ b/chrome/browser/task_manager/task_manager_browsertest_util.cc @@ -184,5 +184,14 @@ base::string16 MatchPrint(const char* title) { base::string16 MatchAnyPrint() { return MatchPrint("*"); } +base::string16 MatchSubframe(const char* title) { + return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_SUBFRAME_PREFIX, + base::ASCIIToUTF16(title)); +} + +base::string16 MatchAnySubframe() { + return MatchSubframe("*"); +} + } // namespace browsertest_util } // namespace task_manager diff --git a/chrome/browser/task_manager/task_manager_browsertest_util.h b/chrome/browser/task_manager/task_manager_browsertest_util.h index 9b4010e..e66ec37 100644 --- a/chrome/browser/task_manager/task_manager_browsertest_util.h +++ b/chrome/browser/task_manager/task_manager_browsertest_util.h @@ -35,6 +35,8 @@ base::string16 MatchBackground(const char* title); // "Background: " + title base::string16 MatchAnyBackground(); // "Background: *" base::string16 MatchPrint(const char* title); // "Print: " + title base::string16 MatchAnyPrint(); // "Print: *" +base::string16 MatchSubframe(const char* title); // "Subframe: " + title +base::string16 MatchAnySubframe(); // "Subframe: *" } // namespace browsertest_util } // namespace task_manager diff --git a/chrome/browser/task_manager/web_contents_resource_provider.cc b/chrome/browser/task_manager/web_contents_resource_provider.cc index b3cdf67..dc720db 100644 --- a/chrome/browser/task_manager/web_contents_resource_provider.cc +++ b/chrome/browser/task_manager/web_contents_resource_provider.cc @@ -27,8 +27,9 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/image/image_skia.h" -using content::RenderViewHost; using content::RenderFrameHost; +using content::RenderProcessHost; +using content::RenderViewHost; using content::SiteInstance; using content::WebContents; @@ -86,7 +87,8 @@ WebContents* SubframeResource::GetWebContents() const { // Tracks changes to one WebContents, and manages task manager resources for // that WebContents, on behalf of a WebContentsResourceProvider. -class TaskManagerWebContentsEntry : public content::WebContentsObserver { +class TaskManagerWebContentsEntry : public content::WebContentsObserver, + public content::RenderProcessHostObserver { public: typedef std::multimap<SiteInstance*, RendererResource*> ResourceMap; typedef std::pair<ResourceMap::iterator, ResourceMap::iterator> ResourceRange; @@ -97,19 +99,7 @@ class TaskManagerWebContentsEntry : public content::WebContentsObserver { provider_(provider), main_frame_site_instance_(NULL) {} - ~TaskManagerWebContentsEntry() override { - for (ResourceMap::iterator j = resources_by_site_instance_.begin(); - j != resources_by_site_instance_.end();) { - RendererResource* resource = j->second; - - // Advance to next non-duplicate entry. - do { - ++j; - } while (j != resources_by_site_instance_.end() && resource == j->second); - - delete resource; - } - } + ~TaskManagerWebContentsEntry() override { ClearAllResources(false); } // content::WebContentsObserver implementation. void RenderFrameDeleted(RenderFrameHost* render_frame_host) override { @@ -124,19 +114,26 @@ class TaskManagerWebContentsEntry : public content::WebContentsObserver { } void RenderViewReady() override { - ClearAllResources(); + ClearAllResources(true); CreateAllResources(); } - void RenderProcessGone(base::TerminationStatus status) override { - ClearAllResources(); - } - void WebContentsDestroyed() override { - ClearAllResources(); + ClearAllResources(true); provider_->DeleteEntry(web_contents(), this); // Deletes |this|. } + // content::RenderProcessHostObserver implementation. + void RenderProcessExited(RenderProcessHost* process_host, + base::TerminationStatus status, + int exit_code) override { + ClearResourcesForProcess(process_host); + } + + void RenderProcessHostDestroyed(RenderProcessHost* process_host) override { + tracked_process_hosts_.erase(process_host); + } + // Called by WebContentsResourceProvider. RendererResource* GetResourceForSiteInstance(SiteInstance* site_instance) { ResourceMap::iterator i = resources_by_site_instance_.find(site_instance); @@ -153,21 +150,27 @@ class TaskManagerWebContentsEntry : public content::WebContentsObserver { base::Unretained(this))); } - void ClearAllResources() { - for (ResourceMap::iterator j = resources_by_site_instance_.begin(); - j != resources_by_site_instance_.end();) { - RendererResource* resource = j->second; - - // Advance to next non-duplicate entry. - do { - ++j; - } while (j != resources_by_site_instance_.end() && resource == j->second); - - // Remove the resource from the Task Manager. - task_manager()->RemoveResource(resource); + void ClearAllResources(bool update_task_manager) { + RendererResource* last_resource = NULL; + for (auto& x : resources_by_site_instance_) { + RendererResource* resource = x.second; + if (resource == last_resource) + continue; // Skip multiset duplicates. + if (update_task_manager) + task_manager()->RemoveResource(resource); delete resource; + last_resource = resource; } resources_by_site_instance_.clear(); + + RenderProcessHost* last_process_host = NULL; + for (RenderProcessHost* process_host : tracked_process_hosts_) { + if (last_process_host == process_host) + continue; // Skip multiset duplicates. + process_host->RemoveObserver(this); + last_process_host = process_host; + } + tracked_process_hosts_.clear(); tracked_frame_hosts_.clear(); } @@ -193,16 +196,33 @@ class TaskManagerWebContentsEntry : public content::WebContentsObserver { // actually destroy it. task_manager()->RemoveResource(resource); delete resource; + DecrementProcessWatch(site_instance->GetProcess()); if (site_instance == main_frame_site_instance_) { main_frame_site_instance_ = NULL; } } } + void ClearResourcesForProcess(RenderProcessHost* crashed_process) { + std::vector<RenderFrameHost*> frame_hosts_to_delete; + for (RenderFrameHost* frame_host : tracked_frame_hosts_) { + if (frame_host->GetProcess() == crashed_process) { + frame_hosts_to_delete.push_back(frame_host); + } + } + for (RenderFrameHost* frame_host : frame_hosts_to_delete) { + ClearResourceForFrame(frame_host); + } + } + void CreateResourceForFrame(RenderFrameHost* render_frame_host) { SiteInstance* site_instance = render_frame_host->GetSiteInstance(); DCHECK_EQ(0u, tracked_frame_hosts_.count(render_frame_host)); + + if (!site_instance->GetProcess()->HasConnection()) + return; + tracked_frame_hosts_.insert(render_frame_host); ResourceRange existing_resource_range = @@ -235,6 +255,7 @@ class TaskManagerWebContentsEntry : public content::WebContentsObserver { } task_manager()->RemoveResource(old_resource); delete old_resource; + DecrementProcessWatch(site_instance->GetProcess()); } } @@ -242,7 +263,34 @@ class TaskManagerWebContentsEntry : public content::WebContentsObserver { task_manager()->AddResource(new_resource.get()); resources_by_site_instance_.insert( std::make_pair(site_instance, new_resource.release())); + IncrementProcessWatch(site_instance->GetProcess()); + } + } + + // Add ourself as an observer of |process|, if we aren't already. Must be + // balanced by a call to DecrementProcessWatch(). + // TODO(nick): Move away from RenderProcessHostObserver once + // WebContentsObserver supports per-frame process death notices. + void IncrementProcessWatch(RenderProcessHost* process) { + auto range = tracked_process_hosts_.equal_range(process); + if (range.first == range.second) { + process->AddObserver(this); + } + tracked_process_hosts_.insert(range.first, process); + } + + void DecrementProcessWatch(RenderProcessHost* process) { + auto range = tracked_process_hosts_.equal_range(process); + if (range.first == range.second) { + NOTREACHED(); + return; + } + + auto element = range.first++; + if (range.first == range.second) { + process->RemoveObserver(this); } + tracked_process_hosts_.erase(element, range.first); } private: @@ -251,8 +299,20 @@ class TaskManagerWebContentsEntry : public content::WebContentsObserver { WebContentsInformation* info() { return provider_->info(); } WebContentsResourceProvider* const provider_; + + // Every RenderFrameHost that we're watching. std::set<RenderFrameHost*> tracked_frame_hosts_; + + // The set of processes we're currently observing. There is one entry here per + // RendererResource we create. A multimap because we may request observation + // more than once, say if two resources happen to share a process. + std::multiset<RenderProcessHost*> tracked_process_hosts_; + + // Maps SiteInstances to the RendererResources. A multimap, this contains one + // entry per tracked RenderFrameHost, so we can tell when we're done reusing. ResourceMap resources_by_site_instance_; + + // The site instance of the main frame. SiteInstance* main_frame_site_instance_; }; diff --git a/chrome/browser/ui/cocoa/task_manager_mac.mm b/chrome/browser/ui/cocoa/task_manager_mac.mm index c5b7f01..9fba1b6 100644 --- a/chrome/browser/ui/cocoa/task_manager_mac.mm +++ b/chrome/browser/ui/cocoa/task_manager_mac.mm @@ -515,8 +515,8 @@ NSImage* TaskManagerMac::GetImageForRow(int row) { // TaskManagerMac, public: void TaskManagerMac::WindowWasClosed() { - instance_ = NULL; delete this; + instance_ = NULL; // |instance_| is static } int TaskManagerMac::RowCount() const { diff --git a/chrome/test/data/iframe.html b/chrome/test/data/iframe.html index a08e34b..eed403d 100644 --- a/chrome/test/data/iframe.html +++ b/chrome/test/data/iframe.html @@ -1,4 +1,4 @@ <html><head><title>iframe test</title></head> <body> -<iframe src="title1.html"/> +<iframe src="title1.html"></iframe> </body></html>
\ No newline at end of file diff --git a/chrome/test/data/iframe_cross_site.html b/chrome/test/data/iframe_cross_site.html new file mode 100644 index 0000000..37b6148 --- /dev/null +++ b/chrome/test/data/iframe_cross_site.html @@ -0,0 +1,7 @@ +<html><head><title>cross-site iframe test</title></head> +<body> +<!-- This only works if the CrossSiteRedirector is running on the embedded test + server, and the host_resolver is set up to handle b.com. --> +<iframe src="/cross-site/b.com/title1.html" id="frame1"></iframe> +<iframe src="/cross-site/c.com/title1.html" id="frame2"></iframe> +</body></html>
\ No newline at end of file |