#include "chrome/browser/task_manager/task_manager.h"
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/i18n/number_formatting.h"
#include "base/i18n/rtl.h"
#include "base/process_util.h"
#include "base/rand_util.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/background/background_contents_service.h"
#include "chrome/browser/background/background_contents_service_factory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/task_manager/task_manager_resource_providers.h"
#include "chrome/browser/task_manager/task_manager_worker_resource_provider.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/view_type.h"
#include "content/public/browser/browser_child_process_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/result_codes.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/ui_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/text/bytes_formatting.h"
#include "ui/gfx/image/image_skia.h"
#include "unicode/coll.h"
using content::BrowserThread;
using content::OpenURLParams;
using content::Referrer;
using content::ResourceRequestInfo;
using content::WebContents;
namespace {
#if defined(OS_MACOSX)
const int kUpdateTimeMs = 2000;
#else
const int kUpdateTimeMs = 1000;
#endif
template <class T>
int ValueCompare(T value1, T value2) {
if (value1 < value2)
return -1;
if (value1 == value2)
return 0;
return 1;
}
string16 FormatStatsSize(const WebKit::WebCache::ResourceTypeStat& stat) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
ui::FormatBytesWithUnits(stat.size, ui::DATA_UNITS_KIBIBYTE, false),
ui::FormatBytesWithUnits(stat.liveSize, ui::DATA_UNITS_KIBIBYTE, false));
}
}
TaskManagerModel::TaskManagerModel(TaskManager* task_manager)
: pending_video_memory_usage_stats_update_(false),
update_requests_(0),
listen_requests_(0),
update_state_(IDLE),
goat_salt_(base::RandUint64()),
last_unique_id_(0) {
AddResourceProvider(
new TaskManagerBrowserProcessResourceProvider(task_manager));
AddResourceProvider(
new TaskManagerBackgroundContentsResourceProvider(task_manager));
AddResourceProvider(new TaskManagerTabContentsResourceProvider(task_manager));
AddResourceProvider(new TaskManagerPanelResourceProvider(task_manager));
AddResourceProvider(
new TaskManagerChildProcessResourceProvider(task_manager));
AddResourceProvider(
new TaskManagerExtensionProcessResourceProvider(task_manager));
#if defined(ENABLE_NOTIFICATIONS)
TaskManager::ResourceProvider* provider =
TaskManagerNotificationResourceProvider::Create(task_manager);
if (provider)
AddResourceProvider(provider);
#endif
AddResourceProvider(new TaskManagerWorkerResourceProvider(task_manager));
}
TaskManagerModel::~TaskManagerModel() {
}
int TaskManagerModel::ResourceCount() const {
return resources_.size();
}
int TaskManagerModel::GroupCount() const {
return group_map_.size();
}
void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) {
observer_list_.AddObserver(observer);
}
void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) {
observer_list_.RemoveObserver(observer);
}
int TaskManagerModel::GetResourceUniqueId(int index) const {
CHECK_LT(index, ResourceCount());
return resources_[index]->get_unique_id();
}
int TaskManagerModel::GetResourceIndexByUniqueId(const int unique_id) const {
for (int resource_index = 0; resource_index < ResourceCount();
++resource_index) {
if (GetResourceUniqueId(resource_index) == unique_id)
return resource_index;
}
return -1;
}
string16 TaskManagerModel::GetResourceTitle(int index) const {
CHECK_LT(index, ResourceCount());
return resources_[index]->GetTitle();
}
string16 TaskManagerModel::GetResourceProfileName(int index) const {
CHECK_LT(index, ResourceCount());
return resources_[index]->GetProfileName();
}
int64 TaskManagerModel::GetNetworkUsage(int index) const {
CHECK_LT(index, ResourceCount());
return GetNetworkUsage(resources_[index]);
}
string16 TaskManagerModel::GetResourceNetworkUsage(int index) const {
int64 net_usage = GetNetworkUsage(index);
if (net_usage == -1)
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
if (net_usage == 0)
return ASCIIToUTF16("0");
string16 net_byte = ui::FormatSpeed(net_usage);
return base::i18n::GetDisplayStringInLTRDirectionality(net_byte);
}
double TaskManagerModel::GetCPUUsage(int index) const {
CHECK_LT(index, ResourceCount());
return GetCPUUsage(resources_[index]);
}
string16 TaskManagerModel::GetResourceCPUUsage(int index) const {
CHECK_LT(index, ResourceCount());
return UTF8ToUTF16(base::StringPrintf(
#if defined(OS_MACOSX)
"%.1f",
#else
"%.0f",
#endif
GetCPUUsage(resources_[index])));
}
string16 TaskManagerModel::GetResourcePrivateMemory(int index) const {
size_t private_mem;
if (!GetPrivateMemory(index, &private_mem))
return ASCIIToUTF16("N/A");
return GetMemCellText(private_mem);
}
string16 TaskManagerModel::GetResourceSharedMemory(int index) const {
size_t shared_mem;
if (!GetSharedMemory(index, &shared_mem))
return ASCIIToUTF16("N/A");
return GetMemCellText(shared_mem);
}
string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const {
size_t phys_mem;
GetPhysicalMemory(index, &phys_mem);
return GetMemCellText(phys_mem);
}
int TaskManagerModel::GetProcessId(int index) const {
CHECK_LT(index, ResourceCount());
return base::GetProcId(resources_[index]->GetProcess());
}
base::ProcessHandle TaskManagerModel::GetProcess(int index) const {
CHECK_LT(index, ResourceCount());
return resources_[index]->GetProcess();
}
string16 TaskManagerModel::GetResourceProcessId(int index) const {
return base::IntToString16(GetProcessId(index));
}
string16 TaskManagerModel::GetResourceGoatsTeleported(int index) const {
CHECK_LT(index, ResourceCount());
return base::FormatNumber(GetGoatsTeleported(index));
}
string16 TaskManagerModel::GetResourceWebCoreImageCacheSize(
int index) const {
CHECK_LT(index, ResourceCount());
if (!resources_[index]->ReportsCacheStats())
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
const WebKit::WebCache::ResourceTypeStats stats(
resources_[index]->GetWebCoreCacheStats());
return FormatStatsSize(stats.images);
}
string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
int index) const {
CHECK_LT(index, ResourceCount());
if (!resources_[index]->ReportsCacheStats())
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
const WebKit::WebCache::ResourceTypeStats stats(
resources_[index]->GetWebCoreCacheStats());
return FormatStatsSize(stats.scripts);
}
string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize(
int index) const {
CHECK_LT(index, ResourceCount());
if (!resources_[index]->ReportsCacheStats())
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
const WebKit::WebCache::ResourceTypeStats stats(
resources_[index]->GetWebCoreCacheStats());
return FormatStatsSize(stats.cssStyleSheets);
}
string16 TaskManagerModel::GetResourceVideoMemory(int index) const {
CHECK_LT(index, ResourceCount());
bool result;
size_t video_memory;
bool has_duplicates;
result = GetVideoMemory(index, &video_memory, &has_duplicates);
if (!result || !video_memory) {
return ASCIIToUTF16("N/A");
} else if (has_duplicates) {
return ASCIIToUTF16("(") +
GetMemCellText(video_memory) +
ASCIIToUTF16(")");
} else {
return GetMemCellText(video_memory);
}
}
string16 TaskManagerModel::GetResourceFPS(
int index) const {
CHECK_LT(index, ResourceCount());
if (!resources_[index]->ReportsFPS())
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
double fps = resources_[index]->GetFPS();
return UTF8ToUTF16(base::StringPrintf("%.0f", fps));
}
string16 TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const {
CHECK_LT(index, ResourceCount());
if (!resources_[index]->ReportsSqliteMemoryUsed())
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
return GetMemCellText(resources_[index]->SqliteMemoryUsedBytes());
}
string16 TaskManagerModel::GetResourceV8MemoryAllocatedSize(
int index) const {
if (!resources_[index]->ReportsV8MemoryStats())
return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
ui::FormatBytesWithUnits(resources_[index]->GetV8MemoryAllocated(),
ui::DATA_UNITS_KIBIBYTE,
false),
ui::FormatBytesWithUnits(resources_[index]->GetV8MemoryUsed(),
ui::DATA_UNITS_KIBIBYTE,
false));
}
bool TaskManagerModel::IsResourceFirstInGroup(int index) const {
CHECK_LT(index, ResourceCount());
TaskManager::Resource* resource = resources_[index];
GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
DCHECK(iter != group_map_.end());
const ResourceList* group = iter->second;
return ((*group)[0] == resource);
}
bool TaskManagerModel::IsResourceLastInGroup(int index) const {
CHECK_LT(index, ResourceCount());
TaskManager::Resource* resource = resources_[index];
GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
DCHECK(iter != group_map_.end());
const ResourceList* group = iter->second;
return (group->back() == resource);
}
bool TaskManagerModel::IsBackgroundResource(int index) const {
CHECK_LT(index, ResourceCount());
return resources_[index]->IsBackground();
}
gfx::ImageSkia TaskManagerModel::GetResourceIcon(int index) const {
CHECK_LT(index, ResourceCount());
gfx::ImageSkia icon = resources_[index]->GetIcon();
if (!icon.isNull())
return icon;
static gfx::ImageSkia* default_icon = ResourceBundle::GetSharedInstance().
GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
return *default_icon;
}
TaskManagerModel::GroupRange
TaskManagerModel::GetGroupRangeForResource(int index) const {
CHECK_LT(index, ResourceCount());
TaskManager::Resource* resource = resources_[index];
GroupMap::const_iterator group_iter =
group_map_.find(resource->GetProcess());
DCHECK(group_iter != group_map_.end());
ResourceList* group = group_iter->second;
DCHECK(group);
if (group->size() == 1) {
return std::make_pair(index, 1);
} else {
for (int i = index; i >= 0; --i) {
if (resources_[i] == (*group)[0])
return std::make_pair(i, group->size());
}
NOTREACHED();
return std::make_pair(-1, -1);
}
}
int TaskManagerModel::GetGroupIndexForResource(int index) const {
int group_index = -1;
for (int i = 0; i <= index; ++i) {
if (IsResourceFirstInGroup(i))
group_index++;
}
DCHECK_NE(group_index, -1);
return group_index;
}
int TaskManagerModel::GetResourceIndexForGroup(int group_index,
int index_in_group) const {
int group_count = -1;
int count_in_group = -1;
for (int i = 0; i < ResourceCount(); ++i) {
if (IsResourceFirstInGroup(i))
group_count++;
if (group_count == group_index) {
count_in_group++;
if (count_in_group == index_in_group)
return i;
} else if (group_count > group_index) {
break;
}
}
NOTREACHED();
return -1;
}
int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const {
CHECK(row1 < ResourceCount() && row2 < ResourceCount());
if (col_id == IDS_TASK_MANAGER_TASK_COLUMN) {
static icu::Collator* collator = NULL;
if (!collator) {
UErrorCode create_status = U_ZERO_ERROR;
collator = icu::Collator::createInstance(create_status);
if (!U_SUCCESS(create_status)) {
collator = NULL;
NOTREACHED();
}
}
string16 title1 = GetResourceTitle(row1);
string16 title2 = GetResourceTitle(row2);
UErrorCode compare_status = U_ZERO_ERROR;
UCollationResult compare_result = collator->compare(
static_cast<const UChar*>(title1.c_str()),
static_cast<int>(title1.length()),
static_cast<const UChar*>(title2.c_str()),
static_cast<int>(title2.length()),
compare_status);
DCHECK(U_SUCCESS(compare_status));
return compare_result;
} else if (col_id == IDS_TASK_MANAGER_PROFILE_NAME_COLUMN) {
string16 profile1 = GetResourceProfileName(row1);
string16 profile2 = GetResourceProfileName(row2);
return profile1.compare(0, profile1.length(), profile2, 0,
profile2.length());
} else if (col_id == IDS_TASK_MANAGER_NET_COLUMN) {
return ValueCompare<int64>(GetNetworkUsage(resources_[row1]),
GetNetworkUsage(resources_[row2]));
} else if (col_id == IDS_TASK_MANAGER_CPU_COLUMN) {
return ValueCompare<double>(GetCPUUsage(resources_[row1]),
GetCPUUsage(resources_[row2]));
} else if (col_id == IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN) {
size_t value1;
size_t value2;
if (!GetPrivateMemory(row1, &value1) || !GetPrivateMemory(row2, &value2))
return 0;
return ValueCompare<size_t>(value1, value2);
} else if (col_id == IDS_TASK_MANAGER_SHARED_MEM_COLUMN) {
size_t value1;
size_t value2;
if (!GetSharedMemory(row1, &value1) || !GetSharedMemory(row2, &value2))
return 0;
return ValueCompare<size_t>(value1, value2);
} else if (col_id == IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN) {
size_t value1;
size_t value2;
if (!GetPhysicalMemory(row1, &value1) ||
!GetPhysicalMemory(row2, &value2))
return 0;
return ValueCompare<size_t>(value1, value2);
} else if (col_id == IDS_TASK_MANAGER_PROCESS_ID_COLUMN) {
int proc1_id = base::GetProcId(resources_[row1]->GetProcess());
int proc2_id = base::GetProcId(resources_[row2]->GetProcess());
return ValueCompare<int>(proc1_id, proc2_id);
} else if (col_id == IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN ||
col_id == IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN ||
col_id == IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN) {
WebKit::WebCache::ResourceTypeStats stats1 = { { 0 } };
WebKit::WebCache::ResourceTypeStats stats2 = { { 0 } };
if (resources_[row1]->ReportsCacheStats())
stats1 = resources_[row1]->GetWebCoreCacheStats();
if (resources_[row2]->ReportsCacheStats())
stats2 = resources_[row2]->GetWebCoreCacheStats();
if (IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN == col_id)
return ValueCompare<size_t>(stats1.images.size, stats2.images.size);
if (IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN == col_id)
return ValueCompare<size_t>(stats1.scripts.size, stats2.scripts.size);
DCHECK_EQ(IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN, col_id);
return ValueCompare<size_t>(stats1.cssStyleSheets.size,
stats2.cssStyleSheets.size);
} else if (col_id == IDS_TASK_MANAGER_FPS_COLUMN) {
return ValueCompare<float>(resources_[row1]->GetFPS(),
resources_[row2]->GetFPS());
} else if (col_id == IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN) {
size_t value1;
size_t value2;
bool has_duplicates;
if (!GetVideoMemory(row1, &value1, &has_duplicates)) value1 = 0;
if (!GetVideoMemory(row2, &value2, &has_duplicates)) value2 = 0;
return ValueCompare<size_t>(value1, value2);
} else if (col_id == IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN) {
return ValueCompare<int>(GetGoatsTeleported(row1),
GetGoatsTeleported(row2));
} else if (col_id == IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN) {
size_t value1;
size_t value2;
bool reports_v8_memory1 = GetV8Memory(row1, &value1);
bool reports_v8_memory2 = GetV8Memory(row2, &value2);
if (reports_v8_memory1 == reports_v8_memory2)
return ValueCompare<size_t>(value1, value2);
else
return reports_v8_memory1 ? 1 : -1;
} else {
NOTREACHED();
return 0;
}
}
base::ProcessHandle TaskManagerModel::GetResourceProcessHandle(int index)
const {
CHECK_LT(index, ResourceCount());
return resources_[index]->GetProcess();
}
int TaskManagerModel::GetUniqueChildProcessId(int index) const {
CHECK_LT(index, ResourceCount());
return resources_[index]->GetUniqueChildProcessId();
}
TaskManager::Resource::Type TaskManagerModel::GetResourceType(int index) const {
CHECK_LT(index, ResourceCount());
return resources_[index]->GetType();
}
WebContents* TaskManagerModel::GetResourceWebContents(int index) const {
CHECK_LT(index, ResourceCount());
return resources_[index]->GetWebContents();
}
const extensions::Extension* TaskManagerModel::GetResourceExtension(
int index) const {
CHECK_LT(index, ResourceCount());
return resources_[index]->GetExtension();
}
int64 TaskManagerModel::GetNetworkUsage(TaskManager::Resource* resource)
const {
int64 net_usage = GetNetworkUsageForResource(resource);
if (net_usage == 0 && !resource->SupportNetworkUsage())
return -1;
return net_usage;
}
double TaskManagerModel::GetCPUUsage(TaskManager::Resource* resource) const {
CPUUsageMap::const_iterator iter =
cpu_usage_map_.find(resource->GetProcess());
if (iter == cpu_usage_map_.end())
return 0;
return iter->second;
}
bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const {
base::ProcessHandle handle = resources_[index]->GetProcess();
MemoryUsageMap::const_iterator iter = memory_usage_map_.find(handle);
if (iter == memory_usage_map_.end()) {
MemoryUsageEntry usage;
if (!GetAndCacheMemoryMetrics(handle, &usage))
return false;
*result = usage.first;
} else {
*result = iter->second.first;
}
return true;
}
bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const {
base::ProcessHandle handle = resources_[index]->GetProcess();
MemoryUsageMap::const_iterator iter = memory_usage_map_.find(handle);
if (iter == memory_usage_map_.end()) {
MemoryUsageEntry usage;
if (!GetAndCacheMemoryMetrics(handle, &usage))
return false;
*result = usage.second;
} else {
*result = iter->second.second;
}
return true;
}
bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const {
*result = 0;
base::ProcessMetrics* process_metrics;
if (!GetProcessMetricsForRow(index, &process_metrics))
return false;
base::WorkingSetKBytes ws_usage;
if (!process_metrics->GetWorkingSetKBytes(&ws_usage))
return false;
size_t total_bytes = process_metrics->GetWorkingSetSize();
total_bytes -= ws_usage.shared * 1024;
*result = total_bytes;
return true;
}
bool TaskManagerModel::GetWebCoreCacheStats(
int index, WebKit::WebCache::ResourceTypeStats* result) const {
if (!resources_[index]->ReportsCacheStats())
return false;
*result = resources_[index]->GetWebCoreCacheStats();
return true;
}
bool TaskManagerModel::GetVideoMemory(
int index, size_t* video_memory, bool* has_duplicates) const {
TaskManager::Resource* resource = resources_[index];
base::ProcessId pid = base::GetProcId(resource->GetProcess());
content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i =
video_memory_usage_stats_.process_map.find(pid);
if (i == video_memory_usage_stats_.process_map.end()) {
*video_memory = 0;
*has_duplicates = false;
return false;
}
*video_memory = (*i).second.video_memory;
*has_duplicates = (*i).second.has_duplicates;
return true;
}
bool TaskManagerModel::GetFPS(int index, float* result) const {
*result = 0;
if (!resources_[index]->ReportsFPS())
return false;
*result = resources_[index]->GetFPS();
return true;
}
bool TaskManagerModel::GetSqliteMemoryUsedBytes(
int index, size_t* result) const {
*result = 0;
if (!resources_[index]->ReportsSqliteMemoryUsed())
return false;
*result = resources_[index]->SqliteMemoryUsedBytes();
return true;
}
bool TaskManagerModel::GetV8Memory(int index, size_t* result) const {
*result = 0;
if (!resources_[index]->ReportsV8MemoryStats())
return false;
*result = resources_[index]->GetV8MemoryAllocated();
return true;
}
bool TaskManagerModel::GetV8MemoryUsed(int index, size_t* result) const {
*result = 0;
if (!resources_[index]->ReportsV8MemoryStats())
return false;
*result = resources_[index]->GetV8MemoryUsed();
return true;
}
bool TaskManagerModel::CanActivate(int index) const {
CHECK_LT(index, ResourceCount());
return GetResourceWebContents(index) != NULL;
}
bool TaskManagerModel::CanInspect(int index) const {
CHECK_LT(index, ResourceCount());
return resources_[index]->CanInspect();
}
void TaskManagerModel::Inspect(int index) const {
CHECK_LT(index, ResourceCount());
resources_[index]->Inspect();
}
int TaskManagerModel::GetGoatsTeleported(int index) const {
int seed = goat_salt_ * (index + 1);
return (seed >> 16) & 255;
}
string16 TaskManagerModel::GetMemCellText(int64 number) const {
#if !defined(OS_MACOSX)
string16 str = base::FormatNumber(number / 1024);
base::i18n::AdjustStringForLocaleDirection(&str);
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT, str);
#else
return ui::FormatBytes(number);
#endif
}
void TaskManagerModel::StartListening() {
listen_requests_++;
if (listen_requests_ > 1)
return;
DCHECK_EQ(1, listen_requests_);
for (ResourceProviderList::iterator iter = providers_.begin();
iter != providers_.end(); ++iter) {
(*iter)->StartUpdating();
}
}
void TaskManagerModel::StopListening() {
listen_requests_--;
if (listen_requests_ > 0)
return;
DCHECK_EQ(0, listen_requests_);
for (ResourceProviderList::const_iterator iter = providers_.begin();
iter != providers_.end(); ++iter) {
(*iter)->StopUpdating();
}
Clear();
}
void TaskManagerModel::StartUpdating() {
update_requests_++;
if (update_requests_ > 1)
return;
DCHECK_EQ(1, update_requests_);
DCHECK_NE(TASK_PENDING, update_state_);
if (update_state_ == IDLE) {
MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&TaskManagerModel::Refresh, this));
}
update_state_ = TASK_PENDING;
StartListening();
if (!resources_.empty()) {
FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
OnReadyPeriodicalUpdate());
}
}
void TaskManagerModel::StopUpdating() {
update_requests_--;
if (update_requests_ > 0)
return;
CHECK_EQ(0, update_requests_);
DCHECK_EQ(TASK_PENDING, update_state_);
update_state_ = STOPPING;
StopListening();
}
void TaskManagerModel::AddResourceProvider(
TaskManager::ResourceProvider* provider) {
DCHECK(provider);
providers_.push_back(provider);
}
void TaskManagerModel::AddResource(TaskManager::Resource* resource) {
resource->unique_id_ = ++last_unique_id_;
base::ProcessHandle process = resource->GetProcess();
ResourceList* group_entries = NULL;
GroupMap::const_iterator group_iter = group_map_.find(process);
int new_entry_index = 0;
if (group_iter == group_map_.end()) {
group_entries = new ResourceList();
group_map_[process] = group_entries;
group_entries->push_back(resource);
resources_.push_back(resource);
new_entry_index = static_cast<int>(resources_.size() - 1);
} else {
group_entries = group_iter->second;
group_entries->push_back(resource);
ResourceList::iterator iter =
std::find(resources_.begin(),
resources_.end(),
(*group_entries)[group_entries->size() - 2]);
DCHECK(iter != resources_.end());
new_entry_index = static_cast<int>(iter - resources_.begin()) + 1;
resources_.insert(++iter, resource);
}
if (metrics_map_.find(process) == metrics_map_.end()) {
base::ProcessMetrics* pm =
#if !defined(OS_MACOSX)
base::ProcessMetrics::CreateProcessMetrics(process);
#else
base::ProcessMetrics::CreateProcessMetrics(
process, content::BrowserChildProcessHost::GetPortProvider());
#endif
metrics_map_[process] = pm;
}
FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
OnItemsAdded(new_entry_index, 1));
}
void TaskManagerModel::RemoveResource(TaskManager::Resource* resource) {
base::ProcessHandle process = resource->GetProcess();
GroupMap::iterator group_iter = group_map_.find(process);
DCHECK(group_iter != group_map_.end());
ResourceList* group_entries = group_iter->second;
ResourceList::iterator iter = std::find(group_entries->begin(),
group_entries->end(),
resource);
DCHECK(iter != group_entries->end());
group_entries->erase(iter);
if (group_entries->empty()) {
delete group_entries;
group_map_.erase(process);
MetricsMap::iterator pm_iter = metrics_map_.find(process);
DCHECK(pm_iter != metrics_map_.end());
if (pm_iter != metrics_map_.end()) {
delete pm_iter->second;
metrics_map_.erase(process);
}
CPUUsageMap::iterator cpu_iter = cpu_usage_map_.find(process);
if (cpu_iter != cpu_usage_map_.end())
cpu_usage_map_.erase(cpu_iter);
}
iter = std::find(resources_.begin(), resources_.end(), resource);
DCHECK(iter != resources_.end());
int index = static_cast<int>(iter - resources_.begin());
FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
OnItemsToBeRemoved(index, 1));
resources_.erase(iter);
ResourceValueMap::iterator net_iter =
current_byte_count_map_.find(resource);
if (net_iter != current_byte_count_map_.end())
current_byte_count_map_.erase(net_iter);
net_iter = displayed_network_usage_map_.find(resource);
if (net_iter != displayed_network_usage_map_.end())
displayed_network_usage_map_.erase(net_iter);
FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
OnItemsRemoved(index, 1));
}
void TaskManagerModel::Clear() {
int size = ResourceCount();
if (size > 0) {
resources_.clear();
for (GroupMap::iterator iter = group_map_.begin();
iter != group_map_.end(); ++iter) {
delete iter->second;
}
group_map_.clear();
for (MetricsMap::iterator iter = metrics_map_.begin();
iter != metrics_map_.end(); ++iter) {
delete iter->second;
}
metrics_map_.clear();
cpu_usage_map_.clear();
current_byte_count_map_.clear();
displayed_network_usage_map_.clear();
FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
OnItemsRemoved(0, size));
}
last_unique_id_ = 0;
}
void TaskManagerModel::ModelChanged() {
FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, OnModelChanged());
}
void TaskManagerModel::NotifyResourceTypeStats(
base::ProcessId renderer_id,
const WebKit::WebCache::ResourceTypeStats& stats) {
for (ResourceList::iterator it = resources_.begin();
it != resources_.end(); ++it) {
if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
(*it)->NotifyResourceTypeStats(stats);
}
}
}
void TaskManagerModel::NotifyFPS(base::ProcessId renderer_id,
int routing_id,
float fps) {
for (ResourceList::iterator it = resources_.begin();
it != resources_.end(); ++it) {
if (base::GetProcId((*it)->GetProcess()) == renderer_id &&
(*it)->GetRoutingID() == routing_id) {
(*it)->NotifyFPS(fps);
}
}
}
void TaskManagerModel::NotifyVideoMemoryUsageStats(
const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
DCHECK(pending_video_memory_usage_stats_update_);
video_memory_usage_stats_ = video_memory_usage_stats;
pending_video_memory_usage_stats_update_ = false;
}
void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id,
size_t v8_memory_allocated,
size_t v8_memory_used) {
for (ResourceList::iterator it = resources_.begin();
it != resources_.end(); ++it) {
if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
(*it)->NotifyV8HeapStats(v8_memory_allocated, v8_memory_used);
}
}
}
class TaskManagerModelGpuDataManagerObserver
: public content::GpuDataManagerObserver {
public:
TaskManagerModelGpuDataManagerObserver() {
content::GpuDataManager::GetInstance()->AddObserver(this);
}
virtual ~TaskManagerModelGpuDataManagerObserver() {
content::GpuDataManager::GetInstance()->RemoveObserver(this);
}
static void NotifyVideoMemoryUsageStats(
content::GPUVideoMemoryUsageStats video_memory_usage_stats) {
TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats(
video_memory_usage_stats);
}
virtual void OnGpuInfoUpdate() OVERRIDE {}
virtual void OnVideoMemoryUsageStatsUpdate(
const content::GPUVideoMemoryUsageStats& video_memory_usage_stats)
OVERRIDE {
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
NotifyVideoMemoryUsageStats(video_memory_usage_stats);
} else {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, base::Bind(
&TaskManagerModelGpuDataManagerObserver::
NotifyVideoMemoryUsageStats,
video_memory_usage_stats));
}
}
};
void TaskManagerModel::RefreshVideoMemoryUsageStats()
{
if (pending_video_memory_usage_stats_update_) return;
if (!video_memory_usage_stats_observer_.get()) {
video_memory_usage_stats_observer_.reset(
new TaskManagerModelGpuDataManagerObserver());
}
pending_video_memory_usage_stats_update_ = true;
content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate();
}
void TaskManagerModel::Refresh() {
DCHECK_NE(IDLE, update_state_);
if (update_state_ == STOPPING) {
update_state_ = IDLE;
return;
}
goat_salt_ = base::RandUint64();
cpu_usage_map_.clear();
for (ResourceList::iterator iter = resources_.begin();
iter != resources_.end(); ++iter) {
base::ProcessHandle process = (*iter)->GetProcess();
CPUUsageMap::iterator cpu_iter = cpu_usage_map_.find(process);
if (cpu_iter != cpu_usage_map_.end())
continue;
MetricsMap::iterator metrics_iter = metrics_map_.find(process);
DCHECK(metrics_iter != metrics_map_.end());
cpu_usage_map_[process] = metrics_iter->second->GetCPUUsage();
}
memory_usage_map_.clear();
RefreshVideoMemoryUsageStats();
displayed_network_usage_map_.clear();
base::TimeDelta update_time =
base::TimeDelta::FromMilliseconds(kUpdateTimeMs);
for (ResourceValueMap::iterator iter = current_byte_count_map_.begin();
iter != current_byte_count_map_.end(); ++iter) {
if (update_time > base::TimeDelta::FromSeconds(1)) {
int divider = update_time.InSeconds();
displayed_network_usage_map_[iter->first] = iter->second / divider;
} else {
displayed_network_usage_map_[iter->first] = iter->second *
(1 / update_time.InSeconds());
}
iter->second = 0;
}
for (ResourceList::iterator iter = resources_.begin();
iter != resources_.end(); ++iter) {
(*iter)->Refresh();
}
if (!resources_.empty()) {
FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
OnItemsChanged(0, ResourceCount()));
}
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&TaskManagerModel::Refresh, this),
base::TimeDelta::FromMilliseconds(kUpdateTimeMs));
}
int64 TaskManagerModel::GetNetworkUsageForResource(
TaskManager::Resource* resource) const {
ResourceValueMap::const_iterator iter =
displayed_network_usage_map_.find(resource);
if (iter == displayed_network_usage_map_.end())
return 0;
return iter->second;
}
void TaskManagerModel::BytesRead(BytesReadParam param) {
if (update_state_ != TASK_PENDING || listen_requests_ == 0) {
return;
}
if (param.byte_count == 0) {
return;
}
TaskManager::Resource* resource = NULL;
for (ResourceProviderList::iterator iter = providers_.begin();
iter != providers_.end(); ++iter) {
resource = (*iter)->GetResource(param.origin_pid,
param.render_process_host_child_id,
param.routing_id);
if (resource)
break;
}
if (resource == NULL) {
CHECK(param.origin_pid || (param.render_process_host_child_id != -1));
param.origin_pid = 0;
param.render_process_host_child_id = param.routing_id = -1;
BytesRead(param);
return;
}
if (!resource->SupportNetworkUsage())
resource->SetSupportNetworkUsage();
ResourceValueMap::const_iterator iter_res =
current_byte_count_map_.find(resource);
if (iter_res == current_byte_count_map_.end())
current_byte_count_map_[resource] = param.byte_count;
else
current_byte_count_map_[resource] = iter_res->second + param.byte_count;
}
void TaskManagerModel::NotifyBytesRead(const net::URLRequest& request,
int byte_count) {
const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request);
int render_process_host_child_id = -1, routing_id = -1;
if (info)
info->GetAssociatedRenderView(&render_process_host_child_id, &routing_id);
int origin_pid = 0;
if (info)
origin_pid = info->GetOriginPID();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&TaskManagerModel::BytesRead, this,
BytesReadParam(origin_pid, render_process_host_child_id,
routing_id, byte_count)));
}
bool TaskManagerModel::GetProcessMetricsForRow(
int row, base::ProcessMetrics** proc_metrics) const {
DCHECK(row < ResourceCount());
*proc_metrics = NULL;
MetricsMap::const_iterator iter =
metrics_map_.find(resources_[row]->GetProcess());
if (iter == metrics_map_.end())
return false;
*proc_metrics = iter->second;
return true;
}
int TaskManager::Resource::GetRoutingID() const { return 0; }
bool TaskManager::Resource::ReportsCacheStats() const { return false; }
WebKit::WebCache::ResourceTypeStats
TaskManager::Resource::GetWebCoreCacheStats() const {
return WebKit::WebCache::ResourceTypeStats();
}
bool TaskManager::Resource::ReportsFPS() const { return false; }
float TaskManager::Resource::GetFPS() const { return 0.0f; }
bool TaskManager::Resource::ReportsSqliteMemoryUsed() const { return false; }
size_t TaskManager::Resource::SqliteMemoryUsedBytes() const { return 0; }
const extensions::Extension* TaskManager::Resource::GetExtension() const {
return NULL;
}
bool TaskManager::Resource::ReportsV8MemoryStats() const { return false; }
size_t TaskManager::Resource::GetV8MemoryAllocated() const { return 0; }
size_t TaskManager::Resource::GetV8MemoryUsed() const { return 0; }
bool TaskManager::Resource::CanInspect() const { return false; }
content::WebContents* TaskManager::Resource::GetWebContents() const {
return NULL;
}
bool TaskManager::Resource::IsBackground() const { return false; }
void TaskManager::RegisterPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement);
}
TaskManager::TaskManager()
: ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TaskManagerModel(this))) {
}
TaskManager::~TaskManager() {
}
bool TaskManager::IsBrowserProcess(int index) const {
return index < model_->ResourceCount() &&
model_->GetResourceProcessHandle(index) ==
base::GetCurrentProcessHandle();
}
void TaskManager::KillProcess(int index) {
base::ProcessHandle process = model_->GetResourceProcessHandle(index);
DCHECK(process);
if (process != base::GetCurrentProcessHandle())
base::KillProcess(process, content::RESULT_CODE_KILLED, false);
}
void TaskManager::ActivateProcess(int index) {
WebContents* chosen_web_contents = model_->GetResourceWebContents(index);
if (chosen_web_contents && chosen_web_contents->GetDelegate())
chosen_web_contents->GetDelegate()->ActivateContents(chosen_web_contents);
}
void TaskManager::AddResource(Resource* resource) {
model_->AddResource(resource);
}
void TaskManager::RemoveResource(Resource* resource) {
model_->RemoveResource(resource);
}
void TaskManager::OnWindowClosed() {
model_->StopUpdating();
}
void TaskManager::ModelChanged() {
model_->ModelChanged();
}
TaskManager* TaskManager::GetInstance() {
return Singleton<TaskManager>::get();
}
void TaskManager::OpenAboutMemory() {
Browser* browser = browser::FindOrCreateTabbedBrowser(
ProfileManager::GetDefaultProfileOrOffTheRecord());
chrome::NavigateParams params(browser, GURL(chrome::kChromeUIMemoryURL),
content::PAGE_TRANSITION_LINK);
params.disposition = NEW_FOREGROUND_TAB;
chrome::Navigate(¶ms);
}
bool TaskManagerModel::GetAndCacheMemoryMetrics(base::ProcessHandle handle,
MemoryUsageEntry* usage) const {
MetricsMap::const_iterator iter = metrics_map_.find(handle);
if (iter == metrics_map_.end())
return false;
if (!iter->second->GetMemoryBytes(&usage->first, &usage->second))
return false;
memory_usage_map_.insert(std::make_pair(handle, *usage));
return true;
}
namespace {
int CountExtensionBackgroundPagesForProfile(Profile* profile) {
int count = 0;
ExtensionProcessManager* manager = profile->GetExtensionProcessManager();
if (!manager)
return count;
const ExtensionProcessManager::ExtensionHostSet& background_hosts =
manager->background_hosts();
for (ExtensionProcessManager::const_iterator iter = background_hosts.begin();
iter != background_hosts.end(); ++iter) {
++count;
}
return count;
}
}
int TaskManager::GetBackgroundPageCount() {
int count = 0;
ProfileManager* profile_manager = g_browser_process->profile_manager();
if (!profile_manager)
return count;
std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
for (std::vector<Profile*>::const_iterator iter = profiles.begin();
iter != profiles.end();
++iter) {
Profile* profile = *iter;
BackgroundContentsService* background_contents_service =
BackgroundContentsServiceFactory::GetForProfile(profile);
if (background_contents_service)
count += background_contents_service->GetBackgroundContents().size();
count += CountExtensionBackgroundPagesForProfile(profile);
if (profile->HasOffTheRecordProfile()) {
count += CountExtensionBackgroundPagesForProfile(
profile->GetOffTheRecordProfile());
}
}
return count;
}