| 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 |