Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / task_manager / child_process_resource_provider.cc
blob0054b4b53e275b9cb93743abc9209af33f3e835a
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/task_manager/child_process_resource_provider.h"
7 #include <vector>
9 #include "base/i18n/rtl.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/strings/string16.h"
12 #include "chrome/browser/process_resource_usage.h"
13 #include "chrome/browser/task_manager/resource_provider.h"
14 #include "chrome/browser/task_manager/task_manager.h"
15 #include "chrome/grit/generated_resources.h"
16 #include "components/nacl/common/nacl_process_type.h"
17 #include "content/public/browser/browser_child_process_host.h"
18 #include "content/public/browser/browser_child_process_host_iterator.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/child_process_data.h"
21 #include "content/public/common/service_registry.h"
22 #include "grit/theme_resources.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/base/resource/resource_bundle.h"
25 #include "ui/gfx/image/image_skia.h"
27 using content::BrowserChildProcessHostIterator;
28 using content::BrowserThread;
29 using content::WebContents;
31 namespace task_manager {
33 class ChildProcessResource : public Resource {
34 public:
35 ChildProcessResource(int process_type,
36 const base::string16& name,
37 base::ProcessHandle handle,
38 int unique_process_id);
39 ~ChildProcessResource() override;
41 // Resource methods:
42 base::string16 GetTitle() const override;
43 base::string16 GetProfileName() const override;
44 gfx::ImageSkia GetIcon() const override;
45 base::ProcessHandle GetProcess() const override;
46 int GetUniqueChildProcessId() const override;
47 Type GetType() const override;
48 bool SupportNetworkUsage() const override;
49 void SetSupportNetworkUsage() override;
50 void Refresh() override;
51 bool ReportsV8MemoryStats() const override;
52 size_t GetV8MemoryAllocated() const override;
53 size_t GetV8MemoryUsed() const override;
55 // Returns the pid of the child process.
56 int process_id() const { return pid_; }
58 private:
59 // Returns a localized title for the child process. For example, a plugin
60 // process would be "Plugin: Flash" when name is "Flash".
61 base::string16 GetLocalizedTitle() const;
63 static void ConnectResourceReporterOnIOThread(
64 int id, mojo::InterfaceRequest<ResourceUsageReporter> req);
66 int process_type_;
67 base::string16 name_;
68 base::ProcessHandle handle_;
69 int pid_;
70 int unique_process_id_;
71 mutable base::string16 title_;
72 bool network_usage_support_;
73 scoped_ptr<ProcessResourceUsage> resource_usage_;
75 // The icon painted for the child processs.
76 // TODO(jcampan): we should have plugin specific icons for well-known
77 // plugins.
78 static gfx::ImageSkia* default_icon_;
80 base::WeakPtrFactory<ChildProcessResource> weak_factory_;
82 DISALLOW_COPY_AND_ASSIGN(ChildProcessResource);
85 gfx::ImageSkia* ChildProcessResource::default_icon_ = NULL;
87 // static
88 void ChildProcessResource::ConnectResourceReporterOnIOThread(
89 int id, mojo::InterfaceRequest<ResourceUsageReporter> req) {
90 DCHECK_CURRENTLY_ON(BrowserThread::IO);
91 content::BrowserChildProcessHost* host =
92 content::BrowserChildProcessHost::FromID(id);
93 if (!host)
94 return;
96 content::ServiceRegistry* registry = host->GetServiceRegistry();
97 if (!registry)
98 return;
100 registry->ConnectToRemoteService(req.Pass());
103 ChildProcessResource::ChildProcessResource(int process_type,
104 const base::string16& name,
105 base::ProcessHandle handle,
106 int unique_process_id)
107 : process_type_(process_type),
108 name_(name),
109 handle_(handle),
110 unique_process_id_(unique_process_id),
111 network_usage_support_(false),
112 weak_factory_(this) {
113 // We cache the process id because it's not cheap to calculate, and it won't
114 // be available when we get the plugin disconnected notification.
115 pid_ = base::GetProcId(handle);
116 if (!default_icon_) {
117 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
118 default_icon_ = rb.GetImageSkiaNamed(IDR_PLUGINS_FAVICON);
119 // TODO(jabdelmalek): use different icon for web workers.
121 ResourceUsageReporterPtr service;
122 mojo::InterfaceRequest<ResourceUsageReporter> request =
123 mojo::GetProxy(&service);
124 BrowserThread::PostTask(
125 BrowserThread::IO, FROM_HERE,
126 base::Bind(&ChildProcessResource::ConnectResourceReporterOnIOThread,
127 unique_process_id, base::Passed(&request)));
128 resource_usage_.reset(new ProcessResourceUsage(service.Pass()));
131 ChildProcessResource::~ChildProcessResource() {
134 // Resource methods:
135 base::string16 ChildProcessResource::GetTitle() const {
136 if (title_.empty())
137 title_ = GetLocalizedTitle();
139 return title_;
142 base::string16 ChildProcessResource::GetProfileName() const {
143 return base::string16();
146 gfx::ImageSkia ChildProcessResource::GetIcon() const {
147 return *default_icon_;
150 base::ProcessHandle ChildProcessResource::GetProcess() const {
151 return handle_;
154 int ChildProcessResource::GetUniqueChildProcessId() const {
155 return unique_process_id_;
158 Resource::Type ChildProcessResource::GetType() const {
159 // Translate types to Resource::Type, since ChildProcessData's type
160 // is not available for all TaskManager resources.
161 switch (process_type_) {
162 case content::PROCESS_TYPE_PLUGIN:
163 case content::PROCESS_TYPE_PPAPI_PLUGIN:
164 case content::PROCESS_TYPE_PPAPI_BROKER:
165 return Resource::PLUGIN;
166 case content::PROCESS_TYPE_UTILITY:
167 return Resource::UTILITY;
168 case content::PROCESS_TYPE_ZYGOTE:
169 return Resource::ZYGOTE;
170 case content::PROCESS_TYPE_SANDBOX_HELPER:
171 return Resource::SANDBOX_HELPER;
172 case content::PROCESS_TYPE_GPU:
173 return Resource::GPU;
174 case PROCESS_TYPE_NACL_LOADER:
175 case PROCESS_TYPE_NACL_BROKER:
176 return Resource::NACL;
177 default:
178 return Resource::UNKNOWN;
182 bool ChildProcessResource::SupportNetworkUsage() const {
183 return network_usage_support_;
186 void ChildProcessResource::SetSupportNetworkUsage() {
187 network_usage_support_ = true;
190 base::string16 ChildProcessResource::GetLocalizedTitle() const {
191 base::string16 title = name_;
192 if (title.empty()) {
193 switch (process_type_) {
194 case content::PROCESS_TYPE_PLUGIN:
195 case content::PROCESS_TYPE_PPAPI_PLUGIN:
196 case content::PROCESS_TYPE_PPAPI_BROKER:
197 title = l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UNKNOWN_PLUGIN_NAME);
198 break;
199 default:
200 // Nothing to do for non-plugin processes.
201 break;
205 // Explicitly mark name as LTR if there is no strong RTL character,
206 // to avoid the wrong concatenation result similar to "!Yahoo Mail: the
207 // best web-based Email: NIGULP", in which "NIGULP" stands for the Hebrew
208 // or Arabic word for "plugin".
209 base::i18n::AdjustStringForLocaleDirection(&title);
211 switch (process_type_) {
212 case content::PROCESS_TYPE_UTILITY:
213 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX, title);
214 case content::PROCESS_TYPE_GPU:
215 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_GPU_PREFIX);
216 case content::PROCESS_TYPE_PLUGIN:
217 case content::PROCESS_TYPE_PPAPI_PLUGIN:
218 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PLUGIN_PREFIX, title);
219 case content::PROCESS_TYPE_PPAPI_BROKER:
220 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PLUGIN_BROKER_PREFIX,
221 title);
222 case PROCESS_TYPE_NACL_BROKER:
223 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NACL_BROKER_PREFIX);
224 case PROCESS_TYPE_NACL_LOADER:
225 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_NACL_PREFIX, title);
226 // These types don't need display names or get them from elsewhere.
227 case content::PROCESS_TYPE_BROWSER:
228 case content::PROCESS_TYPE_RENDERER:
229 case content::PROCESS_TYPE_ZYGOTE:
230 case content::PROCESS_TYPE_SANDBOX_HELPER:
231 case content::PROCESS_TYPE_MAX:
232 NOTREACHED();
233 break;
234 case content::PROCESS_TYPE_UNKNOWN:
235 NOTREACHED() << "Need localized name for child process type.";
238 return title;
241 void ChildProcessResource::Refresh() {
242 if (resource_usage_)
243 resource_usage_->Refresh(base::Closure());
246 bool ChildProcessResource::ReportsV8MemoryStats() const {
247 if (resource_usage_)
248 return resource_usage_->ReportsV8MemoryStats();
249 return false;
252 size_t ChildProcessResource::GetV8MemoryAllocated() const {
253 if (resource_usage_)
254 return resource_usage_->GetV8MemoryAllocated();
255 return 0;
258 size_t ChildProcessResource::GetV8MemoryUsed() const {
259 if (resource_usage_)
260 return resource_usage_->GetV8MemoryUsed();
261 return 0;
264 ////////////////////////////////////////////////////////////////////////////////
265 // ChildProcessResourceProvider class
266 ////////////////////////////////////////////////////////////////////////////////
268 ChildProcessResourceProvider::
269 ChildProcessResourceProvider(TaskManager* task_manager)
270 : task_manager_(task_manager),
271 updating_(false) {
274 ChildProcessResourceProvider::~ChildProcessResourceProvider() {
277 Resource* ChildProcessResourceProvider::GetResource(
278 int origin_pid,
279 int child_id,
280 int route_id) {
281 PidResourceMap::iterator iter = pid_to_resources_.find(origin_pid);
282 if (iter != pid_to_resources_.end())
283 return iter->second;
284 else
285 return NULL;
288 void ChildProcessResourceProvider::StartUpdating() {
289 DCHECK(!updating_);
290 updating_ = true;
292 // Get the existing child processes.
293 BrowserThread::PostTask(
294 BrowserThread::IO, FROM_HERE,
295 base::Bind(
296 &ChildProcessResourceProvider::RetrieveChildProcessData,
297 this));
299 BrowserChildProcessObserver::Add(this);
302 void ChildProcessResourceProvider::StopUpdating() {
303 DCHECK(updating_);
304 updating_ = false;
306 // Delete all the resources.
307 STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
309 resources_.clear();
310 pid_to_resources_.clear();
312 BrowserChildProcessObserver::Remove(this);
315 void ChildProcessResourceProvider::BrowserChildProcessHostConnected(
316 const content::ChildProcessData& data) {
317 DCHECK(updating_);
319 if (resources_.count(data.handle)) {
320 // The case may happen that we have added a child_process_info as part of
321 // the iteration performed during StartUpdating() call but the notification
322 // that it has connected was not fired yet. So when the notification
323 // happens, we already know about this plugin and just ignore it.
324 return;
326 AddToTaskManager(data);
329 void ChildProcessResourceProvider::
330 BrowserChildProcessHostDisconnected(
331 const content::ChildProcessData& data) {
332 DCHECK(updating_);
334 ChildProcessMap::iterator iter = resources_.find(data.handle);
335 if (iter == resources_.end()) {
336 // ChildProcessData disconnection notifications are asynchronous, so we
337 // might be notified for a plugin we don't know anything about (if it was
338 // closed before the task manager was shown and destroyed after that).
339 return;
341 // Remove the resource from the Task Manager.
342 ChildProcessResource* resource = iter->second;
343 task_manager_->RemoveResource(resource);
344 // Remove it from the provider.
345 resources_.erase(iter);
346 // Remove it from our pid map.
347 PidResourceMap::iterator pid_iter =
348 pid_to_resources_.find(resource->process_id());
349 DCHECK(pid_iter != pid_to_resources_.end());
350 if (pid_iter != pid_to_resources_.end())
351 pid_to_resources_.erase(pid_iter);
353 // Finally, delete the resource.
354 delete resource;
357 void ChildProcessResourceProvider::AddToTaskManager(
358 const content::ChildProcessData& child_process_data) {
359 ChildProcessResource* resource =
360 new ChildProcessResource(
361 child_process_data.process_type,
362 child_process_data.name,
363 child_process_data.handle,
364 child_process_data.id);
365 resources_[child_process_data.handle] = resource;
366 pid_to_resources_[resource->process_id()] = resource;
367 task_manager_->AddResource(resource);
370 // The ChildProcessData::Iterator has to be used from the IO thread.
371 void ChildProcessResourceProvider::RetrieveChildProcessData() {
372 std::vector<content::ChildProcessData> child_processes;
373 for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
374 // Only add processes which are already started, since we need their handle.
375 if (iter.GetData().handle == base::kNullProcessHandle)
376 continue;
377 child_processes.push_back(iter.GetData());
379 // Now notify the UI thread that we have retrieved information about child
380 // processes.
381 BrowserThread::PostTask(
382 BrowserThread::UI, FROM_HERE,
383 base::Bind(
384 &ChildProcessResourceProvider::ChildProcessDataRetreived,
385 this, child_processes));
388 // This is called on the UI thread.
389 void ChildProcessResourceProvider::ChildProcessDataRetreived(
390 const std::vector<content::ChildProcessData>& child_processes) {
391 for (size_t i = 0; i < child_processes.size(); ++i)
392 AddToTaskManager(child_processes[i]);
394 task_manager_->model()->NotifyDataReady();
397 } // namespace task_manager