NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / task_manager / child_process_resource_provider.cc
blobca276074ef92a0e913876dc4a32ec02a3e3352bb
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/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 {
30 public:
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();
38 // Resource methods:
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_; }
52 private:
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;
57 int process_type_;
58 base::string16 name_;
59 base::ProcessHandle handle_;
60 int pid_;
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
68 // plugins.
69 static gfx::ImageSkia* default_icon_;
71 DISALLOW_COPY_AND_ASSIGN(ChildProcessResource);
74 gfx::ImageSkia* ChildProcessResource::default_icon_ = NULL;
76 ChildProcessResource::ChildProcessResource(
77 int process_type,
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),
83 name_(name),
84 handle_(handle),
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);
91 if (!default_icon_) {
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() {
101 // Resource methods:
102 int ChildProcessResource::GetNaClDebugStubPort() const {
103 return nacl_debug_stub_port_;
106 base::string16 ChildProcessResource::GetTitle() const {
107 if (title_.empty())
108 title_ = GetLocalizedTitle();
110 return title_;
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 {
122 return handle_;
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;
148 default:
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_;
163 if (title.empty()) {
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);
169 break;
170 default:
171 // Nothing to do for non-plugin processes.
172 break;
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,
192 title);
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:
203 NOTREACHED();
204 break;
206 case content::PROCESS_TYPE_WORKER:
207 NOTREACHED() << "Workers are not handled by this provider.";
208 break;
209 case content::PROCESS_TYPE_UNKNOWN:
210 NOTREACHED() << "Need localized name for child process type.";
213 return title;
216 ////////////////////////////////////////////////////////////////////////////////
217 // ChildProcessResourceProvider class
218 ////////////////////////////////////////////////////////////////////////////////
220 ChildProcessResourceProvider::
221 ChildProcessResourceProvider(TaskManager* task_manager)
222 : task_manager_(task_manager),
223 updating_(false) {
226 ChildProcessResourceProvider::~ChildProcessResourceProvider() {
229 Resource* ChildProcessResourceProvider::GetResource(
230 int origin_pid,
231 int child_id,
232 int route_id) {
233 PidResourceMap::iterator iter = pid_to_resources_.find(origin_pid);
234 if (iter != pid_to_resources_.end())
235 return iter->second;
236 else
237 return NULL;
240 void ChildProcessResourceProvider::StartUpdating() {
241 DCHECK(!updating_);
242 updating_ = true;
244 // Get the existing child processes.
245 BrowserThread::PostTask(
246 BrowserThread::IO, FROM_HERE,
247 base::Bind(
248 &ChildProcessResourceProvider::RetrieveChildProcessData,
249 this));
251 BrowserChildProcessObserver::Add(this);
254 void ChildProcessResourceProvider::StopUpdating() {
255 DCHECK(updating_);
256 updating_ = false;
258 // Delete all the resources.
259 STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
261 resources_.clear();
262 pid_to_resources_.clear();
264 BrowserChildProcessObserver::Remove(this);
267 void ChildProcessResourceProvider::BrowserChildProcessHostConnected(
268 const content::ChildProcessData& data) {
269 DCHECK(updating_);
271 // Workers are handled by WorkerResourceProvider.
272 if (data.process_type == content::PROCESS_TYPE_WORKER)
273 return;
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.
279 return;
281 AddToTaskManager(data);
284 void ChildProcessResourceProvider::
285 BrowserChildProcessHostDisconnected(
286 const content::ChildProcessData& data) {
287 DCHECK(updating_);
289 if (data.process_type == content::PROCESS_TYPE_WORKER)
290 return;
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).
296 return;
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.
311 delete 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)
334 continue;
335 if (iter.GetData().process_type == content::PROCESS_TYPE_WORKER)
336 continue;
337 child_processes.push_back(iter.GetData());
339 // Now notify the UI thread that we have retrieved information about child
340 // processes.
341 BrowserThread::PostTask(
342 BrowserThread::UI, FROM_HERE,
343 base::Bind(
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