blob: 6dfbc0c9e869355695e0e91aa5e8de7fb11c307e [file] [log] [blame]
// Copyright (c) 2010 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_manager_resource_providers.h"
#include "build/build_config.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/basictypes.h"
#include "base/file_version_info.h"
#include "base/i18n/rtl.h"
#include "base/process_util.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/notifications/balloon_collection.h"
#include "chrome/browser/notifications/balloon_host.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/sqlite_utils.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#if defined(OS_MACOSX)
#include "skia/ext/skia_utils_mac.h"
#endif
#if defined(OS_WIN)
#include "chrome/browser/app_icon_win.h"
#include "gfx/icon_util.h"
#endif // defined(OS_WIN)
////////////////////////////////////////////////////////////////////////////////
// TaskManagerTabContentsResource class
////////////////////////////////////////////////////////////////////////////////
TaskManagerTabContentsResource::TaskManagerTabContentsResource(
TabContents* tab_contents)
: tab_contents_(tab_contents),
pending_stats_update_(false),
v8_memory_allocated_(0),
v8_memory_used_(0),
pending_v8_memory_allocated_update_(false) {
// We cache the process as when the TabContents is closed the process
// becomes NULL and the TaskManager still needs it.
process_ = tab_contents_->GetRenderProcessHost()->GetHandle();
pid_ = base::GetProcId(process_);
stats_.images.size = 0;
stats_.cssStyleSheets.size = 0;
stats_.scripts.size = 0;
stats_.xslStyleSheets.size = 0;
stats_.fonts.size = 0;
}
TaskManagerTabContentsResource::~TaskManagerTabContentsResource() {
}
std::wstring TaskManagerTabContentsResource::GetTitle() const {
// Fall back on the URL if there's no title.
std::wstring tab_title(UTF16ToWideHack(tab_contents_->GetTitle()));
if (tab_title.empty()) {
tab_title = UTF8ToWide(tab_contents_->GetURL().spec());
// Force URL to be LTR.
base::i18n::GetDisplayStringInLTRDirectionality(&tab_title);
} else {
// Since the tab_title will be concatenated with
// IDS_TASK_MANAGER_TAB_PREFIX, we need to explicitly set the tab_title to
// be LTR format if there is no strong RTL charater in it. Otherwise, if
// IDS_TASK_MANAGER_TAB_PREFIX is an RTL word, the concatenated result
// might be wrong. For example, http://mail.yahoo.com, whose title is
// "Yahoo! Mail: The best web-based Email!", without setting it explicitly
// as LTR format, the concatenated result will be "!Yahoo! Mail: The best
// web-based Email :BAT", in which the capital letters "BAT" stands for
// the Hebrew word for "tab".
base::i18n::AdjustStringForLocaleDirection(tab_title, &tab_title);
}
return l10n_util::GetStringF(IDS_TASK_MANAGER_TAB_PREFIX, tab_title);
}
void TaskManagerTabContentsResource::Refresh() {
if (!pending_stats_update_) {
tab_contents_->render_view_host()->Send(new ViewMsg_GetCacheResourceStats);
pending_stats_update_ = true;
}
if (!pending_v8_memory_allocated_update_) {
tab_contents_->render_view_host()->Send(new ViewMsg_GetV8HeapStats);
pending_v8_memory_allocated_update_ = true;
}
}
WebKit::WebCache::ResourceTypeStats
TaskManagerTabContentsResource::GetWebCoreCacheStats() const {
return stats_;
}
size_t TaskManagerTabContentsResource::GetV8MemoryAllocated() const {
return v8_memory_allocated_;
}
size_t TaskManagerTabContentsResource::GetV8MemoryUsed() const {
return v8_memory_used_;
}
void TaskManagerTabContentsResource::NotifyResourceTypeStats(
const WebKit::WebCache::ResourceTypeStats& stats) {
stats_ = stats;
pending_stats_update_ = false;
}
void TaskManagerTabContentsResource::NotifyV8HeapStats(
size_t v8_memory_allocated, size_t v8_memory_used) {
v8_memory_allocated_ = v8_memory_allocated;
v8_memory_used_ = v8_memory_used;
pending_v8_memory_allocated_update_ = false;
}
SkBitmap TaskManagerTabContentsResource::GetIcon() const {
return tab_contents_->GetFavIcon();
}
base::ProcessHandle TaskManagerTabContentsResource::GetProcess() const {
return process_;
}
TabContents* TaskManagerTabContentsResource::GetTabContents() const {
return static_cast<TabContents*>(tab_contents_);
}
////////////////////////////////////////////////////////////////////////////////
// TaskManagerTabContentsResourceProvider class
////////////////////////////////////////////////////////////////////////////////
TaskManagerTabContentsResourceProvider::
TaskManagerTabContentsResourceProvider(TaskManager* task_manager)
: updating_(false),
task_manager_(task_manager) {
}
TaskManagerTabContentsResourceProvider::
~TaskManagerTabContentsResourceProvider() {
}
TaskManager::Resource* TaskManagerTabContentsResourceProvider::GetResource(
int origin_pid,
int render_process_host_id,
int routing_id) {
TabContents* tab_contents =
tab_util::GetTabContentsByID(render_process_host_id, routing_id);
if (!tab_contents) // Not one of our resource.
return NULL;
base::ProcessHandle process_handle =
tab_contents->GetRenderProcessHost()->GetHandle();
if (!process_handle) {
// We should not be holding on to a dead tab (it should have been removed
// through the NOTIFY_TAB_CONTENTS_DISCONNECTED notification.
NOTREACHED();
return NULL;
}
int pid = base::GetProcId(process_handle);
if (pid != origin_pid)
return NULL;
std::map<TabContents*, TaskManagerTabContentsResource*>::iterator
res_iter = resources_.find(tab_contents);
if (res_iter == resources_.end())
// Can happen if the tab was closed while a network request was being
// performed.
return NULL;
return res_iter->second;
}
void TaskManagerTabContentsResourceProvider::StartUpdating() {
DCHECK(!updating_);
updating_ = true;
// Add all the existing TabContents.
for (TabContentsIterator iterator; !iterator.done(); ++iterator)
Add(*iterator);
// Then we register for notifications to get new tabs.
registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::TAB_CONTENTS_SWAPPED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
NotificationService::AllSources());
// TAB_CONTENTS_DISCONNECTED should be enough to know when to remove a
// resource. This is an attempt at mitigating a crasher that seem to
// indicate a resource is still referencing a deleted TabContents
// (http://crbug.com/7321).
registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
NotificationService::AllSources());
}
void TaskManagerTabContentsResourceProvider::StopUpdating() {
DCHECK(updating_);
updating_ = false;
// Then we unregister for notifications to get new tabs.
registrar_.Remove(this, NotificationType::TAB_CONTENTS_CONNECTED,
NotificationService::AllSources());
registrar_.Remove(this, NotificationType::TAB_CONTENTS_SWAPPED,
NotificationService::AllSources());
registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
NotificationService::AllSources());
registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
NotificationService::AllSources());
// Delete all the resources.
STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
resources_.clear();
}
void TaskManagerTabContentsResourceProvider::AddToTaskManager(
TabContents* tab_contents) {
TaskManagerTabContentsResource* resource =
new TaskManagerTabContentsResource(tab_contents);
resources_[tab_contents] = resource;
task_manager_->AddResource(resource);
}
void TaskManagerTabContentsResourceProvider::Add(TabContents* tab_contents) {
if (!updating_)
return;
// Don't add dead tabs or tabs that haven't yet connected.
// Also ignore tabs which display extension content. We collapse
// all of these into one extension row.
if (!tab_contents->GetRenderProcessHost()->GetHandle() ||
!tab_contents->notify_disconnection() ||
tab_contents->HostsExtension()) {
return;
}
std::map<TabContents*, TaskManagerTabContentsResource*>::const_iterator
iter = resources_.find(tab_contents);
if (iter != resources_.end()) {
// The case may happen that we have added a TabContents as part of the
// iteration performed during StartUpdating() call but the notification that
// it has connected was not fired yet. So when the notification happens, we
// already know about this tab and just ignore it.
return;
}
AddToTaskManager(tab_contents);
}
void TaskManagerTabContentsResourceProvider::Remove(TabContents* tab_contents) {
if (!updating_)
return;
std::map<TabContents*, TaskManagerTabContentsResource*>::iterator
iter = resources_.find(tab_contents);
if (iter == resources_.end()) {
// Since TabContents are destroyed asynchronously (see TabContentsCollector
// in navigation_controller.cc), we can be notified of a tab being removed
// that we don't know. This can happen if the user closes a tab and quickly
// opens the task manager, before the tab is actually destroyed.
return;
}
// Remove the resource from the Task Manager.
TaskManagerTabContentsResource* resource = iter->second;
task_manager_->RemoveResource(resource);
// And from the provider.
resources_.erase(iter);
// Finally, delete the resource.
delete resource;
}
void TaskManagerTabContentsResourceProvider::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type.value) {
case NotificationType::TAB_CONTENTS_CONNECTED:
Add(Source<TabContents>(source).ptr());
break;
case NotificationType::TAB_CONTENTS_SWAPPED:
Remove(Source<TabContents>(source).ptr());
Add(Source<TabContents>(source).ptr());
break;
case NotificationType::TAB_CONTENTS_DESTROYED:
// If this DCHECK is triggered, it could explain http://crbug.com/7321.
DCHECK(resources_.find(Source<TabContents>(source).ptr()) ==
resources_.end()) << "TAB_CONTENTS_DESTROYED with no associated "
"TAB_CONTENTS_DISCONNECTED";
// Fall through.
case NotificationType::TAB_CONTENTS_DISCONNECTED:
Remove(Source<TabContents>(source).ptr());
break;
default:
NOTREACHED() << "Unexpected notification.";
return;
}
}
////////////////////////////////////////////////////////////////////////////////
// TaskManagerChildProcessResource class
////////////////////////////////////////////////////////////////////////////////
SkBitmap* TaskManagerChildProcessResource::default_icon_ = NULL;
TaskManagerChildProcessResource::TaskManagerChildProcessResource(
ChildProcessInfo child_proc)
: child_process_(child_proc),
title_(),
network_usage_support_(false) {
// We cache the process id because it's not cheap to calculate, and it won't
// be available when we get the plugin disconnected notification.
pid_ = child_proc.id();
if (!default_icon_) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
// TODO(jabdelmalek): use different icon for web workers.
}
}
TaskManagerChildProcessResource::~TaskManagerChildProcessResource() {
}
// TaskManagerResource methods:
std::wstring TaskManagerChildProcessResource::GetTitle() const {
if (title_.empty())
title_ = child_process_.GetLocalizedTitle();
return title_;
}
SkBitmap TaskManagerChildProcessResource::GetIcon() const {
return *default_icon_;
}
base::ProcessHandle TaskManagerChildProcessResource::GetProcess() const {
return child_process_.handle();
}
////////////////////////////////////////////////////////////////////////////////
// TaskManagerChildProcessResourceProvider class
////////////////////////////////////////////////////////////////////////////////
TaskManagerChildProcessResourceProvider::
TaskManagerChildProcessResourceProvider(TaskManager* task_manager)
: updating_(false),
task_manager_(task_manager) {
}
TaskManagerChildProcessResourceProvider::
~TaskManagerChildProcessResourceProvider() {
}
TaskManager::Resource* TaskManagerChildProcessResourceProvider::GetResource(
int origin_pid,
int render_process_host_id,
int routing_id) {
std::map<int, TaskManagerChildProcessResource*>::iterator iter =
pid_to_resources_.find(origin_pid);
if (iter != pid_to_resources_.end())
return iter->second;
else
return NULL;
}
void TaskManagerChildProcessResourceProvider::StartUpdating() {
DCHECK(!updating_);
updating_ = true;
// Register for notifications to get new child processes.
registrar_.Add(this, NotificationType::CHILD_PROCESS_HOST_CONNECTED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::CHILD_PROCESS_HOST_DISCONNECTED,
NotificationService::AllSources());
// Get the existing child processes.
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableMethod(
this,
&TaskManagerChildProcessResourceProvider::RetrieveChildProcessInfo));
}
void TaskManagerChildProcessResourceProvider::StopUpdating() {
DCHECK(updating_);
updating_ = false;
// Unregister for notifications to get new plugin processes.
registrar_.Remove(this, NotificationType::CHILD_PROCESS_HOST_CONNECTED,
NotificationService::AllSources());
registrar_.Remove(this,
NotificationType::CHILD_PROCESS_HOST_DISCONNECTED,
NotificationService::AllSources());
// Delete all the resources.
STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
resources_.clear();
pid_to_resources_.clear();
existing_child_process_info_.clear();
}
void TaskManagerChildProcessResourceProvider::Observe(
NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type.value) {
case NotificationType::CHILD_PROCESS_HOST_CONNECTED:
Add(*Details<ChildProcessInfo>(details).ptr());
break;
case NotificationType::CHILD_PROCESS_HOST_DISCONNECTED:
Remove(*Details<ChildProcessInfo>(details).ptr());
break;
default:
NOTREACHED() << "Unexpected notification.";
return;
}
}
void TaskManagerChildProcessResourceProvider::Add(
ChildProcessInfo child_process_info) {
if (!updating_)
return;
std::map<ChildProcessInfo, TaskManagerChildProcessResource*>::
const_iterator iter = resources_.find(child_process_info);
if (iter != resources_.end()) {
// The case may happen that we have added a child_process_info as part of
// the iteration performed during StartUpdating() call but the notification
// that it has connected was not fired yet. So when the notification
// happens, we already know about this plugin and just ignore it.
return;
}
AddToTaskManager(child_process_info);
}
void TaskManagerChildProcessResourceProvider::Remove(
ChildProcessInfo child_process_info) {
if (!updating_)
return;
std::map<ChildProcessInfo, TaskManagerChildProcessResource*>
::iterator iter = resources_.find(child_process_info);
if (iter == resources_.end()) {
// ChildProcessInfo disconnection notifications are asynchronous, so we
// might be notified for a plugin we don't know anything about (if it was
// closed before the task manager was shown and destroyed after that).
return;
}
// Remove the resource from the Task Manager.
TaskManagerChildProcessResource* resource = iter->second;
task_manager_->RemoveResource(resource);
// Remove it from the provider.
resources_.erase(iter);
// Remove it from our pid map.
std::map<int, TaskManagerChildProcessResource*>::iterator pid_iter =
pid_to_resources_.find(resource->process_id());
DCHECK(pid_iter != pid_to_resources_.end());
if (pid_iter != pid_to_resources_.end())
pid_to_resources_.erase(pid_iter);
// Finally, delete the resource.
delete resource;
}
void TaskManagerChildProcessResourceProvider::AddToTaskManager(
ChildProcessInfo child_process_info) {
TaskManagerChildProcessResource* resource =
new TaskManagerChildProcessResource(child_process_info);
resources_[child_process_info] = resource;
pid_to_resources_[resource->process_id()] = resource;
task_manager_->AddResource(resource);
}
// The ChildProcessInfo::Iterator has to be used from the IO thread.
void TaskManagerChildProcessResourceProvider::RetrieveChildProcessInfo() {
for (BrowserChildProcessHost::Iterator iter; !iter.Done(); ++iter) {
// Only add processes which are already started, since we need their handle.
if ((*iter)->handle() != base::kNullProcessHandle)
existing_child_process_info_.push_back(**iter);
}
// Now notify the UI thread that we have retrieved information about child
// processes.
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this,
&TaskManagerChildProcessResourceProvider::ChildProcessInfoRetreived));
}
// This is called on the UI thread.
void TaskManagerChildProcessResourceProvider::ChildProcessInfoRetreived() {
std::vector<ChildProcessInfo>::const_iterator iter;
for (iter = existing_child_process_info_.begin();
iter != existing_child_process_info_.end(); ++iter) {
Add(*iter);
}
existing_child_process_info_.clear();
}
////////////////////////////////////////////////////////////////////////////////
// TaskManagerExtensionProcessResource class
////////////////////////////////////////////////////////////////////////////////
SkBitmap* TaskManagerExtensionProcessResource::default_icon_ = NULL;
TaskManagerExtensionProcessResource::TaskManagerExtensionProcessResource(
ExtensionHost* extension_host)
: extension_host_(extension_host) {
if (!default_icon_) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
}
process_handle_ = extension_host_->render_process_host()->GetHandle();
pid_ = base::GetProcId(process_handle_);
std::wstring extension_name(UTF8ToWide(GetExtension()->name()));
DCHECK(!extension_name.empty());
title_ = l10n_util::GetStringF(IDS_TASK_MANAGER_EXTENSION_PREFIX,
extension_name);
}
TaskManagerExtensionProcessResource::~TaskManagerExtensionProcessResource() {
}
std::wstring TaskManagerExtensionProcessResource::GetTitle() const {
return title_;
}
SkBitmap TaskManagerExtensionProcessResource::GetIcon() const {
return *default_icon_;
}
base::ProcessHandle TaskManagerExtensionProcessResource::GetProcess() const {
return process_handle_;
}
const Extension* TaskManagerExtensionProcessResource::GetExtension() const {
return extension_host_->extension();
}
////////////////////////////////////////////////////////////////////////////////
// TaskManagerExtensionProcessResourceProvider class
////////////////////////////////////////////////////////////////////////////////
TaskManagerExtensionProcessResourceProvider::
TaskManagerExtensionProcessResourceProvider(TaskManager* task_manager)
: task_manager_(task_manager),
updating_(false) {
}
TaskManagerExtensionProcessResourceProvider::
~TaskManagerExtensionProcessResourceProvider() {
}
TaskManager::Resource* TaskManagerExtensionProcessResourceProvider::GetResource(
int origin_pid,
int render_process_host_id,
int routing_id) {
std::map<int, TaskManagerExtensionProcessResource*>::iterator iter =
pid_to_resources_.find(origin_pid);
if (iter != pid_to_resources_.end())
return iter->second;
else
return NULL;
}
void TaskManagerExtensionProcessResourceProvider::StartUpdating() {
DCHECK(!updating_);
updating_ = true;
// Add all the existing ExtensionHosts.
ProfileManager* profile_manager = g_browser_process->profile_manager();
for (ProfileManager::const_iterator it = profile_manager->begin();
it != profile_manager->end(); ++it) {
ExtensionProcessManager* process_manager =
(*it)->GetExtensionProcessManager();
if (!process_manager)
continue;
ExtensionProcessManager::const_iterator jt;
for (jt = process_manager->begin(); jt != process_manager->end(); ++jt)
AddToTaskManager(*jt);
}
// Register for notifications about extension process changes.
registrar_.Add(this, NotificationType::EXTENSION_PROCESS_CREATED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
NotificationService::AllSources());
}
void TaskManagerExtensionProcessResourceProvider::StopUpdating() {
DCHECK(updating_);
updating_ = false;
// Unregister for notifications about extension process changes.
registrar_.Remove(this, NotificationType::EXTENSION_PROCESS_CREATED,
NotificationService::AllSources());
registrar_.Remove(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
NotificationService::AllSources());
registrar_.Remove(this, NotificationType::EXTENSION_HOST_DESTROYED,
NotificationService::AllSources());
// Delete all the resources.
STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
resources_.clear();
pid_to_resources_.clear();
}
void TaskManagerExtensionProcessResourceProvider::Observe(
NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type.value) {
case NotificationType::EXTENSION_PROCESS_CREATED:
AddToTaskManager(Details<ExtensionHost>(details).ptr());
break;
case NotificationType::EXTENSION_PROCESS_TERMINATED:
case NotificationType::EXTENSION_HOST_DESTROYED:
RemoveFromTaskManager(Details<ExtensionHost>(details).ptr());
break;
default:
NOTREACHED() << "Unexpected notification.";
return;
}
}
void TaskManagerExtensionProcessResourceProvider::AddToTaskManager(
ExtensionHost* extension_host) {
// Don't add dead extension processes.
if (!extension_host->IsRenderViewLive())
return;
TaskManagerExtensionProcessResource* resource =
new TaskManagerExtensionProcessResource(extension_host);
DCHECK(resources_.find(extension_host) == resources_.end());
resources_[extension_host] = resource;
pid_to_resources_[resource->process_id()] = resource;
task_manager_->AddResource(resource);
}
void TaskManagerExtensionProcessResourceProvider::RemoveFromTaskManager(
ExtensionHost* extension_host) {
if (!updating_)
return;
std::map<ExtensionHost*, TaskManagerExtensionProcessResource*>
::iterator iter = resources_.find(extension_host);
if (iter == resources_.end())
return;
// Remove the resource from the Task Manager.
TaskManagerExtensionProcessResource* resource = iter->second;
task_manager_->RemoveResource(resource);
// Remove it from the provider.
resources_.erase(iter);
// Remove it from our pid map.
std::map<int, TaskManagerExtensionProcessResource*>::iterator pid_iter =
pid_to_resources_.find(resource->process_id());
DCHECK(pid_iter != pid_to_resources_.end());
if (pid_iter != pid_to_resources_.end())
pid_to_resources_.erase(pid_iter);
// Finally, delete the resource.
delete resource;
}
////////////////////////////////////////////////////////////////////////////////
// TaskManagerNotificationResource class
////////////////////////////////////////////////////////////////////////////////
SkBitmap* TaskManagerNotificationResource::default_icon_ = NULL;
TaskManagerNotificationResource::TaskManagerNotificationResource(
BalloonHost* balloon_host)
: balloon_host_(balloon_host) {
if (!default_icon_) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
}
process_handle_ = balloon_host_->render_view_host()->process()->GetHandle();
pid_ = base::GetProcId(process_handle_);
title_ = l10n_util::GetStringF(IDS_TASK_MANAGER_NOTIFICATION_PREFIX,
balloon_host_->GetSource());
}
TaskManagerNotificationResource::~TaskManagerNotificationResource() {
}
SkBitmap TaskManagerNotificationResource::GetIcon() const {
return *default_icon_;
}
base::ProcessHandle TaskManagerNotificationResource::GetProcess() const {
return process_handle_;
}
////////////////////////////////////////////////////////////////////////////////
// TaskManagerNotificationResourceProvider class
////////////////////////////////////////////////////////////////////////////////
TaskManagerNotificationResourceProvider::
TaskManagerNotificationResourceProvider(TaskManager* task_manager)
: task_manager_(task_manager),
updating_(false) {
}
TaskManagerNotificationResourceProvider::
~TaskManagerNotificationResourceProvider() {
}
TaskManager::Resource* TaskManagerNotificationResourceProvider::GetResource(
int origin_pid,
int render_process_host_id,
int routing_id) {
// TODO(johnnyg): provide resources by pid if necessary.
return NULL;
}
void TaskManagerNotificationResourceProvider::StartUpdating() {
DCHECK(!updating_);
updating_ = true;
// Add all the existing BalloonHosts.
BalloonCollection* collection =
g_browser_process->notification_ui_manager()->balloon_collection();
const BalloonCollection::Balloons& balloons = collection->GetActiveBalloons();
for (BalloonCollection::Balloons::const_iterator it = balloons.begin();
it != balloons.end(); ++it) {
AddToTaskManager((*it)->view()->GetHost());
}
// Register for notifications about extension process changes.
registrar_.Add(this, NotificationType::NOTIFY_BALLOON_CONNECTED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::NOTIFY_BALLOON_DISCONNECTED,
NotificationService::AllSources());
}
void TaskManagerNotificationResourceProvider::StopUpdating() {
DCHECK(updating_);
updating_ = false;
// Unregister for notifications about extension process changes.
registrar_.Remove(this, NotificationType::NOTIFY_BALLOON_CONNECTED,
NotificationService::AllSources());
registrar_.Remove(this, NotificationType::NOTIFY_BALLOON_DISCONNECTED,
NotificationService::AllSources());
// Delete all the resources.
STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
resources_.clear();
}
void TaskManagerNotificationResourceProvider::Observe(
NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type.value) {
case NotificationType::NOTIFY_BALLOON_CONNECTED:
AddToTaskManager(Source<BalloonHost>(source).ptr());
break;
case NotificationType::NOTIFY_BALLOON_DISCONNECTED:
RemoveFromTaskManager(Source<BalloonHost>(source).ptr());
break;
default:
NOTREACHED() << "Unexpected notification.";
return;
}
}
void TaskManagerNotificationResourceProvider::AddToTaskManager(
BalloonHost* balloon_host) {
TaskManagerNotificationResource* resource =
new TaskManagerNotificationResource(balloon_host);
DCHECK(resources_.find(balloon_host) == resources_.end());
resources_[balloon_host] = resource;
task_manager_->AddResource(resource);
}
void TaskManagerNotificationResourceProvider::RemoveFromTaskManager(
BalloonHost* balloon_host) {
if (!updating_)
return;
std::map<BalloonHost*, TaskManagerNotificationResource*>::iterator iter =
resources_.find(balloon_host);
if (iter == resources_.end())
return;
// Remove the resource from the Task Manager.
TaskManagerNotificationResource* resource = iter->second;
task_manager_->RemoveResource(resource);
// Remove it from the map.
resources_.erase(iter);
// Finally, delete the resource.
delete resource;
}
////////////////////////////////////////////////////////////////////////////////
// TaskManagerBrowserProcessResource class
////////////////////////////////////////////////////////////////////////////////
SkBitmap* TaskManagerBrowserProcessResource::default_icon_ = NULL;
TaskManagerBrowserProcessResource::TaskManagerBrowserProcessResource()
: title_() {
pid_ = base::GetCurrentProcId();
bool success = base::OpenPrivilegedProcessHandle(pid_, &process_);
DCHECK(success);
#if defined(OS_WIN)
if (!default_icon_) {
HICON icon = GetAppIcon();
if (icon) {
ICONINFO icon_info = {0};
BITMAP bitmap_info = {0};
GetIconInfo(icon, &icon_info);
GetObject(icon_info.hbmMask, sizeof(bitmap_info), &bitmap_info);
gfx::Size icon_size(bitmap_info.bmWidth, bitmap_info.bmHeight);
default_icon_ = IconUtil::CreateSkBitmapFromHICON(icon, icon_size);
}
}
#elif defined(OS_LINUX)
if (!default_icon_) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
default_icon_ = rb.GetBitmapNamed(IDR_PRODUCT_LOGO_16);
}
#elif defined(OS_MACOSX)
if (!default_icon_) {
// IDR_PRODUCT_LOGO_16 doesn't quite look like chrome/mac's icns icon. Load
// the real app icon (requires a nsimage->skbitmap->nsimage conversion :-().
default_icon_ = new SkBitmap(gfx::AppplicationIconAtSize(16));
}
#else
// TODO(port): Port icon code.
NOTIMPLEMENTED();
#endif // defined(OS_WIN)
}
TaskManagerBrowserProcessResource::~TaskManagerBrowserProcessResource() {
base::CloseProcessHandle(process_);
}
// TaskManagerResource methods:
std::wstring TaskManagerBrowserProcessResource::GetTitle() const {
if (title_.empty()) {
title_ = l10n_util::GetString(IDS_TASK_MANAGER_WEB_BROWSER_CELL_TEXT);
}
return title_;
}
SkBitmap TaskManagerBrowserProcessResource::GetIcon() const {
return *default_icon_;
}
size_t TaskManagerBrowserProcessResource::SqliteMemoryUsedBytes() const {
return static_cast<size_t>(sqlite3_memory_used());
}
base::ProcessHandle TaskManagerBrowserProcessResource::GetProcess() const {
return base::GetCurrentProcessHandle(); // process_;
}
////////////////////////////////////////////////////////////////////////////////
// TaskManagerBrowserProcessResourceProvider class
////////////////////////////////////////////////////////////////////////////////
TaskManagerBrowserProcessResourceProvider::
TaskManagerBrowserProcessResourceProvider(TaskManager* task_manager)
: updating_(false),
task_manager_(task_manager) {
}
TaskManagerBrowserProcessResourceProvider::
~TaskManagerBrowserProcessResourceProvider() {
}
TaskManager::Resource* TaskManagerBrowserProcessResourceProvider::GetResource(
int origin_pid,
int render_process_host_id,
int routing_id) {
if (origin_pid != resource_.process_id()) {
return NULL;
}
return &resource_;
}
void TaskManagerBrowserProcessResourceProvider::StartUpdating() {
task_manager_->AddResource(&resource_);
}
void TaskManagerBrowserProcessResourceProvider::StopUpdating() {
}