summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornick <nick@chromium.org>2014-12-01 14:49:03 -0800
committerCommit bot <commit-bot@chromium.org>2014-12-01 22:49:27 +0000
commit2644f688b10594e42df1ed4f38eee931159f7661 (patch)
tree404e26ac0aee35cb99b0593b98e4045a43d6cf8b
parentb05cf256962eaeda358a515f132379cbf270ad7b (diff)
downloadchromium_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.cc277
-rw-r--r--chrome/browser/task_manager/task_manager_browsertest_util.cc9
-rw-r--r--chrome/browser/task_manager/task_manager_browsertest_util.h2
-rw-r--r--chrome/browser/task_manager/web_contents_resource_provider.cc126
-rw-r--r--chrome/browser/ui/cocoa/task_manager_mac.mm2
-rw-r--r--chrome/test/data/iframe.html2
-rw-r--r--chrome/test/data/iframe_cross_site.html7
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