New Task Manager - Phase 1.3.2: Implement Tab Contents Task Providing
Part 2: Implementing a task-manager representation of WebContents owned
by the prerender manager.
[email protected]
BUG=470990
TEST=browser_tests --gtest_filter=PrerenderBrowserTest.TaskManagement*
Review URL: https://codereview.chromium.org/1185183008
Cr-Commit-Position: refs/heads/master@{#335788}
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 7b742f0..c08cfaa2 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -16,6 +16,7 @@
#include "base/prefs/pref_service.h"
#include "base/run_loop.h"
#include "base/scoped_observer.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -48,6 +49,9 @@
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/safe_browsing/safe_browsing_util.h"
#include "chrome/browser/safe_browsing/test_database_manager.h"
+#include "chrome/browser/task_management/providers/task_provider_observer.h"
+#include "chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h"
+#include "chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h"
#include "chrome/browser/task_manager/task_manager.h"
#include "chrome/browser/task_manager/task_manager_browsertest_util.h"
#include "chrome/browser/ui/browser.h"
@@ -4080,4 +4084,100 @@
}
#endif // !defined(DISABLE_NACL)
+#if defined(ENABLE_TASK_MANAGER)
+
+namespace {
+
+// Defines a test class for testing that will act as a mock task manager.
+class MockTaskManager : public task_management::TaskProviderObserver {
+ public:
+ MockTaskManager() {}
+ ~MockTaskManager() override {}
+
+ // task_management::Task_providerObserver:
+ void TaskAdded(task_management::Task* task) override {
+ EXPECT_FALSE(ContainsKey(provided_tasks_, task));
+ provided_tasks_.insert(task);
+ }
+
+ void TaskRemoved(task_management::Task* task) override {
+ EXPECT_TRUE(ContainsKey(provided_tasks_, task));
+ provided_tasks_.erase(task);
+ }
+
+ base::string16 GetPrerenderTitlePrefix() const {
+ return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PRERENDER_PREFIX,
+ base::string16());
+ }
+
+ const std::set<task_management::WebContentsTag*>& tracked_tags() const {
+ return task_management::WebContentsTagsManager::GetInstance()->
+ tracked_tags();
+ }
+
+ const std::set<task_management::Task*>& provided_tasks() const {
+ return provided_tasks_;
+ }
+
+ private:
+ std::set<task_management::Task*> provided_tasks_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockTaskManager);
+};
+
+// Tests the correct recording of tags for the prerender WebContents.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, TaskManagementTagsBasic) {
+ MockTaskManager task_manager;
+ EXPECT_TRUE(task_manager.tracked_tags().empty());
+
+ // Start prerendering a page and make sure it's correctly tagged.
+ PrerenderTestURL("files/prerender/prerender_page.html", FINAL_STATUS_USED, 1);
+ EXPECT_FALSE(task_manager.tracked_tags().empty());
+
+ // TODO(afakhry): Once we start tagging the tab contents the below tests
+ // must be changed.
+ EXPECT_EQ(1U, task_manager.tracked_tags().size());
+
+ // Swap in the prerendered content and make sure its tag is removed.
+ NavigateToDestURL();
+ EXPECT_TRUE(task_manager.tracked_tags().empty());
+}
+
+// Tests that the task manager will be provided by tasks that correspond to
+// prerendered WebContents.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, TaskManagementTasksProvided) {
+ MockTaskManager task_manager;
+ EXPECT_TRUE(task_manager.tracked_tags().empty());
+
+ task_management::WebContentsTaskProvider provider;
+ provider.SetObserver(&task_manager);
+
+ // Still empty, no pre-existing tasks.
+ EXPECT_TRUE(task_manager.provided_tasks().empty());
+
+ // Start prerendering a page.
+ PrerenderTestURL("files/prerender/prerender_page.html", FINAL_STATUS_USED, 1);
+ EXPECT_FALSE(task_manager.tracked_tags().empty());
+
+ // TODO(afakhry): The below may not be true after we support more tags.
+ EXPECT_EQ(1U, task_manager.tracked_tags().size());
+ ASSERT_EQ(1U, task_manager.provided_tasks().size());
+
+ const task_management::Task* task = *task_manager.provided_tasks().begin();
+ EXPECT_EQ(task_management::Task::RENDERER, task->GetType());
+ const base::string16 title = task->title();
+ const base::string16 expected_prefix = task_manager.GetPrerenderTitlePrefix();
+ EXPECT_TRUE(base::StartsWith(title,
+ expected_prefix,
+ base::CompareCase::INSENSITIVE_ASCII));
+
+ NavigateToDestURL();
+ // TODO(afakhry): The below may not be true after we support more tags.
+ EXPECT_TRUE(task_manager.provided_tasks().empty());
+}
+
+} // namespace
+
+#endif // defined(ENABLE_TASK_MANAGER)
+
} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index fb7daa9..d9da339 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/prerender/prerender_manager_factory.h"
#include "chrome/browser/prerender/prerender_resource_throttle.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/task_management/web_contents_tags.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tab_helpers.h"
#include "chrome/browser/ui/web_contents_sizer.h"
@@ -279,6 +280,11 @@
TabHelpers::AttachTabHelpers(prerender_contents_.get());
content::WebContentsObserver::Observe(prerender_contents_.get());
+ // Tag the prerender contents with the task manager specific prerender tag, so
+ // that it shows up in the task manager.
+ task_management::WebContentsTags::CreateForPrerenderContents(
+ prerender_contents_.get());
+
web_contents_delegate_.reset(new WebContentsDelegateImpl(this));
prerender_contents_.get()->SetDelegate(web_contents_delegate_.get());
// Set the size of the prerender WebContents.
@@ -671,6 +677,11 @@
WebContents* PrerenderContents::ReleasePrerenderContents() {
prerender_contents_->SetDelegate(NULL);
content::WebContentsObserver::Observe(NULL);
+
+ // Clear the task manager tag we added earlier to our
+ // WebContents since it's no longer a prerender contents.
+ task_management::WebContentsTags::ClearTag(prerender_contents_.get());
+
return prerender_contents_.release();
}
diff --git a/chrome/browser/task_management/providers/web_contents/prerender_tag.cc b/chrome/browser/task_management/providers/web_contents/prerender_tag.cc
new file mode 100644
index 0000000..6e6ae3d2
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/prerender_tag.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 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 "chrome/browser/task_management/providers/web_contents/prerender_tag.h"
+#include "chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h"
+
+namespace task_management {
+
+PrerenderTask* PrerenderTag::CreateTask() const {
+ return new PrerenderTask(web_contents());
+}
+
+PrerenderTag::PrerenderTag(content::WebContents* web_contents)
+ : WebContentsTag(web_contents) {
+}
+
+PrerenderTag::~PrerenderTag() {
+}
+
+} // namespace task_management
diff --git a/chrome/browser/task_management/providers/web_contents/prerender_tag.h b/chrome/browser/task_management/providers/web_contents/prerender_tag.h
new file mode 100644
index 0000000..6c6f9593
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/prerender_tag.h
@@ -0,0 +1,32 @@
+// Copyright 2015 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.
+
+#ifndef CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_PRERENDER_TAG_H_
+#define CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_PRERENDER_TAG_H_
+
+#include "chrome/browser/task_management/providers/web_contents/prerender_task.h"
+#include "chrome/browser/task_management/providers/web_contents/web_contents_tag.h"
+
+namespace task_management {
+
+// Defines a concrete UserData type for WebContents owned by the
+// PrerenderManager.
+class PrerenderTag : public WebContentsTag {
+ public:
+ // task_management::WebContentsTag:
+ PrerenderTask* CreateTask() const override;
+
+ private:
+ friend class WebContentsTags;
+
+ explicit PrerenderTag(content::WebContents* web_contents);
+ ~PrerenderTag() override;
+
+ DISALLOW_COPY_AND_ASSIGN(PrerenderTag);
+};
+
+} // namespace task_management
+
+
+#endif // CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_PRERENDER_TAG_H_
diff --git a/chrome/browser/task_management/providers/web_contents/prerender_task.cc b/chrome/browser/task_management/providers/web_contents/prerender_task.cc
new file mode 100644
index 0000000..dc039b4f
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/prerender_task.cc
@@ -0,0 +1,59 @@
+// Copyright 2015 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 "chrome/browser/task_management/providers/web_contents/prerender_task.h"
+
+#include "chrome/grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace task_management {
+
+namespace {
+
+gfx::ImageSkia* g_prerender_icon = nullptr;
+
+// Returns the prerender icon or |nullptr| if the |ResourceBundle| is not ready
+// yet.
+gfx::ImageSkia* GetPrerenderIcon() {
+ if (g_prerender_icon)
+ return g_prerender_icon;
+
+ if (!ResourceBundle::HasSharedInstance())
+ return nullptr;
+
+ g_prerender_icon =
+ ResourceBundle::GetSharedInstance().GetImageSkiaNamed(IDR_PRERENDER);
+ return g_prerender_icon;
+}
+
+base::string16 PrefixTitle(const base::string16& title) {
+ return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PRERENDER_PREFIX, title);
+}
+
+} // namespace
+
+PrerenderTask::PrerenderTask(content::WebContents* web_contents)
+ : RendererTask(
+ PrefixTitle(RendererTask::GetTitleFromWebContents(web_contents)),
+ GetPrerenderIcon(),
+ web_contents) {
+}
+
+PrerenderTask::~PrerenderTask() {
+}
+
+void PrerenderTask::OnTitleChanged(content::NavigationEntry* entry) {
+ // As long as this task lives we keep prefixing its title with "Prerender:".
+ set_title(PrefixTitle(RendererTask::GetTitleFromWebContents(web_contents())));
+}
+
+void PrerenderTask::OnFaviconChanged() {
+ // As long as this task lives we keep using the prerender icon, so we ignore
+ // this event.
+}
+
+} // namespace task_management
diff --git a/chrome/browser/task_management/providers/web_contents/prerender_task.h b/chrome/browser/task_management/providers/web_contents/prerender_task.h
new file mode 100644
index 0000000..7d4d1d0
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/prerender_task.h
@@ -0,0 +1,29 @@
+// Copyright 2015 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.
+
+#ifndef CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_PRERENDER_TASK_H_
+#define CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_PRERENDER_TASK_H_
+
+#include "chrome/browser/task_management/providers/web_contents/renderer_task.h"
+
+namespace task_management {
+
+// Defines a task manager representation of WebContents owned by the
+// PrerenderManager.
+class PrerenderTask : public RendererTask {
+ public:
+ explicit PrerenderTask(content::WebContents* web_contents);
+ ~PrerenderTask() override;
+
+ // task_management::RendererTask:
+ void OnTitleChanged(content::NavigationEntry* entry) override;
+ void OnFaviconChanged() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PrerenderTask);
+};
+
+} // namespace task_management
+
+#endif // CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_PRERENDER_TASK_H_
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.cc b/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.cc
index b61ef1e..44d0c64 100644
--- a/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.cc
+++ b/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.cc
@@ -47,6 +47,11 @@
provider_ = nullptr;
}
+void WebContentsTagsManager::ClearFromProvider(const WebContentsTag* tag) {
+ if (provider_)
+ provider_->OnWebContentsTagRemoved(tag);
+}
+
WebContentsTagsManager::WebContentsTagsManager()
: provider_(nullptr) {
}
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h b/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h
index 62ac3cf..da4a315 100644
--- a/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h
+++ b/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h
@@ -33,6 +33,12 @@
void SetProvider(WebContentsTaskProvider* provider);
void ClearProvider();
+ // This is called by WebContentsTags::ClearTag(). This is needed for Tags
+ // whose destruction does not correspond to the destruction of their
+ // WebContents. In this case the provider (if any) must be manually cleared,
+ // or else the corresponding task for the |tag| will continue to exist.
+ void ClearFromProvider(const WebContentsTag* tag);
+
const std::set<WebContentsTag*>& tracked_tags() const {
return tracked_tags_;
}
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc b/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc
index 7cd7c0d6..4c24931 100644
--- a/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc
+++ b/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc
@@ -35,6 +35,10 @@
// entry's WebContents.
void CreateAllTasks();
+ // Clears all the tasks in this entry. The provider's observer will be
+ // notified if |notify_observer| is true.
+ void ClearAllTasks(bool notify_observer);
+
// Returns the |RendererTask| that corresponds to the given
// |render_frame_host| or |nullptr| if the given frame is not tracked by this
// entry.
@@ -61,10 +65,6 @@
// notifies the provider's observer of the tasks removal.
void ClearTaskForFrame(RenderFrameHost* render_frame_host);
- // Clears all the tasks in this entry. The provider's observer will be
- // notified if |notify_observer| is true.
- void ClearAllTasks(bool notify_observer);
-
// The provider that owns this entry.
WebContentsTaskProvider* provider_;
@@ -106,6 +106,21 @@
base::Unretained(this)));
}
+void WebContentsEntry::ClearAllTasks(bool notify_observer) {
+ for (auto& pair : frames_by_site_instance_) {
+ FramesList& frames_list = pair.second;
+ DCHECK(!frames_list.empty());
+ RendererTask* task = tasks_by_frames_[frames_list[0]];
+ if (notify_observer)
+ provider_->NotifyObserverTaskRemoved(task);
+ delete task;
+ }
+
+ frames_by_site_instance_.clear();
+ tasks_by_frames_.clear();
+ main_frame_site_instance_ = nullptr;
+}
+
RendererTask* WebContentsEntry::GetTaskForFrame(
RenderFrameHost* render_frame_host) const {
auto itr = tasks_by_frames_.find(render_frame_host);
@@ -238,21 +253,6 @@
}
}
-void WebContentsEntry::ClearAllTasks(bool notify_observer) {
- for (auto& pair : frames_by_site_instance_) {
- FramesList& frames_list = pair.second;
- DCHECK(!frames_list.empty());
- RendererTask* task = tasks_by_frames_[frames_list[0]];
- if (notify_observer)
- provider_->NotifyObserverTaskRemoved(task);
- delete task;
- }
-
- frames_by_site_instance_.clear();
- tasks_by_frames_.clear();
- main_frame_site_instance_ = nullptr;
-}
-
////////////////////////////////////////////////////////////////////////////////
WebContentsTaskProvider::WebContentsTaskProvider() : entries_map_() {
@@ -262,7 +262,8 @@
STLDeleteValues(&entries_map_);
}
-void WebContentsTaskProvider::OnWebContentsTagCreated(WebContentsTag* tag) {
+void WebContentsTaskProvider::OnWebContentsTagCreated(
+ const WebContentsTag* tag) {
DCHECK(tag);
content::WebContents* web_contents = tag->web_contents();
DCHECK(web_contents);
@@ -282,6 +283,22 @@
entry->CreateAllTasks();
}
+void WebContentsTaskProvider::OnWebContentsTagRemoved(
+ const WebContentsTag* tag) {
+ DCHECK(tag);
+ content::WebContents* web_contents = tag->web_contents();
+ DCHECK(web_contents);
+
+ auto itr = entries_map_.find(web_contents);
+ DCHECK(itr != entries_map_.end());
+ WebContentsEntry* entry = itr->second;
+
+ // Must manually clear the tasks and notify the observer.
+ entry->ClearAllTasks(true);
+ entries_map_.erase(itr);
+ delete entry;
+}
+
Task* WebContentsTaskProvider::GetTaskOfUrlRequest(int origin_pid,
int child_id,
int route_id) {
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h b/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h
index 0104cac..cc9c7f3 100644
--- a/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h
+++ b/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h
@@ -29,7 +29,10 @@
// This will be called every time we're notified that a new |WebContentsTag|
// has been created.
- void OnWebContentsTagCreated(WebContentsTag* tag);
+ void OnWebContentsTagCreated(const WebContentsTag* tag);
+
+ // Manually remove |tag|'s corresponding Task.
+ void OnWebContentsTagRemoved(const WebContentsTag* tag);
// task_management::TaskProvider:
Task* GetTaskOfUrlRequest(int origin_pid,
diff --git a/chrome/browser/task_management/web_contents_tags.cc b/chrome/browser/task_management/web_contents_tags.cc
index 72adce1..9371a0d 100644
--- a/chrome/browser/task_management/web_contents_tags.cc
+++ b/chrome/browser/task_management/web_contents_tags.cc
@@ -6,11 +6,13 @@
#include "chrome/browser/task_management/providers/web_contents/background_contents_tag.h"
#include "chrome/browser/task_management/providers/web_contents/devtools_tag.h"
+#include "chrome/browser/task_management/providers/web_contents/prerender_tag.h"
#include "chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h"
#include "content/public/browser/web_contents.h"
namespace task_management {
+#if defined(ENABLE_TASK_MANAGER)
namespace {
// Adds the |tag| to |contents|. It also adds the |tag| to the
@@ -27,27 +29,53 @@
}
} // namespace
+#endif // defined(ENABLE_TASK_MANAGER)
// static
void WebContentsTags::CreateForBackgroundContents(
content::WebContents* web_contents,
BackgroundContents* background_contents) {
+#if defined(ENABLE_TASK_MANAGER)
if (!WebContentsTag::FromWebContents(web_contents)) {
TagWebContents(
web_contents,
new BackgroundContentsTag(web_contents, background_contents),
WebContentsTag::kTagKey);
}
+#endif // defined(ENABLE_TASK_MANAGER)
}
// static
void WebContentsTags::CreateForDevToolsContents(
content::WebContents* web_contents) {
+#if defined(ENABLE_TASK_MANAGER)
if (!WebContentsTag::FromWebContents(web_contents)) {
TagWebContents(web_contents,
new DevToolsTag(web_contents),
WebContentsTag::kTagKey);
}
+#endif // defined(ENABLE_TASK_MANAGER)
+}
+
+// static
+void WebContentsTags::CreateForPrerenderContents(
+ content::WebContents* web_contents) {
+#if defined(ENABLE_TASK_MANAGER)
+ if (!WebContentsTag::FromWebContents(web_contents)) {
+ TagWebContents(web_contents,
+ new PrerenderTag(web_contents),
+ WebContentsTag::kTagKey);
+ }
+#endif // defined(ENABLE_TASK_MANAGER)
+}
+
+// static
+void WebContentsTags::ClearTag(content::WebContents* web_contents) {
+#if defined(ENABLE_TASK_MANAGER)
+ const WebContentsTag* tag = WebContentsTag::FromWebContents(web_contents);
+ WebContentsTagsManager::GetInstance()->ClearFromProvider(tag);
+ web_contents->RemoveUserData(WebContentsTag::kTagKey);
+#endif // defined(ENABLE_TASK_MANAGER)
}
} // namespace task_management
diff --git a/chrome/browser/task_management/web_contents_tags.h b/chrome/browser/task_management/web_contents_tags.h
index d81b88e..3c929393 100644
--- a/chrome/browser/task_management/web_contents_tags.h
+++ b/chrome/browser/task_management/web_contents_tags.h
@@ -39,6 +39,19 @@
// not have to be cleaned up by the caller, as it is owned by |web_contents|.
static void CreateForDevToolsContents(content::WebContents* web_contents);
+ // Tag a WebContents owned by the PrerenderManager so that it shows up in the
+ // task manager. Calling this function creates a PrerenderTag, and attaches it
+ // to |web_contents|. If an instance is already attached, this does nothing.
+ // The resulting tag does not have to be cleaned up by the caller, as it is
+ // owned by |web_contents|.
+ static void CreateForPrerenderContents(content::WebContents* web_contents);
+
+ // Clears the task-manager tag, created by any of the above functions, from
+ // the given |web_contents| if any.
+ // Clearing the tag is necessary only when you need to re-tag an existing
+ // WebContents, to indicate a change in ownership.
+ static void ClearTag(content::WebContents* web_contents);
+
private:
DISALLOW_COPY_AND_ASSIGN(WebContentsTags);
};