Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / task_manager / child_process_resource_provider.cc
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.
4
5 #include "chrome/browser/task_manager/child_process_resource_provider.h"
6
7 #include <vector>
8
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 "chrome/grit/generated_resources.h"
14 #include "components/nacl/common/nacl_process_type.h"
15 #include "content/public/browser/browser_child_process_host_iterator.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/child_process_data.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"
22
23 using content::BrowserChildProcessHostIterator;
24 using content::BrowserThread;
25 using content::WebContents;
26
27 namespace task_manager {
28
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();
36
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;
46
47   // Returns the pid of the child process.
48   int process_id() const { return pid_; }
49
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;
54
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_;
62
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_;
67
68   DISALLOW_COPY_AND_ASSIGN(ChildProcessResource);
69 };
70
71 gfx::ImageSkia* ChildProcessResource::default_icon_ = NULL;
72
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.
90   }
91 }
92
93 ChildProcessResource::~ChildProcessResource() {
94 }
95
96 // Resource methods:
97 base::string16 ChildProcessResource::GetTitle() const {
98   if (title_.empty())
99     title_ = GetLocalizedTitle();
100
101   return title_;
102 }
103
104 base::string16 ChildProcessResource::GetProfileName() const {
105   return base::string16();
106 }
107
108 gfx::ImageSkia ChildProcessResource::GetIcon() const {
109   return *default_icon_;
110 }
111
112 base::ProcessHandle ChildProcessResource::GetProcess() const {
113   return handle_;
114 }
115
116 int ChildProcessResource::GetUniqueChildProcessId() const {
117   return unique_process_id_;
118 }
119
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;
141   }
142 }
143
144 bool ChildProcessResource::SupportNetworkUsage() const {
145   return network_usage_support_;
146 }
147
148 void ChildProcessResource::SetSupportNetworkUsage() {
149   network_usage_support_ = true;
150 }
151
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;
164     }
165   }
166
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);
172
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;
196     case content::PROCESS_TYPE_UNKNOWN:
197       NOTREACHED() << "Need localized name for child process type.";
198   }
199
200   return title;
201 }
202
203 ////////////////////////////////////////////////////////////////////////////////
204 // ChildProcessResourceProvider class
205 ////////////////////////////////////////////////////////////////////////////////
206
207 ChildProcessResourceProvider::
208     ChildProcessResourceProvider(TaskManager* task_manager)
209     : task_manager_(task_manager),
210       updating_(false) {
211 }
212
213 ChildProcessResourceProvider::~ChildProcessResourceProvider() {
214 }
215
216 Resource* ChildProcessResourceProvider::GetResource(
217     int origin_pid,
218     int child_id,
219     int route_id) {
220   PidResourceMap::iterator iter = pid_to_resources_.find(origin_pid);
221   if (iter != pid_to_resources_.end())
222     return iter->second;
223   else
224     return NULL;
225 }
226
227 void ChildProcessResourceProvider::StartUpdating() {
228   DCHECK(!updating_);
229   updating_ = true;
230
231   // Get the existing child processes.
232   BrowserThread::PostTask(
233       BrowserThread::IO, FROM_HERE,
234       base::Bind(
235           &ChildProcessResourceProvider::RetrieveChildProcessData,
236           this));
237
238   BrowserChildProcessObserver::Add(this);
239 }
240
241 void ChildProcessResourceProvider::StopUpdating() {
242   DCHECK(updating_);
243   updating_ = false;
244
245   // Delete all the resources.
246   STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
247
248   resources_.clear();
249   pid_to_resources_.clear();
250
251   BrowserChildProcessObserver::Remove(this);
252 }
253
254 void ChildProcessResourceProvider::BrowserChildProcessHostConnected(
255     const content::ChildProcessData& data) {
256   DCHECK(updating_);
257
258   if (resources_.count(data.handle)) {
259     // The case may happen that we have added a child_process_info as part of
260     // the iteration performed during StartUpdating() call but the notification
261     // that it has connected was not fired yet. So when the notification
262     // happens, we already know about this plugin and just ignore it.
263     return;
264   }
265   AddToTaskManager(data);
266 }
267
268 void ChildProcessResourceProvider::
269     BrowserChildProcessHostDisconnected(
270         const content::ChildProcessData& data) {
271   DCHECK(updating_);
272
273   ChildProcessMap::iterator iter = resources_.find(data.handle);
274   if (iter == resources_.end()) {
275     // ChildProcessData disconnection notifications are asynchronous, so we
276     // might be notified for a plugin we don't know anything about (if it was
277     // closed before the task manager was shown and destroyed after that).
278     return;
279   }
280   // Remove the resource from the Task Manager.
281   ChildProcessResource* resource = iter->second;
282   task_manager_->RemoveResource(resource);
283   // Remove it from the provider.
284   resources_.erase(iter);
285   // Remove it from our pid map.
286   PidResourceMap::iterator pid_iter =
287       pid_to_resources_.find(resource->process_id());
288   DCHECK(pid_iter != pid_to_resources_.end());
289   if (pid_iter != pid_to_resources_.end())
290     pid_to_resources_.erase(pid_iter);
291
292   // Finally, delete the resource.
293   delete resource;
294 }
295
296 void ChildProcessResourceProvider::AddToTaskManager(
297     const content::ChildProcessData& child_process_data) {
298   ChildProcessResource* resource =
299       new ChildProcessResource(
300           child_process_data.process_type,
301           child_process_data.name,
302           child_process_data.handle,
303           child_process_data.id);
304   resources_[child_process_data.handle] = resource;
305   pid_to_resources_[resource->process_id()] = resource;
306   task_manager_->AddResource(resource);
307 }
308
309 // The ChildProcessData::Iterator has to be used from the IO thread.
310 void ChildProcessResourceProvider::RetrieveChildProcessData() {
311   std::vector<content::ChildProcessData> child_processes;
312   for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
313     // Only add processes which are already started, since we need their handle.
314     if (iter.GetData().handle == base::kNullProcessHandle)
315       continue;
316     child_processes.push_back(iter.GetData());
317   }
318   // Now notify the UI thread that we have retrieved information about child
319   // processes.
320   BrowserThread::PostTask(
321       BrowserThread::UI, FROM_HERE,
322       base::Bind(
323           &ChildProcessResourceProvider::ChildProcessDataRetreived,
324           this, child_processes));
325 }
326
327 // This is called on the UI thread.
328 void ChildProcessResourceProvider::ChildProcessDataRetreived(
329     const std::vector<content::ChildProcessData>& child_processes) {
330   for (size_t i = 0; i < child_processes.size(); ++i)
331     AddToTaskManager(child_processes[i]);
332
333   task_manager_->model()->NotifyDataReady();
334 }
335
336 }  // namespace task_manager