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"
9 #include "base/i18n/rtl.h"
10 #include "base/strings/string16.h"
11 #include "chrome/browser/task_manager/resource_provider.h"
12 #include "chrome/browser/task_manager/task_manager.h"
13 #include "components/nacl/common/nacl_process_type.h"
14 #include "content/public/browser/browser_child_process_host_iterator.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/child_process_data.h"
17 #include "grit/generated_resources.h"
18 #include "grit/theme_resources.h"
19 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/base/resource/resource_bundle.h"
21 #include "ui/gfx/image/image_skia.h"
23 using content::BrowserChildProcessHostIterator
;
24 using content::BrowserThread
;
25 using content::WebContents
;
27 namespace task_manager
{
29 class ChildProcessResource
: public Resource
{
31 ChildProcessResource(int process_type
,
32 const base::string16
& name
,
33 base::ProcessHandle handle
,
34 int unique_process_id
,
35 int nacl_debug_stub_port
);
36 virtual ~ChildProcessResource();
39 virtual int GetNaClDebugStubPort() const OVERRIDE
;
40 virtual base::string16
GetTitle() const OVERRIDE
;
41 virtual base::string16
GetProfileName() const OVERRIDE
;
42 virtual gfx::ImageSkia
GetIcon() const OVERRIDE
;
43 virtual base::ProcessHandle
GetProcess() const OVERRIDE
;
44 virtual int GetUniqueChildProcessId() const OVERRIDE
;
45 virtual Type
GetType() const OVERRIDE
;
46 virtual bool SupportNetworkUsage() const OVERRIDE
;
47 virtual void SetSupportNetworkUsage() OVERRIDE
;
49 // Returns the pid of the child process.
50 int process_id() const { return pid_
; }
53 // Returns a localized title for the child process. For example, a plugin
54 // process would be "Plug-in: Flash" when name is "Flash".
55 base::string16
GetLocalizedTitle() const;
59 base::ProcessHandle handle_
;
61 int unique_process_id_
;
62 int nacl_debug_stub_port_
;
63 mutable base::string16 title_
;
64 bool network_usage_support_
;
66 // The icon painted for the child processs.
67 // TODO(jcampan): we should have plugin specific icons for well-known
69 static gfx::ImageSkia
* default_icon_
;
71 DISALLOW_COPY_AND_ASSIGN(ChildProcessResource
);
74 gfx::ImageSkia
* ChildProcessResource::default_icon_
= NULL
;
76 ChildProcessResource::ChildProcessResource(
78 const base::string16
& name
,
79 base::ProcessHandle handle
,
80 int unique_process_id
,
81 int nacl_debug_stub_port
)
82 : process_type_(process_type
),
85 unique_process_id_(unique_process_id
),
86 nacl_debug_stub_port_(nacl_debug_stub_port
),
87 network_usage_support_(false) {
88 // We cache the process id because it's not cheap to calculate, and it won't
89 // be available when we get the plugin disconnected notification.
90 pid_
= base::GetProcId(handle
);
92 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
93 default_icon_
= rb
.GetImageSkiaNamed(IDR_PLUGINS_FAVICON
);
94 // TODO(jabdelmalek): use different icon for web workers.
98 ChildProcessResource::~ChildProcessResource() {
102 int ChildProcessResource::GetNaClDebugStubPort() const {
103 return nacl_debug_stub_port_
;
106 base::string16
ChildProcessResource::GetTitle() const {
108 title_
= GetLocalizedTitle();
113 base::string16
ChildProcessResource::GetProfileName() const {
114 return base::string16();
117 gfx::ImageSkia
ChildProcessResource::GetIcon() const {
118 return *default_icon_
;
121 base::ProcessHandle
ChildProcessResource::GetProcess() const {
125 int ChildProcessResource::GetUniqueChildProcessId() const {
126 return unique_process_id_
;
129 Resource::Type
ChildProcessResource::GetType() const {
130 // Translate types to Resource::Type, since ChildProcessData's type
131 // is not available for all TaskManager resources.
132 switch (process_type_
) {
133 case content::PROCESS_TYPE_PLUGIN
:
134 case content::PROCESS_TYPE_PPAPI_PLUGIN
:
135 case content::PROCESS_TYPE_PPAPI_BROKER
:
136 return Resource::PLUGIN
;
137 case content::PROCESS_TYPE_UTILITY
:
138 return Resource::UTILITY
;
139 case content::PROCESS_TYPE_ZYGOTE
:
140 return Resource::ZYGOTE
;
141 case content::PROCESS_TYPE_SANDBOX_HELPER
:
142 return Resource::SANDBOX_HELPER
;
143 case content::PROCESS_TYPE_GPU
:
144 return Resource::GPU
;
145 case PROCESS_TYPE_NACL_LOADER
:
146 case PROCESS_TYPE_NACL_BROKER
:
147 return Resource::NACL
;
149 return Resource::UNKNOWN
;
153 bool ChildProcessResource::SupportNetworkUsage() const {
154 return network_usage_support_
;
157 void ChildProcessResource::SetSupportNetworkUsage() {
158 network_usage_support_
= true;
161 base::string16
ChildProcessResource::GetLocalizedTitle() const {
162 base::string16 title
= name_
;
164 switch (process_type_
) {
165 case content::PROCESS_TYPE_PLUGIN
:
166 case content::PROCESS_TYPE_PPAPI_PLUGIN
:
167 case content::PROCESS_TYPE_PPAPI_BROKER
:
168 title
= l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UNKNOWN_PLUGIN_NAME
);
171 // Nothing to do for non-plugin processes.
176 // Explicitly mark name as LTR if there is no strong RTL character,
177 // to avoid the wrong concatenation result similar to "!Yahoo Mail: the
178 // best web-based Email: NIGULP", in which "NIGULP" stands for the Hebrew
179 // or Arabic word for "plugin".
180 base::i18n::AdjustStringForLocaleDirection(&title
);
182 switch (process_type_
) {
183 case content::PROCESS_TYPE_UTILITY
:
184 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX
);
185 case content::PROCESS_TYPE_GPU
:
186 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_GPU_PREFIX
);
187 case content::PROCESS_TYPE_PLUGIN
:
188 case content::PROCESS_TYPE_PPAPI_PLUGIN
:
189 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PLUGIN_PREFIX
, title
);
190 case content::PROCESS_TYPE_PPAPI_BROKER
:
191 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PLUGIN_BROKER_PREFIX
,
193 case PROCESS_TYPE_NACL_BROKER
:
194 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NACL_BROKER_PREFIX
);
195 case PROCESS_TYPE_NACL_LOADER
:
196 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_NACL_PREFIX
, title
);
197 // These types don't need display names or get them from elsewhere.
198 case content::PROCESS_TYPE_BROWSER
:
199 case content::PROCESS_TYPE_RENDERER
:
200 case content::PROCESS_TYPE_ZYGOTE
:
201 case content::PROCESS_TYPE_SANDBOX_HELPER
:
202 case content::PROCESS_TYPE_MAX
:
206 case content::PROCESS_TYPE_WORKER
:
207 NOTREACHED() << "Workers are not handled by this provider.";
209 case content::PROCESS_TYPE_UNKNOWN
:
210 NOTREACHED() << "Need localized name for child process type.";
216 ////////////////////////////////////////////////////////////////////////////////
217 // ChildProcessResourceProvider class
218 ////////////////////////////////////////////////////////////////////////////////
220 ChildProcessResourceProvider::
221 ChildProcessResourceProvider(TaskManager
* task_manager
)
222 : task_manager_(task_manager
),
226 ChildProcessResourceProvider::~ChildProcessResourceProvider() {
229 Resource
* ChildProcessResourceProvider::GetResource(
233 PidResourceMap::iterator iter
= pid_to_resources_
.find(origin_pid
);
234 if (iter
!= pid_to_resources_
.end())
240 void ChildProcessResourceProvider::StartUpdating() {
244 // Get the existing child processes.
245 BrowserThread::PostTask(
246 BrowserThread::IO
, FROM_HERE
,
248 &ChildProcessResourceProvider::RetrieveChildProcessData
,
251 BrowserChildProcessObserver::Add(this);
254 void ChildProcessResourceProvider::StopUpdating() {
258 // Delete all the resources.
259 STLDeleteContainerPairSecondPointers(resources_
.begin(), resources_
.end());
262 pid_to_resources_
.clear();
264 BrowserChildProcessObserver::Remove(this);
267 void ChildProcessResourceProvider::BrowserChildProcessHostConnected(
268 const content::ChildProcessData
& data
) {
271 // Workers are handled by WorkerResourceProvider.
272 if (data
.process_type
== content::PROCESS_TYPE_WORKER
)
274 if (resources_
.count(data
.handle
)) {
275 // The case may happen that we have added a child_process_info as part of
276 // the iteration performed during StartUpdating() call but the notification
277 // that it has connected was not fired yet. So when the notification
278 // happens, we already know about this plugin and just ignore it.
281 AddToTaskManager(data
);
284 void ChildProcessResourceProvider::
285 BrowserChildProcessHostDisconnected(
286 const content::ChildProcessData
& data
) {
289 if (data
.process_type
== content::PROCESS_TYPE_WORKER
)
291 ChildProcessMap::iterator iter
= resources_
.find(data
.handle
);
292 if (iter
== resources_
.end()) {
293 // ChildProcessData disconnection notifications are asynchronous, so we
294 // might be notified for a plugin we don't know anything about (if it was
295 // closed before the task manager was shown and destroyed after that).
298 // Remove the resource from the Task Manager.
299 ChildProcessResource
* resource
= iter
->second
;
300 task_manager_
->RemoveResource(resource
);
301 // Remove it from the provider.
302 resources_
.erase(iter
);
303 // Remove it from our pid map.
304 PidResourceMap::iterator pid_iter
=
305 pid_to_resources_
.find(resource
->process_id());
306 DCHECK(pid_iter
!= pid_to_resources_
.end());
307 if (pid_iter
!= pid_to_resources_
.end())
308 pid_to_resources_
.erase(pid_iter
);
310 // Finally, delete the resource.
314 void ChildProcessResourceProvider::AddToTaskManager(
315 const content::ChildProcessData
& child_process_data
) {
316 ChildProcessResource
* resource
=
317 new ChildProcessResource(
318 child_process_data
.process_type
,
319 child_process_data
.name
,
320 child_process_data
.handle
,
321 child_process_data
.id
,
322 child_process_data
.nacl_debug_stub_port
);
323 resources_
[child_process_data
.handle
] = resource
;
324 pid_to_resources_
[resource
->process_id()] = resource
;
325 task_manager_
->AddResource(resource
);
328 // The ChildProcessData::Iterator has to be used from the IO thread.
329 void ChildProcessResourceProvider::RetrieveChildProcessData() {
330 std::vector
<content::ChildProcessData
> child_processes
;
331 for (BrowserChildProcessHostIterator iter
; !iter
.Done(); ++iter
) {
332 // Only add processes which are already started, since we need their handle.
333 if (iter
.GetData().handle
== base::kNullProcessHandle
)
335 if (iter
.GetData().process_type
== content::PROCESS_TYPE_WORKER
)
337 child_processes
.push_back(iter
.GetData());
339 // Now notify the UI thread that we have retrieved information about child
341 BrowserThread::PostTask(
342 BrowserThread::UI
, FROM_HERE
,
344 &ChildProcessResourceProvider::ChildProcessDataRetreived
,
345 this, child_processes
));
348 // This is called on the UI thread.
349 void ChildProcessResourceProvider::ChildProcessDataRetreived(
350 const std::vector
<content::ChildProcessData
>& child_processes
) {
351 for (size_t i
= 0; i
< child_processes
.size(); ++i
)
352 AddToTaskManager(child_processes
[i
]);
354 task_manager_
->model()->NotifyDataReady();
357 } // namespace task_manager