// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/task_management/providers/web_contents/renderer_task.h" #include "base/i18n/rtl.h" #include "base/numerics/safe_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/favicon/favicon_utils.h" #include "chrome/browser/process_resource_usage.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/task_management/task_manager_observer.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/common/service_registry.h" #include "ui/base/l10n/l10n_util.h" namespace task_management { namespace { // Creates the Mojo service wrapper that will be used to sample the V8 memory // usage and the the WebCache resource stats of the render process hosted by // |render_process_host|. ProcessResourceUsage* CreateRendererResourcesSampler( content::RenderProcessHost* render_process_host) { ResourceUsageReporterPtr service; content::ServiceRegistry* service_registry = render_process_host->GetServiceRegistry(); if (service_registry) service_registry->ConnectToRemoteService(mojo::GetProxy(&service)); return new ProcessResourceUsage(service.Pass()); } // Gets the profile name associated with the browser context of the given // |render_process_host| from the profile info cache. base::string16 GetRendererProfileName( const content::RenderProcessHost* render_process_host) { Profile* profile = Profile::FromBrowserContext(render_process_host->GetBrowserContext()); return Task::GetProfileNameFromProfile(profile); } inline bool IsRendererResourceSamplingDisabled(int64_t flags) { return (flags & (REFRESH_TYPE_V8_MEMORY | REFRESH_TYPE_WEBCACHE_STATS)) == 0; } std::string GetRapporSampleName(content::WebContents* web_contents) { return web_contents->GetVisibleURL().GetOrigin().spec(); } } // namespace RendererTask::RendererTask(const base::string16& title, const gfx::ImageSkia* icon, content::WebContents* web_contents, content::RenderProcessHost* render_process_host) : Task(title, GetRapporSampleName(web_contents), icon, render_process_host->GetHandle()), web_contents_(web_contents), render_process_host_(render_process_host), renderer_resources_sampler_( CreateRendererResourcesSampler(render_process_host_)), render_process_id_(render_process_host_->GetID()), v8_memory_allocated_(0), v8_memory_used_(0), webcache_stats_(), profile_name_(GetRendererProfileName(render_process_host_)) { // All renderer tasks are capable of reporting network usage, so the default // invalid value of -1 doesn't apply here. OnNetworkBytesRead(0); // Tag the web_contents with a |ContentFaviconDriver| (if needed) so that // we can use it to observe favicons changes. favicon::CreateContentFaviconDriverForWebContents(web_contents); favicon::ContentFaviconDriver::FromWebContents(web_contents)->AddObserver( this); } RendererTask::~RendererTask() { favicon::ContentFaviconDriver::FromWebContents(web_contents())-> RemoveObserver(this); } void RendererTask::UpdateRapporSampleName() { set_rappor_sample_name(GetRapporSampleName(web_contents())); } void RendererTask::Activate() { if (!web_contents_->GetDelegate()) return; web_contents_->GetDelegate()->ActivateContents(web_contents_); } void RendererTask::Refresh(const base::TimeDelta& update_interval, int64_t refresh_flags) { Task::Refresh(update_interval, refresh_flags); if (IsRendererResourceSamplingDisabled(refresh_flags)) return; // The renderer resources refresh is performed asynchronously, we will invoke // it and record the current values (which might be invalid at the moment. We // can safely ignore that and count on future refresh cycles potentially // having valid values). renderer_resources_sampler_->Refresh(base::Closure()); v8_memory_allocated_ = base::saturated_cast( renderer_resources_sampler_->GetV8MemoryAllocated()); v8_memory_used_ = base::saturated_cast( renderer_resources_sampler_->GetV8MemoryUsed()); webcache_stats_ = renderer_resources_sampler_->GetWebCoreCacheStats(); } Task::Type RendererTask::GetType() const { return Task::RENDERER; } int RendererTask::GetChildProcessUniqueID() const { return render_process_id_; } base::string16 RendererTask::GetProfileName() const { return profile_name_; } int64_t RendererTask::GetV8MemoryAllocated() const { return v8_memory_allocated_; } int64_t RendererTask::GetV8MemoryUsed() const { return v8_memory_used_; } bool RendererTask::ReportsWebCacheStats() const { return true; } blink::WebCache::ResourceTypeStats RendererTask::GetWebCacheStats() const { return webcache_stats_; } void RendererTask::OnFaviconUpdated(favicon::FaviconDriver* favicon_driver, NotificationIconType notification_icon_type, const GURL& icon_url, bool icon_url_changed, const gfx::Image& image) { if (notification_icon_type == NON_TOUCH_16_DIP) UpdateFavicon(); } // static base::string16 RendererTask::GetTitleFromWebContents( content::WebContents* web_contents) { DCHECK(web_contents); base::string16 title = web_contents->GetTitle(); if (title.empty()) { GURL url = web_contents->GetURL(); title = base::UTF8ToUTF16(url.spec()); // Force URL to be LTR. title = base::i18n::GetDisplayStringInLTRDirectionality(title); } else { // Since the title could later be concatenated with // IDS_TASK_MANAGER_TAB_PREFIX (for example), we need to explicitly set the // 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(&title); } return title; } // static const gfx::ImageSkia* RendererTask::GetFaviconFromWebContents( content::WebContents* web_contents) { DCHECK(web_contents); // Tag the web_contents with a |ContentFaviconDriver| (if needed) so that // we can use it to retrieve the favicon if there is one. favicon::CreateContentFaviconDriverForWebContents(web_contents); gfx::Image image = favicon::ContentFaviconDriver::FromWebContents(web_contents)-> GetFavicon(); if (image.IsEmpty()) return nullptr; return image.ToImageSkia(); } // static const base::string16 RendererTask::PrefixRendererTitle( const base::string16& title, bool is_app, bool is_extension, bool is_incognito, bool is_background) { int message_id = IDS_TASK_MANAGER_TAB_PREFIX; if (is_incognito && !is_app && !is_extension) { message_id = IDS_TASK_MANAGER_TAB_INCOGNITO_PREFIX; } else if (is_app) { if (is_background) message_id = IDS_TASK_MANAGER_BACKGROUND_PREFIX; else if (is_incognito) message_id = IDS_TASK_MANAGER_APP_INCOGNITO_PREFIX; else message_id = IDS_TASK_MANAGER_APP_PREFIX; } else if (is_extension) { if (is_incognito) message_id = IDS_TASK_MANAGER_EXTENSION_INCOGNITO_PREFIX; else message_id = IDS_TASK_MANAGER_EXTENSION_PREFIX; } return l10n_util::GetStringFUTF16(message_id, title); } } // namespace task_management