OLD | NEW |
| (Empty) |
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/task_manager_child_process_resource_provid
er.h" | |
6 | |
7 #include "base/basictypes.h" | |
8 #include "base/i18n/rtl.h" | |
9 #include "base/string16.h" | |
10 #include "base/utf_string_conversions.h" | |
11 #include "chrome/browser/profiles/profile.h" | |
12 #include "chrome/common/chrome_notification_types.h" | |
13 #include "chrome/common/chrome_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/notification_service.h" | |
17 #include "content/public/browser/web_contents.h" | |
18 #include "grit/generated_resources.h" | |
19 #include "grit/theme_resources.h" | |
20 #include "ui/base/l10n/l10n_util.h" | |
21 #include "ui/base/resource/resource_bundle.h" | |
22 #include "ui/gfx/image/image_skia.h" | |
23 | |
24 using content::BrowserChildProcessHostIterator; | |
25 using content::BrowserThread; | |
26 using content::WebContents; | |
27 | |
28 //////////////////////////////////////////////////////////////////////////////// | |
29 // TaskManagerChildProcessResource class | |
30 //////////////////////////////////////////////////////////////////////////////// | |
31 gfx::ImageSkia* TaskManagerChildProcessResource::default_icon_ = NULL; | |
32 | |
33 TaskManagerChildProcessResource::TaskManagerChildProcessResource( | |
34 int process_type, | |
35 const string16& name, | |
36 base::ProcessHandle handle, | |
37 int unique_process_id) | |
38 : process_type_(process_type), | |
39 name_(name), | |
40 handle_(handle), | |
41 unique_process_id_(unique_process_id), | |
42 network_usage_support_(false) { | |
43 // We cache the process id because it's not cheap to calculate, and it won't | |
44 // be available when we get the plugin disconnected notification. | |
45 pid_ = base::GetProcId(handle); | |
46 if (!default_icon_) { | |
47 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
48 default_icon_ = rb.GetImageSkiaNamed(IDR_PLUGINS_FAVICON); | |
49 // TODO(jabdelmalek): use different icon for web workers. | |
50 } | |
51 } | |
52 | |
53 TaskManagerChildProcessResource::~TaskManagerChildProcessResource() { | |
54 } | |
55 | |
56 // TaskManagerResource methods: | |
57 string16 TaskManagerChildProcessResource::GetTitle() const { | |
58 if (title_.empty()) | |
59 title_ = GetLocalizedTitle(); | |
60 | |
61 return title_; | |
62 } | |
63 | |
64 string16 TaskManagerChildProcessResource::GetProfileName() const { | |
65 return string16(); | |
66 } | |
67 | |
68 gfx::ImageSkia TaskManagerChildProcessResource::GetIcon() const { | |
69 return *default_icon_; | |
70 } | |
71 | |
72 base::ProcessHandle TaskManagerChildProcessResource::GetProcess() const { | |
73 return handle_; | |
74 } | |
75 | |
76 int TaskManagerChildProcessResource::GetUniqueChildProcessId() const { | |
77 return unique_process_id_; | |
78 } | |
79 | |
80 TaskManager::Resource::Type TaskManagerChildProcessResource::GetType() const { | |
81 // Translate types to TaskManager::ResourceType, since ChildProcessData's type | |
82 // is not available for all TaskManager resources. | |
83 switch (process_type_) { | |
84 case content::PROCESS_TYPE_PLUGIN: | |
85 case content::PROCESS_TYPE_PPAPI_PLUGIN: | |
86 case content::PROCESS_TYPE_PPAPI_BROKER: | |
87 return TaskManager::Resource::PLUGIN; | |
88 case content::PROCESS_TYPE_UTILITY: | |
89 return TaskManager::Resource::UTILITY; | |
90 case content::PROCESS_TYPE_ZYGOTE: | |
91 return TaskManager::Resource::ZYGOTE; | |
92 case content::PROCESS_TYPE_SANDBOX_HELPER: | |
93 return TaskManager::Resource::SANDBOX_HELPER; | |
94 case content::PROCESS_TYPE_GPU: | |
95 return TaskManager::Resource::GPU; | |
96 case PROCESS_TYPE_PROFILE_IMPORT: | |
97 return TaskManager::Resource::PROFILE_IMPORT; | |
98 case PROCESS_TYPE_NACL_LOADER: | |
99 case PROCESS_TYPE_NACL_BROKER: | |
100 return TaskManager::Resource::NACL; | |
101 default: | |
102 return TaskManager::Resource::UNKNOWN; | |
103 } | |
104 } | |
105 | |
106 bool TaskManagerChildProcessResource::SupportNetworkUsage() const { | |
107 return network_usage_support_; | |
108 } | |
109 | |
110 void TaskManagerChildProcessResource::SetSupportNetworkUsage() { | |
111 network_usage_support_ = true; | |
112 } | |
113 | |
114 string16 TaskManagerChildProcessResource::GetLocalizedTitle() const { | |
115 string16 title = name_; | |
116 if (title.empty()) { | |
117 switch (process_type_) { | |
118 case content::PROCESS_TYPE_PLUGIN: | |
119 case content::PROCESS_TYPE_PPAPI_PLUGIN: | |
120 case content::PROCESS_TYPE_PPAPI_BROKER: | |
121 title = l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UNKNOWN_PLUGIN_NAME); | |
122 break; | |
123 default: | |
124 // Nothing to do for non-plugin processes. | |
125 break; | |
126 } | |
127 } | |
128 | |
129 // Explicitly mark name as LTR if there is no strong RTL character, | |
130 // to avoid the wrong concatenation result similar to "!Yahoo Mail: the | |
131 // best web-based Email: NIGULP", in which "NIGULP" stands for the Hebrew | |
132 // or Arabic word for "plugin". | |
133 base::i18n::AdjustStringForLocaleDirection(&title); | |
134 | |
135 switch (process_type_) { | |
136 case content::PROCESS_TYPE_UTILITY: | |
137 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX); | |
138 case content::PROCESS_TYPE_GPU: | |
139 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_GPU_PREFIX); | |
140 case content::PROCESS_TYPE_PLUGIN: | |
141 case content::PROCESS_TYPE_PPAPI_PLUGIN: | |
142 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PLUGIN_PREFIX, title); | |
143 case content::PROCESS_TYPE_PPAPI_BROKER: | |
144 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PLUGIN_BROKER_PREFIX, | |
145 title); | |
146 case PROCESS_TYPE_PROFILE_IMPORT: | |
147 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX); | |
148 case PROCESS_TYPE_NACL_BROKER: | |
149 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NACL_BROKER_PREFIX); | |
150 case PROCESS_TYPE_NACL_LOADER: | |
151 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_NACL_PREFIX, title); | |
152 // These types don't need display names or get them from elsewhere. | |
153 case content::PROCESS_TYPE_BROWSER: | |
154 case content::PROCESS_TYPE_RENDERER: | |
155 case content::PROCESS_TYPE_ZYGOTE: | |
156 case content::PROCESS_TYPE_SANDBOX_HELPER: | |
157 case content::PROCESS_TYPE_MAX: | |
158 NOTREACHED(); | |
159 break; | |
160 | |
161 case content::PROCESS_TYPE_WORKER: | |
162 NOTREACHED() << "Workers are not handled by this provider."; | |
163 break; | |
164 case content::PROCESS_TYPE_UNKNOWN: | |
165 NOTREACHED() << "Need localized name for child process type."; | |
166 } | |
167 | |
168 return title; | |
169 } | |
170 | |
171 //////////////////////////////////////////////////////////////////////////////// | |
172 // TaskManagerChildProcessResourceProvider class | |
173 //////////////////////////////////////////////////////////////////////////////// | |
174 | |
175 TaskManagerChildProcessResourceProvider:: | |
176 TaskManagerChildProcessResourceProvider(TaskManager* task_manager) | |
177 : task_manager_(task_manager), | |
178 updating_(false) { | |
179 } | |
180 | |
181 TaskManagerChildProcessResourceProvider:: | |
182 ~TaskManagerChildProcessResourceProvider() { | |
183 } | |
184 | |
185 TaskManager::Resource* TaskManagerChildProcessResourceProvider::GetResource( | |
186 int origin_pid, | |
187 int render_process_host_id, | |
188 int routing_id) { | |
189 PidResourceMap::iterator iter = pid_to_resources_.find(origin_pid); | |
190 if (iter != pid_to_resources_.end()) | |
191 return iter->second; | |
192 else | |
193 return NULL; | |
194 } | |
195 | |
196 void TaskManagerChildProcessResourceProvider::StartUpdating() { | |
197 DCHECK(!updating_); | |
198 updating_ = true; | |
199 | |
200 // Get the existing child processes. | |
201 BrowserThread::PostTask( | |
202 BrowserThread::IO, FROM_HERE, | |
203 base::Bind( | |
204 &TaskManagerChildProcessResourceProvider::RetrieveChildProcessData, | |
205 this)); | |
206 | |
207 BrowserChildProcessObserver::Add(this); | |
208 } | |
209 | |
210 void TaskManagerChildProcessResourceProvider::StopUpdating() { | |
211 DCHECK(updating_); | |
212 updating_ = false; | |
213 | |
214 // Delete all the resources. | |
215 STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end()); | |
216 | |
217 resources_.clear(); | |
218 pid_to_resources_.clear(); | |
219 | |
220 BrowserChildProcessObserver::Remove(this); | |
221 } | |
222 | |
223 void TaskManagerChildProcessResourceProvider::BrowserChildProcessHostConnected( | |
224 const content::ChildProcessData& data) { | |
225 DCHECK(updating_); | |
226 | |
227 // Workers are handled by TaskManagerWorkerResourceProvider. | |
228 if (data.process_type == content::PROCESS_TYPE_WORKER) | |
229 return; | |
230 if (resources_.count(data.handle)) { | |
231 // The case may happen that we have added a child_process_info as part of | |
232 // the iteration performed during StartUpdating() call but the notification | |
233 // that it has connected was not fired yet. So when the notification | |
234 // happens, we already know about this plugin and just ignore it. | |
235 return; | |
236 } | |
237 AddToTaskManager(data); | |
238 } | |
239 | |
240 void TaskManagerChildProcessResourceProvider:: | |
241 BrowserChildProcessHostDisconnected(const content::ChildProcessData& data) { | |
242 DCHECK(updating_); | |
243 | |
244 if (data.process_type == content::PROCESS_TYPE_WORKER) | |
245 return; | |
246 ChildProcessMap::iterator iter = resources_.find(data.handle); | |
247 if (iter == resources_.end()) { | |
248 // ChildProcessData disconnection notifications are asynchronous, so we | |
249 // might be notified for a plugin we don't know anything about (if it was | |
250 // closed before the task manager was shown and destroyed after that). | |
251 return; | |
252 } | |
253 // Remove the resource from the Task Manager. | |
254 TaskManagerChildProcessResource* resource = iter->second; | |
255 task_manager_->RemoveResource(resource); | |
256 // Remove it from the provider. | |
257 resources_.erase(iter); | |
258 // Remove it from our pid map. | |
259 PidResourceMap::iterator pid_iter = | |
260 pid_to_resources_.find(resource->process_id()); | |
261 DCHECK(pid_iter != pid_to_resources_.end()); | |
262 if (pid_iter != pid_to_resources_.end()) | |
263 pid_to_resources_.erase(pid_iter); | |
264 | |
265 // Finally, delete the resource. | |
266 delete resource; | |
267 } | |
268 | |
269 void TaskManagerChildProcessResourceProvider::AddToTaskManager( | |
270 const content::ChildProcessData& child_process_data) { | |
271 TaskManagerChildProcessResource* resource = | |
272 new TaskManagerChildProcessResource( | |
273 child_process_data.process_type, | |
274 child_process_data.name, | |
275 child_process_data.handle, | |
276 child_process_data.id); | |
277 resources_[child_process_data.handle] = resource; | |
278 pid_to_resources_[resource->process_id()] = resource; | |
279 task_manager_->AddResource(resource); | |
280 } | |
281 | |
282 // The ChildProcessData::Iterator has to be used from the IO thread. | |
283 void TaskManagerChildProcessResourceProvider::RetrieveChildProcessData() { | |
284 std::vector<content::ChildProcessData> child_processes; | |
285 for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) { | |
286 // Only add processes which are already started, since we need their handle. | |
287 if (iter.GetData().handle == base::kNullProcessHandle) | |
288 continue; | |
289 if (iter.GetData().process_type == content::PROCESS_TYPE_WORKER) | |
290 continue; | |
291 child_processes.push_back(iter.GetData()); | |
292 } | |
293 // Now notify the UI thread that we have retrieved information about child | |
294 // processes. | |
295 BrowserThread::PostTask( | |
296 BrowserThread::UI, FROM_HERE, | |
297 base::Bind( | |
298 &TaskManagerChildProcessResourceProvider::ChildProcessDataRetreived, | |
299 this, child_processes)); | |
300 } | |
301 | |
302 // This is called on the UI thread. | |
303 void TaskManagerChildProcessResourceProvider::ChildProcessDataRetreived( | |
304 const std::vector<content::ChildProcessData>& child_processes) { | |
305 for (size_t i = 0; i < child_processes.size(); ++i) | |
306 AddToTaskManager(child_processes[i]); | |
307 | |
308 content::NotificationService::current()->Notify( | |
309 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY, | |
310 content::Source<TaskManagerChildProcessResourceProvider>(this), | |
311 content::NotificationService::NoDetails()); | |
312 } | |
OLD | NEW |