| 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 <vector> | |
| 8 | |
| 9 #include "base/i18n/rtl.h" | |
| 10 #include "base/string16.h" | |
| 11 #include "chrome/common/chrome_notification_types.h" | |
| 12 #include "chrome/common/chrome_process_type.h" | |
| 13 #include "content/public/browser/browser_child_process_host_iterator.h" | |
| 14 #include "content/public/browser/browser_thread.h" | |
| 15 #include "content/public/browser/child_process_data.h" | |
| 16 #include "content/public/browser/notification_service.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" | |
| 22 | |
| 23 using content::BrowserChildProcessHostIterator; | |
| 24 using content::BrowserThread; | |
| 25 using content::WebContents; | |
| 26 | |
| 27 class TaskManagerChildProcessResource : public TaskManager::Resource { | |
| 28 public: | |
| 29 TaskManagerChildProcessResource(int process_type, | |
| 30 const string16& name, | |
| 31 base::ProcessHandle handle, | |
| 32 int unique_process_id); | |
| 33 virtual ~TaskManagerChildProcessResource(); | |
| 34 | |
| 35 // TaskManager::Resource methods: | |
| 36 virtual string16 GetTitle() const OVERRIDE; | |
| 37 virtual string16 GetProfileName() const OVERRIDE; | |
| 38 virtual gfx::ImageSkia GetIcon() const OVERRIDE; | |
| 39 virtual base::ProcessHandle GetProcess() const OVERRIDE; | |
| 40 virtual int GetUniqueChildProcessId() const OVERRIDE; | |
| 41 virtual Type GetType() const OVERRIDE; | |
| 42 virtual bool SupportNetworkUsage() const OVERRIDE; | |
| 43 virtual void SetSupportNetworkUsage() OVERRIDE; | |
| 44 | |
| 45 // Returns the pid of the child process. | |
| 46 int process_id() const { return pid_; } | |
| 47 | |
| 48 private: | |
| 49 // Returns a localized title for the child process. For example, a plugin | |
| 50 // process would be "Plug-in: Flash" when name is "Flash". | |
| 51 string16 GetLocalizedTitle() const; | |
| 52 | |
| 53 int process_type_; | |
| 54 string16 name_; | |
| 55 base::ProcessHandle handle_; | |
| 56 int pid_; | |
| 57 int unique_process_id_; | |
| 58 mutable string16 title_; | |
| 59 bool network_usage_support_; | |
| 60 | |
| 61 // The icon painted for the child processs. | |
| 62 // TODO(jcampan): we should have plugin specific icons for well-known | |
| 63 // plugins. | |
| 64 static gfx::ImageSkia* default_icon_; | |
| 65 | |
| 66 DISALLOW_COPY_AND_ASSIGN(TaskManagerChildProcessResource); | |
| 67 }; | |
| 68 | |
| 69 gfx::ImageSkia* TaskManagerChildProcessResource::default_icon_ = NULL; | |
| 70 | |
| 71 TaskManagerChildProcessResource::TaskManagerChildProcessResource( | |
| 72 int process_type, | |
| 73 const string16& name, | |
| 74 base::ProcessHandle handle, | |
| 75 int unique_process_id) | |
| 76 : process_type_(process_type), | |
| 77 name_(name), | |
| 78 handle_(handle), | |
| 79 unique_process_id_(unique_process_id), | |
| 80 network_usage_support_(false) { | |
| 81 // We cache the process id because it's not cheap to calculate, and it won't | |
| 82 // be available when we get the plugin disconnected notification. | |
| 83 pid_ = base::GetProcId(handle); | |
| 84 if (!default_icon_) { | |
| 85 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 86 default_icon_ = rb.GetImageSkiaNamed(IDR_PLUGINS_FAVICON); | |
| 87 // TODO(jabdelmalek): use different icon for web workers. | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 TaskManagerChildProcessResource::~TaskManagerChildProcessResource() { | |
| 92 } | |
| 93 | |
| 94 // TaskManagerResource methods: | |
| 95 string16 TaskManagerChildProcessResource::GetTitle() const { | |
| 96 if (title_.empty()) | |
| 97 title_ = GetLocalizedTitle(); | |
| 98 | |
| 99 return title_; | |
| 100 } | |
| 101 | |
| 102 string16 TaskManagerChildProcessResource::GetProfileName() const { | |
| 103 return string16(); | |
| 104 } | |
| 105 | |
| 106 gfx::ImageSkia TaskManagerChildProcessResource::GetIcon() const { | |
| 107 return *default_icon_; | |
| 108 } | |
| 109 | |
| 110 base::ProcessHandle TaskManagerChildProcessResource::GetProcess() const { | |
| 111 return handle_; | |
| 112 } | |
| 113 | |
| 114 int TaskManagerChildProcessResource::GetUniqueChildProcessId() const { | |
| 115 return unique_process_id_; | |
| 116 } | |
| 117 | |
| 118 TaskManager::Resource::Type TaskManagerChildProcessResource::GetType() const { | |
| 119 // Translate types to TaskManager::ResourceType, since ChildProcessData's type | |
| 120 // is not available for all TaskManager resources. | |
| 121 switch (process_type_) { | |
| 122 case content::PROCESS_TYPE_PLUGIN: | |
| 123 case content::PROCESS_TYPE_PPAPI_PLUGIN: | |
| 124 case content::PROCESS_TYPE_PPAPI_BROKER: | |
| 125 return TaskManager::Resource::PLUGIN; | |
| 126 case content::PROCESS_TYPE_UTILITY: | |
| 127 return TaskManager::Resource::UTILITY; | |
| 128 case content::PROCESS_TYPE_ZYGOTE: | |
| 129 return TaskManager::Resource::ZYGOTE; | |
| 130 case content::PROCESS_TYPE_SANDBOX_HELPER: | |
| 131 return TaskManager::Resource::SANDBOX_HELPER; | |
| 132 case content::PROCESS_TYPE_GPU: | |
| 133 return TaskManager::Resource::GPU; | |
| 134 case PROCESS_TYPE_PROFILE_IMPORT: | |
| 135 return TaskManager::Resource::PROFILE_IMPORT; | |
| 136 case PROCESS_TYPE_NACL_LOADER: | |
| 137 case PROCESS_TYPE_NACL_BROKER: | |
| 138 return TaskManager::Resource::NACL; | |
| 139 default: | |
| 140 return TaskManager::Resource::UNKNOWN; | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 bool TaskManagerChildProcessResource::SupportNetworkUsage() const { | |
| 145 return network_usage_support_; | |
| 146 } | |
| 147 | |
| 148 void TaskManagerChildProcessResource::SetSupportNetworkUsage() { | |
| 149 network_usage_support_ = true; | |
| 150 } | |
| 151 | |
| 152 string16 TaskManagerChildProcessResource::GetLocalizedTitle() const { | |
| 153 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_PROFILE_IMPORT: | |
| 185 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX); | |
| 186 case PROCESS_TYPE_NACL_BROKER: | |
| 187 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NACL_BROKER_PREFIX); | |
| 188 case PROCESS_TYPE_NACL_LOADER: | |
| 189 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_NACL_PREFIX, title); | |
| 190 // These types don't need display names or get them from elsewhere. | |
| 191 case content::PROCESS_TYPE_BROWSER: | |
| 192 case content::PROCESS_TYPE_RENDERER: | |
| 193 case content::PROCESS_TYPE_ZYGOTE: | |
| 194 case content::PROCESS_TYPE_SANDBOX_HELPER: | |
| 195 case content::PROCESS_TYPE_MAX: | |
| 196 NOTREACHED(); | |
| 197 break; | |
| 198 | |
| 199 case content::PROCESS_TYPE_WORKER: | |
| 200 NOTREACHED() << "Workers are not handled by this provider."; | |
| 201 break; | |
| 202 case content::PROCESS_TYPE_UNKNOWN: | |
| 203 NOTREACHED() << "Need localized name for child process type."; | |
| 204 } | |
| 205 | |
| 206 return title; | |
| 207 } | |
| 208 | |
| 209 //////////////////////////////////////////////////////////////////////////////// | |
| 210 // TaskManagerChildProcessResourceProvider class | |
| 211 //////////////////////////////////////////////////////////////////////////////// | |
| 212 | |
| 213 TaskManagerChildProcessResourceProvider:: | |
| 214 TaskManagerChildProcessResourceProvider(TaskManager* task_manager) | |
| 215 : task_manager_(task_manager), | |
| 216 updating_(false) { | |
| 217 } | |
| 218 | |
| 219 TaskManagerChildProcessResourceProvider:: | |
| 220 ~TaskManagerChildProcessResourceProvider() { | |
| 221 } | |
| 222 | |
| 223 TaskManager::Resource* TaskManagerChildProcessResourceProvider::GetResource( | |
| 224 int origin_pid, | |
| 225 int render_process_host_id, | |
| 226 int routing_id) { | |
| 227 PidResourceMap::iterator iter = pid_to_resources_.find(origin_pid); | |
| 228 if (iter != pid_to_resources_.end()) | |
| 229 return iter->second; | |
| 230 else | |
| 231 return NULL; | |
| 232 } | |
| 233 | |
| 234 void TaskManagerChildProcessResourceProvider::StartUpdating() { | |
| 235 DCHECK(!updating_); | |
| 236 updating_ = true; | |
| 237 | |
| 238 // Get the existing child processes. | |
| 239 BrowserThread::PostTask( | |
| 240 BrowserThread::IO, FROM_HERE, | |
| 241 base::Bind( | |
| 242 &TaskManagerChildProcessResourceProvider::RetrieveChildProcessData, | |
| 243 this)); | |
| 244 | |
| 245 BrowserChildProcessObserver::Add(this); | |
| 246 } | |
| 247 | |
| 248 void TaskManagerChildProcessResourceProvider::StopUpdating() { | |
| 249 DCHECK(updating_); | |
| 250 updating_ = false; | |
| 251 | |
| 252 // Delete all the resources. | |
| 253 STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end()); | |
| 254 | |
| 255 resources_.clear(); | |
| 256 pid_to_resources_.clear(); | |
| 257 | |
| 258 BrowserChildProcessObserver::Remove(this); | |
| 259 } | |
| 260 | |
| 261 void TaskManagerChildProcessResourceProvider::BrowserChildProcessHostConnected( | |
| 262 const content::ChildProcessData& data) { | |
| 263 DCHECK(updating_); | |
| 264 | |
| 265 // Workers are handled by TaskManagerWorkerResourceProvider. | |
| 266 if (data.process_type == content::PROCESS_TYPE_WORKER) | |
| 267 return; | |
| 268 if (resources_.count(data.handle)) { | |
| 269 // The case may happen that we have added a child_process_info as part of | |
| 270 // the iteration performed during StartUpdating() call but the notification | |
| 271 // that it has connected was not fired yet. So when the notification | |
| 272 // happens, we already know about this plugin and just ignore it. | |
| 273 return; | |
| 274 } | |
| 275 AddToTaskManager(data); | |
| 276 } | |
| 277 | |
| 278 void TaskManagerChildProcessResourceProvider:: | |
| 279 BrowserChildProcessHostDisconnected(const content::ChildProcessData& data) { | |
| 280 DCHECK(updating_); | |
| 281 | |
| 282 if (data.process_type == content::PROCESS_TYPE_WORKER) | |
| 283 return; | |
| 284 ChildProcessMap::iterator iter = resources_.find(data.handle); | |
| 285 if (iter == resources_.end()) { | |
| 286 // ChildProcessData disconnection notifications are asynchronous, so we | |
| 287 // might be notified for a plugin we don't know anything about (if it was | |
| 288 // closed before the task manager was shown and destroyed after that). | |
| 289 return; | |
| 290 } | |
| 291 // Remove the resource from the Task Manager. | |
| 292 TaskManagerChildProcessResource* resource = iter->second; | |
| 293 task_manager_->RemoveResource(resource); | |
| 294 // Remove it from the provider. | |
| 295 resources_.erase(iter); | |
| 296 // Remove it from our pid map. | |
| 297 PidResourceMap::iterator pid_iter = | |
| 298 pid_to_resources_.find(resource->process_id()); | |
| 299 DCHECK(pid_iter != pid_to_resources_.end()); | |
| 300 if (pid_iter != pid_to_resources_.end()) | |
| 301 pid_to_resources_.erase(pid_iter); | |
| 302 | |
| 303 // Finally, delete the resource. | |
| 304 delete resource; | |
| 305 } | |
| 306 | |
| 307 void TaskManagerChildProcessResourceProvider::AddToTaskManager( | |
| 308 const content::ChildProcessData& child_process_data) { | |
| 309 TaskManagerChildProcessResource* resource = | |
| 310 new TaskManagerChildProcessResource( | |
| 311 child_process_data.process_type, | |
| 312 child_process_data.name, | |
| 313 child_process_data.handle, | |
| 314 child_process_data.id); | |
| 315 resources_[child_process_data.handle] = resource; | |
| 316 pid_to_resources_[resource->process_id()] = resource; | |
| 317 task_manager_->AddResource(resource); | |
| 318 } | |
| 319 | |
| 320 // The ChildProcessData::Iterator has to be used from the IO thread. | |
| 321 void TaskManagerChildProcessResourceProvider::RetrieveChildProcessData() { | |
| 322 std::vector<content::ChildProcessData> child_processes; | |
| 323 for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) { | |
| 324 // Only add processes which are already started, since we need their handle. | |
| 325 if (iter.GetData().handle == base::kNullProcessHandle) | |
| 326 continue; | |
| 327 if (iter.GetData().process_type == content::PROCESS_TYPE_WORKER) | |
| 328 continue; | |
| 329 child_processes.push_back(iter.GetData()); | |
| 330 } | |
| 331 // Now notify the UI thread that we have retrieved information about child | |
| 332 // processes. | |
| 333 BrowserThread::PostTask( | |
| 334 BrowserThread::UI, FROM_HERE, | |
| 335 base::Bind( | |
| 336 &TaskManagerChildProcessResourceProvider::ChildProcessDataRetreived, | |
| 337 this, child_processes)); | |
| 338 } | |
| 339 | |
| 340 // This is called on the UI thread. | |
| 341 void TaskManagerChildProcessResourceProvider::ChildProcessDataRetreived( | |
| 342 const std::vector<content::ChildProcessData>& child_processes) { | |
| 343 for (size_t i = 0; i < child_processes.size(); ++i) | |
| 344 AddToTaskManager(child_processes[i]); | |
| 345 | |
| 346 content::NotificationService::current()->Notify( | |
| 347 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY, | |
| 348 content::Source<TaskManagerChildProcessResourceProvider>(this), | |
| 349 content::NotificationService::NoDetails()); | |
| 350 } | |
| OLD | NEW |