Temporarily re-enabling SizeAfterPrefChange test with traces (this time for Linux...
[chromium-blink-merge.git] / chrome / browser / task_manager / child_process_resource_provider.cc
blobeb0510c56d243f4b1fd87059b94d1d38f1dd25af
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 virtual ~ChildProcessResource();
37 // Resource methods:
38 virtual base::string16 GetTitle() const OVERRIDE;
39 virtual base::string16 GetProfileName() const OVERRIDE;
40 virtual gfx::ImageSkia GetIcon() const OVERRIDE;
41 virtual base::ProcessHandle GetProcess() const OVERRIDE;
42 virtual int GetUniqueChildProcessId() const OVERRIDE;
43 virtual Type GetType() const OVERRIDE;
44 virtual bool SupportNetworkUsage() const OVERRIDE;
45 virtual void SetSupportNetworkUsage() OVERRIDE;
47 // Returns the pid of the child process.
48 int process_id() const { return pid_; }
50 private:
51 // Returns a localized title for the child process. For example, a plugin
52 // process would be "Plug-in: Flash" when name is "Flash".
53 base::string16 GetLocalizedTitle() const;
55 int process_type_;
56 base::string16 name_;
57 base::ProcessHandle handle_;
58 int pid_;
59 int unique_process_id_;
60 mutable base::string16 title_;
61 bool network_usage_support_;
63 // The icon painted for the child processs.
64 // TODO(jcampan): we should have plugin specific icons for well-known
65 // plugins.
66 static gfx::ImageSkia* default_icon_;
68 DISALLOW_COPY_AND_ASSIGN(ChildProcessResource);
71 gfx::ImageSkia* ChildProcessResource::default_icon_ = NULL;
73 ChildProcessResource::ChildProcessResource(
74 int process_type,
75 const base::string16& name,
76 base::ProcessHandle handle,
77 int unique_process_id)
78 : process_type_(process_type),
79 name_(name),
80 handle_(handle),
81 unique_process_id_(unique_process_id),
82 network_usage_support_(false) {
83 // We cache the process id because it's not cheap to calculate, and it won't
84 // be available when we get the plugin disconnected notification.
85 pid_ = base::GetProcId(handle);
86 if (!default_icon_) {
87 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
88 default_icon_ = rb.GetImageSkiaNamed(IDR_PLUGINS_FAVICON);
89 // TODO(jabdelmalek): use different icon for web workers.
93 ChildProcessResource::~ChildProcessResource() {
96 // Resource methods:
97 base::string16 ChildProcessResource::GetTitle() const {
98 if (title_.empty())
99 title_ = GetLocalizedTitle();
101 return title_;
104 base::string16 ChildProcessResource::GetProfileName() const {
105 return base::string16();
108 gfx::ImageSkia ChildProcessResource::GetIcon() const {
109 return *default_icon_;
112 base::ProcessHandle ChildProcessResource::GetProcess() const {
113 return handle_;
116 int ChildProcessResource::GetUniqueChildProcessId() const {
117 return unique_process_id_;
120 Resource::Type ChildProcessResource::GetType() const {
121 // Translate types to Resource::Type, since ChildProcessData's type
122 // is not available for all TaskManager resources.
123 switch (process_type_) {
124 case content::PROCESS_TYPE_PLUGIN:
125 case content::PROCESS_TYPE_PPAPI_PLUGIN:
126 case content::PROCESS_TYPE_PPAPI_BROKER:
127 return Resource::PLUGIN;
128 case content::PROCESS_TYPE_UTILITY:
129 return Resource::UTILITY;
130 case content::PROCESS_TYPE_ZYGOTE:
131 return Resource::ZYGOTE;
132 case content::PROCESS_TYPE_SANDBOX_HELPER:
133 return Resource::SANDBOX_HELPER;
134 case content::PROCESS_TYPE_GPU:
135 return Resource::GPU;
136 case PROCESS_TYPE_NACL_LOADER:
137 case PROCESS_TYPE_NACL_BROKER:
138 return Resource::NACL;
139 default:
140 return Resource::UNKNOWN;
144 bool ChildProcessResource::SupportNetworkUsage() const {
145 return network_usage_support_;
148 void ChildProcessResource::SetSupportNetworkUsage() {
149 network_usage_support_ = true;
152 base::string16 ChildProcessResource::GetLocalizedTitle() const {
153 base::string16 title = name_;
154 if (title.empty()) {
155 switch (process_type_) {
156 case content::PROCESS_TYPE_PLUGIN:
157 case content::PROCESS_TYPE_PPAPI_PLUGIN:
158 case content::PROCESS_TYPE_PPAPI_BROKER:
159 title = l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UNKNOWN_PLUGIN_NAME);
160 break;
161 default:
162 // Nothing to do for non-plugin processes.
163 break;
167 // Explicitly mark name as LTR if there is no strong RTL character,
168 // to avoid the wrong concatenation result similar to "!Yahoo Mail: the
169 // best web-based Email: NIGULP", in which "NIGULP" stands for the Hebrew
170 // or Arabic word for "plugin".
171 base::i18n::AdjustStringForLocaleDirection(&title);
173 switch (process_type_) {
174 case content::PROCESS_TYPE_UTILITY:
175 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX);
176 case content::PROCESS_TYPE_GPU:
177 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_GPU_PREFIX);
178 case content::PROCESS_TYPE_PLUGIN:
179 case content::PROCESS_TYPE_PPAPI_PLUGIN:
180 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PLUGIN_PREFIX, title);
181 case content::PROCESS_TYPE_PPAPI_BROKER:
182 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PLUGIN_BROKER_PREFIX,
183 title);
184 case PROCESS_TYPE_NACL_BROKER:
185 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NACL_BROKER_PREFIX);
186 case PROCESS_TYPE_NACL_LOADER:
187 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_NACL_PREFIX, title);
188 // These types don't need display names or get them from elsewhere.
189 case content::PROCESS_TYPE_BROWSER:
190 case content::PROCESS_TYPE_RENDERER:
191 case content::PROCESS_TYPE_ZYGOTE:
192 case content::PROCESS_TYPE_SANDBOX_HELPER:
193 case content::PROCESS_TYPE_MAX:
194 NOTREACHED();
195 break;
197 case content::PROCESS_TYPE_WORKER:
198 NOTREACHED() << "Workers are not handled by this provider.";
199 break;
200 case content::PROCESS_TYPE_UNKNOWN:
201 NOTREACHED() << "Need localized name for child process type.";
204 return title;
207 ////////////////////////////////////////////////////////////////////////////////
208 // ChildProcessResourceProvider class
209 ////////////////////////////////////////////////////////////////////////////////
211 ChildProcessResourceProvider::
212 ChildProcessResourceProvider(TaskManager* task_manager)
213 : task_manager_(task_manager),
214 updating_(false) {
217 ChildProcessResourceProvider::~ChildProcessResourceProvider() {
220 Resource* ChildProcessResourceProvider::GetResource(
221 int origin_pid,
222 int child_id,
223 int route_id) {
224 PidResourceMap::iterator iter = pid_to_resources_.find(origin_pid);
225 if (iter != pid_to_resources_.end())
226 return iter->second;
227 else
228 return NULL;
231 void ChildProcessResourceProvider::StartUpdating() {
232 DCHECK(!updating_);
233 updating_ = true;
235 // Get the existing child processes.
236 BrowserThread::PostTask(
237 BrowserThread::IO, FROM_HERE,
238 base::Bind(
239 &ChildProcessResourceProvider::RetrieveChildProcessData,
240 this));
242 BrowserChildProcessObserver::Add(this);
245 void ChildProcessResourceProvider::StopUpdating() {
246 DCHECK(updating_);
247 updating_ = false;
249 // Delete all the resources.
250 STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
252 resources_.clear();
253 pid_to_resources_.clear();
255 BrowserChildProcessObserver::Remove(this);
258 void ChildProcessResourceProvider::BrowserChildProcessHostConnected(
259 const content::ChildProcessData& data) {
260 DCHECK(updating_);
262 // Workers are handled by WorkerResourceProvider.
263 if (data.process_type == content::PROCESS_TYPE_WORKER)
264 return;
265 if (resources_.count(data.handle)) {
266 // The case may happen that we have added a child_process_info as part of
267 // the iteration performed during StartUpdating() call but the notification
268 // that it has connected was not fired yet. So when the notification
269 // happens, we already know about this plugin and just ignore it.
270 return;
272 AddToTaskManager(data);
275 void ChildProcessResourceProvider::
276 BrowserChildProcessHostDisconnected(
277 const content::ChildProcessData& data) {
278 DCHECK(updating_);
280 if (data.process_type == content::PROCESS_TYPE_WORKER)
281 return;
282 ChildProcessMap::iterator iter = resources_.find(data.handle);
283 if (iter == resources_.end()) {
284 // ChildProcessData disconnection notifications are asynchronous, so we
285 // might be notified for a plugin we don't know anything about (if it was
286 // closed before the task manager was shown and destroyed after that).
287 return;
289 // Remove the resource from the Task Manager.
290 ChildProcessResource* resource = iter->second;
291 task_manager_->RemoveResource(resource);
292 // Remove it from the provider.
293 resources_.erase(iter);
294 // Remove it from our pid map.
295 PidResourceMap::iterator pid_iter =
296 pid_to_resources_.find(resource->process_id());
297 DCHECK(pid_iter != pid_to_resources_.end());
298 if (pid_iter != pid_to_resources_.end())
299 pid_to_resources_.erase(pid_iter);
301 // Finally, delete the resource.
302 delete resource;
305 void ChildProcessResourceProvider::AddToTaskManager(
306 const content::ChildProcessData& child_process_data) {
307 ChildProcessResource* resource =
308 new ChildProcessResource(
309 child_process_data.process_type,
310 child_process_data.name,
311 child_process_data.handle,
312 child_process_data.id);
313 resources_[child_process_data.handle] = resource;
314 pid_to_resources_[resource->process_id()] = resource;
315 task_manager_->AddResource(resource);
318 // The ChildProcessData::Iterator has to be used from the IO thread.
319 void ChildProcessResourceProvider::RetrieveChildProcessData() {
320 std::vector<content::ChildProcessData> child_processes;
321 for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
322 // Only add processes which are already started, since we need their handle.
323 if (iter.GetData().handle == base::kNullProcessHandle)
324 continue;
325 if (iter.GetData().process_type == content::PROCESS_TYPE_WORKER)
326 continue;
327 child_processes.push_back(iter.GetData());
329 // Now notify the UI thread that we have retrieved information about child
330 // processes.
331 BrowserThread::PostTask(
332 BrowserThread::UI, FROM_HERE,
333 base::Bind(
334 &ChildProcessResourceProvider::ChildProcessDataRetreived,
335 this, child_processes));
338 // This is called on the UI thread.
339 void ChildProcessResourceProvider::ChildProcessDataRetreived(
340 const std::vector<content::ChildProcessData>& child_processes) {
341 for (size_t i = 0; i < child_processes.size(); ++i)
342 AddToTaskManager(child_processes[i]);
344 task_manager_->model()->NotifyDataReady();
347 } // namespace task_manager