Commit 6c760df2 authored by nick's avatar nick Committed by Commit Bot

[TaskManager] Allow a Task to mutate its PID after creation

Prior to this change, WebContentsTaskProvider would defer task creation if the
PID was not known at RenderFrameCreated time. However, for a newly-cloned
WebContents, no event ever occurred to re-create the Task once the process
finished launching. This was bug 738169.

Fix the problem by never deferring task_manager::Task creation; instead, create
Tasks for all live, current RenderFrameHosts. If the PID is not known immediately,
allow it to be set on the task at a later time (when RenderProcessHost::IsReady()
becomes true).

Because the TaskManagerImpl was written with the expectation that Tasks have
a constant PID, PID mutation is implemented in terms of temporarily removing the
task, mutating the PID, and re-adding it.

In WebContentsTaskProvider, we no longer need to implement RenderProcessGone.

In TaskGroup, don't waste time collecting stats for a null process ID.

Tests are added exercising this bug, and its subframe equivalent. Test coverage
is added for the PID==0 case, and we ensure that the "Memory" column is
populated with something nonzero.

BUG=738169

Review-Url: https://codereview.chromium.org/2961423002
Cr-Commit-Position: refs/heads/master@{#491180}
parent f0bae7e5
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/task_manager/providers/task_provider_observer.h"
#include "chrome/browser/task_manager/task_manager_observer.h" #include "chrome/browser/task_manager/task_manager_observer.h"
#include "content/public/common/result_codes.h" #include "content/public/common/result_codes.h"
...@@ -22,6 +23,13 @@ namespace { ...@@ -22,6 +23,13 @@ namespace {
// The last ID given to the previously created task. // The last ID given to the previously created task.
int64_t g_last_id = 0; int64_t g_last_id = 0;
base::ProcessId DetermineProcessId(base::ProcessHandle handle,
base::ProcessId process_id) {
if (process_id != base::kNullProcessId)
return process_id;
return base::GetProcId(handle);
}
} // namespace } // namespace
Task::Task(const base::string16& title, Task::Task(const base::string16& title,
...@@ -40,9 +48,7 @@ Task::Task(const base::string16& title, ...@@ -40,9 +48,7 @@ Task::Task(const base::string16& title,
rappor_sample_name_(rappor_sample), rappor_sample_name_(rappor_sample),
icon_(icon ? *icon : gfx::ImageSkia()), icon_(icon ? *icon : gfx::ImageSkia()),
process_handle_(handle), process_handle_(handle),
process_id_(process_id != base::kNullProcessId process_id_(DetermineProcessId(handle, process_id)) {}
? process_id
: base::GetProcId(handle)) {}
Task::~Task() {} Task::~Task() {}
...@@ -94,6 +100,24 @@ void Task::Refresh(const base::TimeDelta& update_interval, ...@@ -94,6 +100,24 @@ void Task::Refresh(const base::TimeDelta& update_interval,
last_refresh_cumulative_bytes_sent_ = cumulative_bytes_sent_; last_refresh_cumulative_bytes_sent_ = cumulative_bytes_sent_;
} }
void Task::UpdateProcessInfo(base::ProcessHandle handle,
base::ProcessId process_id,
TaskProviderObserver* observer) {
process_id = DetermineProcessId(handle, process_id);
// Don't remove the task if there is no change to the process ID.
if (process_id == process_id_)
return;
// TaskManagerImpl and TaskGroup implementations assume that a process ID is
// consistent for the lifetime of a Task. So to change the process ID,
// temporarily unregister this Task.
observer->TaskRemoved(this);
process_handle_ = handle;
process_id_ = process_id;
observer->TaskAdded(this);
}
void Task::OnNetworkBytesRead(int64_t bytes_read) { void Task::OnNetworkBytesRead(int64_t bytes_read) {
cumulative_bytes_read_ += bytes_read; cumulative_bytes_read_ += bytes_read;
} }
......
...@@ -21,6 +21,8 @@ class Profile; ...@@ -21,6 +21,8 @@ class Profile;
namespace task_manager { namespace task_manager {
class TaskProviderObserver;
// Defines a task that corresponds to a tab, an app, an extension, ... etc. It // Defines a task that corresponds to a tab, an app, an extension, ... etc. It
// represents one row in the task manager table. Multiple tasks can share the // represents one row in the task manager table. Multiple tasks can share the
// same process, in which case they're grouped together in the task manager // same process, in which case they're grouped together in the task manager
...@@ -83,6 +85,13 @@ class Task { ...@@ -83,6 +85,13 @@ class Task {
virtual void Refresh(const base::TimeDelta& update_interval, virtual void Refresh(const base::TimeDelta& update_interval,
int64_t refresh_flags); int64_t refresh_flags);
// Modifies the value of process_id(). To mutate the process ID, this Task is
// temporarily unregistered from |observer|, and then re-registered before
// returning.
void UpdateProcessInfo(base::ProcessHandle handle,
base::ProcessId process_id,
TaskProviderObserver* observer);
// Will receive this notification through the task manager from // Will receive this notification through the task manager from
// |ChromeNetworkDelegate::OnNetworkBytesReceived()|. The task will add to the // |ChromeNetworkDelegate::OnNetworkBytesReceived()|. The task will add to the
// |cummulative_read_bytes_|. // |cummulative_read_bytes_|.
...@@ -213,10 +222,10 @@ class Task { ...@@ -213,10 +222,10 @@ class Task {
gfx::ImageSkia icon_; gfx::ImageSkia icon_;
// The handle of the process on which this task is running. // The handle of the process on which this task is running.
const base::ProcessHandle process_handle_; base::ProcessHandle process_handle_;
// The PID of the process on which this task is running. // The PID of the process on which this task is running.
const base::ProcessId process_id_; base::ProcessId process_id_;
DISALLOW_COPY_AND_ASSIGN(Task); DISALLOW_COPY_AND_ASSIGN(Task);
}; };
......
...@@ -41,4 +41,13 @@ void TaskProvider::NotifyObserverTaskUnresponsive(Task* task) const { ...@@ -41,4 +41,13 @@ void TaskProvider::NotifyObserverTaskUnresponsive(Task* task) const {
observer_->TaskUnresponsive(task); observer_->TaskUnresponsive(task);
} }
void TaskProvider::UpdateTaskProcessInfoAndNotifyObserver(
Task* existing_task,
base::ProcessHandle new_process_handle,
base::ProcessId new_process_id) const {
DCHECK(observer_);
existing_task->UpdateProcessInfo(new_process_handle, new_process_id,
observer_);
}
} // namespace task_manager } // namespace task_manager
...@@ -50,6 +50,10 @@ class TaskProvider { ...@@ -50,6 +50,10 @@ class TaskProvider {
void NotifyObserverTaskAdded(Task* task) const; void NotifyObserverTaskAdded(Task* task) const;
void NotifyObserverTaskRemoved(Task* task) const; void NotifyObserverTaskRemoved(Task* task) const;
void NotifyObserverTaskUnresponsive(Task* task) const; void NotifyObserverTaskUnresponsive(Task* task) const;
void UpdateTaskProcessInfoAndNotifyObserver(
Task* existing_task,
base::ProcessHandle new_process_handle,
base::ProcessId new_process_id) const;
private: private:
// This will be called once an observer is set for this provider. When it is // This will be called once an observer is set for this provider. When it is
......
...@@ -55,7 +55,6 @@ class WebContentsEntry : public content::WebContentsObserver { ...@@ -55,7 +55,6 @@ class WebContentsEntry : public content::WebContentsObserver {
RenderFrameHost* new_host) override; RenderFrameHost* new_host) override;
void RenderFrameCreated(RenderFrameHost*) override; void RenderFrameCreated(RenderFrameHost*) override;
void WebContentsDestroyed() override; void WebContentsDestroyed() override;
void RenderProcessGone(base::TerminationStatus status) override;
void OnRendererUnresponsive(RenderWidgetHost* render_widget_host) override; void OnRendererUnresponsive(RenderWidgetHost* render_widget_host) override;
void DidFinishNavigation( void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override; content::NavigationHandle* navigation_handle) override;
...@@ -76,6 +75,10 @@ class WebContentsEntry : public content::WebContentsObserver { ...@@ -76,6 +75,10 @@ class WebContentsEntry : public content::WebContentsObserver {
// Calls |on_task| for each task managed by this WebContentsEntry. // Calls |on_task| for each task managed by this WebContentsEntry.
void ForEachTask(const base::Callback<void(RendererTask*)>& on_task); void ForEachTask(const base::Callback<void(RendererTask*)>& on_task);
// Walks parents until hitting a process boundary. Returns the highest frame
// in the same SiteInstance as |render_frame_host|.
RenderFrameHost* FindLocalRoot(RenderFrameHost* render_frame_host) const;
// The provider that owns this entry. // The provider that owns this entry.
WebContentsTaskProvider* provider_; WebContentsTaskProvider* provider_;
...@@ -135,49 +138,66 @@ void WebContentsEntry::ClearAllTasks(bool notify_observer) { ...@@ -135,49 +138,66 @@ void WebContentsEntry::ClearAllTasks(bool notify_observer) {
RendererTask* WebContentsEntry::GetTaskForFrame( RendererTask* WebContentsEntry::GetTaskForFrame(
RenderFrameHost* render_frame_host) const { RenderFrameHost* render_frame_host) const {
auto itr = tasks_by_frames_.find(render_frame_host); // Only local roots are in |tasks_by_frames_|.
auto itr = tasks_by_frames_.find(FindLocalRoot(render_frame_host));
if (itr == tasks_by_frames_.end()) if (itr == tasks_by_frames_.end())
return nullptr; return nullptr;
return itr->second; return itr->second;
} }
RenderFrameHost* WebContentsEntry::FindLocalRoot(
RenderFrameHost* render_frame_host) const {
SiteInstance* site_instance = render_frame_host->GetSiteInstance();
RenderFrameHost* candidate = render_frame_host;
while (RenderFrameHost* parent = candidate->GetParent()) {
if (parent->GetSiteInstance() != site_instance)
break;
candidate = parent;
}
return candidate;
}
void WebContentsEntry::RenderFrameDeleted(RenderFrameHost* render_frame_host) { void WebContentsEntry::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
ClearTaskForFrame(render_frame_host); ClearTaskForFrame(render_frame_host);
} }
void WebContentsEntry::RenderFrameHostChanged(RenderFrameHost* old_host, void WebContentsEntry::RenderFrameHostChanged(RenderFrameHost* old_host,
RenderFrameHost* new_host) { RenderFrameHost* new_host) {
DCHECK(new_host->IsCurrent());
ClearTaskForFrame(old_host); ClearTaskForFrame(old_host);
CreateTaskForFrame(new_host); CreateTaskForFrame(new_host);
} }
void WebContentsEntry::RenderFrameCreated(RenderFrameHost* render_frame_host) { void WebContentsEntry::RenderFrameCreated(RenderFrameHost* render_frame_host) {
DCHECK(render_frame_host->IsRenderFrameLive());
// Skip pending/speculative hosts. We'll create tasks for these if the // Skip pending/speculative hosts. We'll create tasks for these if the
// navigation commits, at which point RenderFrameHostChanged() will fire. // navigation commits, at which point RenderFrameHostChanged() will fire.
if (!render_frame_host->IsCurrent()) if (!render_frame_host->IsCurrent())
return; return;
// Task manager will have no separate entry for |render_frame_host| if it has CreateTaskForFrame(render_frame_host);
// the same site instance as its parent - quit early in this case.
if (render_frame_host->GetParent() &&
render_frame_host->GetParent()->GetSiteInstance() ==
render_frame_host->GetSiteInstance())
return;
// Postpone processing |render_frame_host| until its process has a PID.
render_frame_host->GetProcess()->PostTaskWhenProcessIsReady(base::Bind(
&WebContentsEntry::RenderFrameReady, weak_factory_.GetWeakPtr(),
render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID()));
} }
void WebContentsEntry::RenderFrameReady(int render_process_id, void WebContentsEntry::RenderFrameReady(int render_process_id,
int render_frame_id) { int render_frame_id) {
// We get here when a RenderProcessHost we are tracking transitions to the
// IsReady state. This might mean we know its process ID.
content::RenderFrameHost* render_frame_host = content::RenderFrameHost* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, render_frame_id); content::RenderFrameHost::FromID(render_process_id, render_frame_id);
if (render_frame_host) if (!render_frame_host)
CreateTaskForFrame(render_frame_host); return;
Task* task = GetTaskForFrame(render_frame_host);
if (!task)
return;
const base::ProcessId determine_pid_from_handle = base::kNullProcessId;
provider_->UpdateTaskProcessInfoAndNotifyObserver(
task, render_frame_host->GetProcess()->GetHandle(),
determine_pid_from_handle);
} }
void WebContentsEntry::WebContentsDestroyed() { void WebContentsEntry::WebContentsDestroyed() {
...@@ -185,10 +205,6 @@ void WebContentsEntry::WebContentsDestroyed() { ...@@ -185,10 +205,6 @@ void WebContentsEntry::WebContentsDestroyed() {
provider_->DeleteEntry(web_contents()); provider_->DeleteEntry(web_contents());
} }
void WebContentsEntry::RenderProcessGone(base::TerminationStatus status) {
ClearAllTasks(true);
}
void WebContentsEntry::OnRendererUnresponsive( void WebContentsEntry::OnRendererUnresponsive(
RenderWidgetHost* render_widget_host) { RenderWidgetHost* render_widget_host) {
// Find the first RenderFrameHost matching the RenderWidgetHost. // Find the first RenderFrameHost matching the RenderWidgetHost.
...@@ -242,23 +258,34 @@ void WebContentsEntry::TitleWasSet(content::NavigationEntry* entry, ...@@ -242,23 +258,34 @@ void WebContentsEntry::TitleWasSet(content::NavigationEntry* entry,
} }
void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) { void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) {
// Currently we do not track pending hosts, or pending delete hosts.
DCHECK(render_frame_host->IsCurrent());
DCHECK(render_frame_host); DCHECK(render_frame_host);
DCHECK(!tasks_by_frames_.count(render_frame_host)); DCHECK(!tasks_by_frames_.count(render_frame_host));
content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); content::SiteInstance* site_instance = render_frame_host->GetSiteInstance();
if (!site_instance->GetProcess()->HasConnection())
return; // Exclude sad tabs and sad oopifs.
if (!render_frame_host->IsRenderFrameLive()) if (!render_frame_host->IsRenderFrameLive())
return; return;
// Exclude frames in the same SiteInstance as their parent; |tasks_by_frames_|
// only contains local roots.
if (render_frame_host->GetParent() &&
site_instance == render_frame_host->GetParent()->GetSiteInstance()) {
return;
}
bool site_instance_exists = bool site_instance_exists =
frames_by_site_instance_.count(site_instance) != 0; frames_by_site_instance_.count(site_instance) != 0;
bool is_main_frame = (render_frame_host == web_contents()->GetMainFrame()); bool is_main_frame = (render_frame_host == web_contents()->GetMainFrame());
bool site_instance_is_main = (site_instance == main_frame_site_instance_); bool site_instance_is_main = (site_instance == main_frame_site_instance_);
RendererTask* new_task = nullptr; RendererTask* new_task = nullptr;
// We don't create a task if there's one for this site_instance AND
// if this is not the main frame or we did record a main frame for the entry. // We need to create a task if one doesn't already exist for this
// SiteInstance, or if the main frame navigates to a process that currently is
// represented by a SubframeTask.
if (!site_instance_exists || (is_main_frame && !site_instance_is_main)) { if (!site_instance_exists || (is_main_frame && !site_instance_is_main)) {
if (is_main_frame) { if (is_main_frame) {
const WebContentsTag* tag = const WebContentsTag* tag =
...@@ -280,7 +307,7 @@ void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) { ...@@ -280,7 +307,7 @@ void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) {
RendererTask* old_task = tasks_by_frames_[existing_rfh]; RendererTask* old_task = tasks_by_frames_[existing_rfh];
if (!new_task) { if (!new_task) {
// We didn't create any new task, so we keep appending the old one. // We didn't create any new task, so we keep using the old one.
tasks_by_frames_[render_frame_host] = old_task; tasks_by_frames_[render_frame_host] = old_task;
} else { } else {
// Overwrite all the existing old tasks with the new one, and delete the // Overwrite all the existing old tasks with the new one, and delete the
...@@ -298,6 +325,15 @@ void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) { ...@@ -298,6 +325,15 @@ void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) {
if (new_task) { if (new_task) {
tasks_by_frames_[render_frame_host] = new_task; tasks_by_frames_[render_frame_host] = new_task;
provider_->NotifyObserverTaskAdded(new_task); provider_->NotifyObserverTaskAdded(new_task);
// If we don't know the OS process handle yet (e.g., because this task is
// still launching), update the task when it becomes available.
if (new_task->process_id() == base::kNullProcessId) {
render_frame_host->GetProcess()->PostTaskWhenProcessIsReady(base::Bind(
&WebContentsEntry::RenderFrameReady, weak_factory_.GetWeakPtr(),
render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID()));
}
} }
} }
...@@ -320,6 +356,9 @@ void WebContentsEntry::ClearTaskForFrame(RenderFrameHost* render_frame_host) { ...@@ -320,6 +356,9 @@ void WebContentsEntry::ClearTaskForFrame(RenderFrameHost* render_frame_host) {
if (site_instance == main_frame_site_instance_) if (site_instance == main_frame_site_instance_)
main_frame_site_instance_ = nullptr; main_frame_site_instance_ = nullptr;
} }
// Whenever we have a task, we should have a main frame site instance.
DCHECK(tasks_by_frames_.empty() == (main_frame_site_instance_ == nullptr));
} }
void WebContentsEntry::ForEachTask( void WebContentsEntry::ForEachTask(
...@@ -335,9 +374,7 @@ void WebContentsEntry::ForEachTask( ...@@ -335,9 +374,7 @@ void WebContentsEntry::ForEachTask(
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
WebContentsTaskProvider::WebContentsTaskProvider() WebContentsTaskProvider::WebContentsTaskProvider() : is_updating_(false) {}
: is_updating_(false) {
}
WebContentsTaskProvider::~WebContentsTaskProvider() { WebContentsTaskProvider::~WebContentsTaskProvider() {
if (is_updating_) { if (is_updating_) {
......
...@@ -109,32 +109,33 @@ TaskGroup::TaskGroup( ...@@ -109,32 +109,33 @@ TaskGroup::TaskGroup(
gpu_memory_has_duplicates_(false), gpu_memory_has_duplicates_(false),
is_backgrounded_(false), is_backgrounded_(false),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
scoped_refptr<TaskGroupSampler> sampler( if (process_id_ != base::kNullProcessId) {
new TaskGroupSampler(base::Process::Open(proc_id), worker_thread_sampler_ = base::MakeRefCounted<TaskGroupSampler>(
blocking_pool_runner, base::Process::Open(process_id_), blocking_pool_runner,
base::Bind(&TaskGroup::OnCpuRefreshDone, base::Bind(&TaskGroup::OnCpuRefreshDone,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
base::Bind(&TaskGroup::OnMemoryUsageRefreshDone, base::Bind(&TaskGroup::OnMemoryUsageRefreshDone,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
base::Bind(&TaskGroup::OnIdleWakeupsRefreshDone, base::Bind(&TaskGroup::OnIdleWakeupsRefreshDone,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
#if defined(OS_LINUX) #if defined(OS_LINUX)
base::Bind(&TaskGroup::OnOpenFdCountRefreshDone, base::Bind(&TaskGroup::OnOpenFdCountRefreshDone,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
#endif // defined(OS_LINUX) #endif // defined(OS_LINUX)
base::Bind(&TaskGroup::OnProcessPriorityDone, base::Bind(&TaskGroup::OnProcessPriorityDone,
weak_ptr_factory_.GetWeakPtr()))); weak_ptr_factory_.GetWeakPtr()));
worker_thread_sampler_.swap(sampler);
shared_sampler_->RegisterCallbacks(
shared_sampler_->RegisterCallbacks( process_id_,
process_id_, base::Bind(&TaskGroup::OnIdleWakeupsRefreshDone, base::Bind(&TaskGroup::OnIdleWakeupsRefreshDone,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
base::Bind(&TaskGroup::OnPhysicalMemoryUsageRefreshDone, base::Bind(&TaskGroup::OnPhysicalMemoryUsageRefreshDone,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
base::Bind(&TaskGroup::OnStartTimeRefreshDone, base::Bind(&TaskGroup::OnStartTimeRefreshDone,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
base::Bind(&TaskGroup::OnCpuTimeRefreshDone, base::Bind(&TaskGroup::OnCpuTimeRefreshDone,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
}
} }
TaskGroup::~TaskGroup() { TaskGroup::~TaskGroup() {
...@@ -226,7 +227,8 @@ void TaskGroup::Refresh(const gpu::VideoMemoryUsageStats& gpu_memory_stats, ...@@ -226,7 +227,8 @@ void TaskGroup::Refresh(const gpu::VideoMemoryUsageStats& gpu_memory_stats,
// 9- Idle Wakeups per second. // 9- Idle Wakeups per second.
// 10- (Linux and ChromeOS only) The number of file descriptors current open. // 10- (Linux and ChromeOS only) The number of file descriptors current open.
// 11- Process priority (foreground vs. background). // 11- Process priority (foreground vs. background).
worker_thread_sampler_->Refresh(refresh_flags); if (worker_thread_sampler_)
worker_thread_sampler_->Refresh(refresh_flags);
} }
Task* TaskGroup::GetTaskById(TaskId task_id) const { Task* TaskGroup::GetTaskById(TaskId task_id) const {
......
...@@ -867,6 +867,109 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, DevToolsOldUndockedWindow) { ...@@ -867,6 +867,109 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, DevToolsOldUndockedWindow) {
DevToolsWindowTesting::CloseDevToolsWindowSync(devtools); DevToolsWindowTesting::CloseDevToolsWindowSync(devtools);
} }
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, HistoryNavigationInNewTab) {
ShowTaskManager();
ui_test_utils::NavigateToURL(browser(), GetTestURL());
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("title1.html")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab()));
ui_test_utils::NavigateToURL(browser(), GURL("about:version"));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("About Version")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab()));
chrome::GoBack(browser(), WindowOpenDisposition::NEW_BACKGROUND_TAB);
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("About Version")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("title1.html")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab()));
// In http://crbug.com/738169, the task_manager::Task for the background tab
// was created with process id 0, resulting in zero values for all process
// metrics. Ensure that this is not the case.
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed(
MatchTab("title1.html"), ColumnSpecifier::PROCESS_ID,
base::kNullProcessId));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed(
MatchTab("title1.html"), ColumnSpecifier::PHYSICAL_MEMORY, 1000));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed(
MatchTab("About Version"), ColumnSpecifier::PHYSICAL_MEMORY, 1000));
}
IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, SubframeHistoryNavigation) {
if (!ShouldExpectSubframes())
return; // This test is lame without OOPIFs.
ShowTaskManager();
// This URL will have two out-of-process iframe processes (for b.com and
// c.com) under --site-per-process: it's an a.com page containing a b.com
// <iframe> containing a b.com <iframe> containing a c.com <iframe>.
ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b(b(c)))"));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchTab("Cross-site iframe factory")));
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()));
GURL d_url = embedded_test_server()->GetURL(
"d.com", "/cross_site_iframe_factory.html?d(e)");
ASSERT_TRUE(content::ExecuteScript(
browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
"frames[0][0].location.href = '" + d_url.spec() + "';"));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(0, MatchSubframe("http://c.com/")));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchSubframe("http://d.com/")));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchSubframe("http://e.com/")));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchSubframe("http://b.com/")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(3, MatchAnySubframe()));
chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchSubframe("http://c.com/")));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(0, MatchSubframe("http://d.com/")));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(0, MatchSubframe("http://e.com/")));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchSubframe("http://b.com/")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe()));
chrome::GoForward(browser(), WindowOpenDisposition::NEW_BACKGROUND_TAB);
// When the subframe appears in the cloned process, it must have a valid
// process ID.
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed(
MatchSubframe("http://d.com/"), ColumnSpecifier::PROCESS_ID,
base::kNullProcessId));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed(
MatchSubframe("http://e.com/"), ColumnSpecifier::PROCESS_ID,
base::kNullProcessId));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(2, MatchSubframe("http://b.com/")));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(2, MatchSubframe("http://b.com/")));
ASSERT_NO_FATAL_FAILURE(
WaitForTaskManagerRows(1, MatchSubframe("http://c.com/")));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(5, MatchAnySubframe()));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab()));
// Subframe processes should report some amount of physical memory usage.
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed(
MatchSubframe("http://d.com/"), ColumnSpecifier::PHYSICAL_MEMORY, 1000));
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed(
MatchSubframe("http://e.com/"), ColumnSpecifier::PHYSICAL_MEMORY, 1000));
}
IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, KillSubframe) { IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, KillSubframe) {
ShowTaskManager(); ShowTaskManager();
...@@ -1156,14 +1259,7 @@ IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, ...@@ -1156,14 +1259,7 @@ IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest,
ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe()));
} }
// Flaky on Linux http://crbug.com/700684 IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, OrderingOfDependentRows) {
#if defined(OS_LINUX)
#define MAYBE_OrderingOfDependentRows DISABLED_OrderingOfDependentRows
#else
#define MAYBE_OrderingOfDependentRows OrderingOfDependentRows
#endif
IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest,
MAYBE_OrderingOfDependentRows) {
ShowTaskManager(); ShowTaskManager();
GURL a_with_frames(embedded_test_server()->GetURL( GURL a_with_frames(embedded_test_server()->GetURL(
......
...@@ -106,6 +106,10 @@ class ResourceChangeObserver { ...@@ -106,6 +106,10 @@ class ResourceChangeObserver {
switch (column_specifier_) { switch (column_specifier_) {
case ColumnSpecifier::COLUMN_NONE: case ColumnSpecifier::COLUMN_NONE:
return "N/A"; return "N/A";
case ColumnSpecifier::PROCESS_ID:
return "Process ID";
case ColumnSpecifier::PHYSICAL_MEMORY:
return "Physical Memory";
case ColumnSpecifier::V8_MEMORY: case ColumnSpecifier::V8_MEMORY:
return "V8 Memory"; return "V8 Memory";
case ColumnSpecifier::V8_MEMORY_USED: case ColumnSpecifier::V8_MEMORY_USED:
......
...@@ -21,6 +21,8 @@ namespace browsertest_util { ...@@ -21,6 +21,8 @@ namespace browsertest_util {
// Specifies some integer-valued column of numeric data reported by the task // Specifies some integer-valued column of numeric data reported by the task
// manager model. Please add more here as needed by tests. // manager model. Please add more here as needed by tests.
enum class ColumnSpecifier { enum class ColumnSpecifier {
PROCESS_ID,
PHYSICAL_MEMORY,
V8_MEMORY, V8_MEMORY,
V8_MEMORY_USED, V8_MEMORY_USED,
SQLITE_MEMORY_USED, SQLITE_MEMORY_USED,
......
...@@ -99,6 +99,12 @@ void TaskManagerTester::ToggleColumnVisibility(ColumnSpecifier column) { ...@@ -99,6 +99,12 @@ void TaskManagerTester::ToggleColumnVisibility(ColumnSpecifier column) {
switch (column) { switch (column) {
case ColumnSpecifier::COLUMN_NONE: case ColumnSpecifier::COLUMN_NONE:
return; return;
case ColumnSpecifier::PROCESS_ID:
column_id = IDS_TASK_MANAGER_PROCESS_ID_COLUMN;
break;
case ColumnSpecifier::PHYSICAL_MEMORY:
column_id = IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN;
break;
case ColumnSpecifier::SQLITE_MEMORY_USED: case ColumnSpecifier::SQLITE_MEMORY_USED:
column_id = IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN; column_id = IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN;
break; break;
...@@ -130,6 +136,14 @@ int64_t TaskManagerTester::GetColumnValue(ColumnSpecifier column, int row) { ...@@ -130,6 +136,14 @@ int64_t TaskManagerTester::GetColumnValue(ColumnSpecifier column, int row) {
case ColumnSpecifier::COLUMN_NONE: case ColumnSpecifier::COLUMN_NONE:
case ColumnSpecifier::MEMORY_STATE: case ColumnSpecifier::MEMORY_STATE:
break; break;
case ColumnSpecifier::PHYSICAL_MEMORY:
value = task_manager()->GetPhysicalMemoryUsage(task_id);
success = true;
break;
case ColumnSpecifier::PROCESS_ID:
value = static_cast<int64_t>(task_manager()->GetProcessId(task_id));
success = true;
break;
case ColumnSpecifier::V8_MEMORY: case ColumnSpecifier::V8_MEMORY:
success = task_manager()->GetV8Memory(task_id, &value, &ignored); success = task_manager()->GetV8Memory(task_id, &value, &ignored);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment