Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/hung_plugin_tab_helper.h" | 5 #include "chrome/browser/ui/hung_plugin_tab_helper.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/process/process.h" | 10 #include "base/process/process.h" |
| 11 #include "base/rand_util.h" | 11 #include "base/rand_util.h" |
| 12 #include "build/build_config.h" | 12 #include "build/build_config.h" |
| 13 #include "chrome/browser/chrome_notification_types.h" | |
| 14 #include "chrome/browser/infobars/infobar_service.h" | 13 #include "chrome/browser/infobars/infobar_service.h" |
| 15 #include "chrome/common/chrome_version_info.h" | 14 #include "chrome/common/chrome_version_info.h" |
| 16 #include "components/infobars/core/confirm_infobar_delegate.h" | 15 #include "components/infobars/core/confirm_infobar_delegate.h" |
| 17 #include "components/infobars/core/infobar.h" | 16 #include "components/infobars/core/infobar.h" |
| 18 #include "content/public/browser/browser_child_process_host_iterator.h" | 17 #include "content/public/browser/browser_child_process_host_iterator.h" |
| 19 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
| 20 #include "content/public/browser/child_process_data.h" | 19 #include "content/public/browser/child_process_data.h" |
| 21 #include "content/public/browser/notification_details.h" | |
| 22 #include "content/public/browser/notification_service.h" | |
| 23 #include "content/public/browser/plugin_service.h" | 20 #include "content/public/browser/plugin_service.h" |
| 24 #include "content/public/browser/render_process_host.h" | 21 #include "content/public/browser/render_process_host.h" |
| 25 #include "content/public/common/process_type.h" | 22 #include "content/public/common/process_type.h" |
| 26 #include "content/public/common/result_codes.h" | 23 #include "content/public/common/result_codes.h" |
| 27 #include "grit/chromium_strings.h" | 24 #include "grit/chromium_strings.h" |
| 28 #include "grit/generated_resources.h" | 25 #include "grit/generated_resources.h" |
| 29 #include "grit/locale_settings.h" | 26 #include "grit/locale_settings.h" |
| 30 #include "grit/theme_resources.h" | 27 #include "grit/theme_resources.h" |
| 31 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
| 32 | 29 |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 254 | 251 |
| 255 HungPluginTabHelper::PluginState::~PluginState() { | 252 HungPluginTabHelper::PluginState::~PluginState() { |
| 256 } | 253 } |
| 257 | 254 |
| 258 | 255 |
| 259 // HungPluginTabHelper -------------------------------------------------------- | 256 // HungPluginTabHelper -------------------------------------------------------- |
| 260 | 257 |
| 261 DEFINE_WEB_CONTENTS_USER_DATA_KEY(HungPluginTabHelper); | 258 DEFINE_WEB_CONTENTS_USER_DATA_KEY(HungPluginTabHelper); |
| 262 | 259 |
| 263 HungPluginTabHelper::HungPluginTabHelper(content::WebContents* contents) | 260 HungPluginTabHelper::HungPluginTabHelper(content::WebContents* contents) |
| 264 : content::WebContentsObserver(contents) { | 261 : content::WebContentsObserver(contents), |
| 265 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, | 262 observer_installed_(false) { |
| 266 content::NotificationService::AllSources()); | |
| 267 } | 263 } |
| 268 | 264 |
| 269 HungPluginTabHelper::~HungPluginTabHelper() { | 265 HungPluginTabHelper::~HungPluginTabHelper() { |
| 270 } | 266 } |
| 271 | 267 |
| 272 void HungPluginTabHelper::PluginCrashed(const base::FilePath& plugin_path, | 268 void HungPluginTabHelper::PluginCrashed(const base::FilePath& plugin_path, |
| 273 base::ProcessId plugin_pid) { | 269 base::ProcessId plugin_pid) { |
| 274 // TODO(brettw) ideally this would take the child process ID. When we do this | 270 // TODO(brettw) ideally this would take the child process ID. When we do this |
| 275 // for NaCl plugins, we'll want to know exactly which process it was since | 271 // for NaCl plugins, we'll want to know exactly which process it was since |
| 276 // the path won't be useful. | 272 // the path won't be useful. |
| 277 InfoBarService* infobar_service = | 273 InfoBarService* infobar_service = |
| 278 InfoBarService::FromWebContents(web_contents()); | 274 InfoBarService::FromWebContents(web_contents()); |
| 279 if (!infobar_service) | 275 if (!infobar_service) |
| 280 return; | 276 return; |
| 281 | 277 |
| 278 if (!observer_installed_) { | |
| 279 observer_installed_ = true; | |
| 280 infobar_service->AddObserver(this); | |
|
Peter Kasting
2014/05/30 18:05:48
Why do we want to add an observer here? We don't
| |
| 281 } | |
| 282 | |
| 282 // For now, just do a brute-force search to see if we have this plugin. Since | 283 // For now, just do a brute-force search to see if we have this plugin. Since |
| 283 // we'll normally have 0 or 1, this is fast. | 284 // we'll normally have 0 or 1, this is fast. |
| 284 for (PluginStateMap::iterator i = hung_plugins_.begin(); | 285 for (PluginStateMap::iterator i = hung_plugins_.begin(); |
| 285 i != hung_plugins_.end(); ++i) { | 286 i != hung_plugins_.end(); ++i) { |
| 286 if (i->second->path == plugin_path) { | 287 if (i->second->path == plugin_path) { |
| 287 if (i->second->infobar) | 288 if (i->second->infobar) |
| 288 infobar_service->RemoveInfoBar(i->second->infobar); | 289 infobar_service->RemoveInfoBar(i->second->infobar); |
| 289 hung_plugins_.erase(i); | 290 hung_plugins_.erase(i); |
| 290 break; | 291 break; |
| 291 } | 292 } |
| 292 } | 293 } |
| 293 } | 294 } |
| 294 | 295 |
| 295 void HungPluginTabHelper::PluginHungStatusChanged( | 296 void HungPluginTabHelper::PluginHungStatusChanged( |
| 296 int plugin_child_id, | 297 int plugin_child_id, |
| 297 const base::FilePath& plugin_path, | 298 const base::FilePath& plugin_path, |
| 298 bool is_hung) { | 299 bool is_hung) { |
| 299 InfoBarService* infobar_service = | 300 InfoBarService* infobar_service = |
| 300 InfoBarService::FromWebContents(web_contents()); | 301 InfoBarService::FromWebContents(web_contents()); |
| 301 if (!infobar_service) | 302 if (!infobar_service) |
| 302 return; | 303 return; |
| 303 | 304 |
| 305 if (!observer_installed_) { | |
| 306 observer_installed_ = true; | |
| 307 infobar_service->AddObserver(this); | |
|
Peter Kasting
2014/05/30 18:05:48
Wouldn't we want this in ShowBar() instead of here
| |
| 308 } | |
| 309 | |
| 304 PluginStateMap::iterator found = hung_plugins_.find(plugin_child_id); | 310 PluginStateMap::iterator found = hung_plugins_.find(plugin_child_id); |
| 305 if (found != hung_plugins_.end()) { | 311 if (found != hung_plugins_.end()) { |
| 306 if (!is_hung) { | 312 if (!is_hung) { |
| 307 // Hung plugin became un-hung, close the infobar and delete our info. | 313 // Hung plugin became un-hung, close the infobar and delete our info. |
| 308 if (found->second->infobar) | 314 if (found->second->infobar) |
| 309 infobar_service->RemoveInfoBar(found->second->infobar); | 315 infobar_service->RemoveInfoBar(found->second->infobar); |
| 310 hung_plugins_.erase(found); | 316 hung_plugins_.erase(found); |
| 311 } | 317 } |
| 312 return; | 318 return; |
| 313 } | 319 } |
| 314 | 320 |
| 315 base::string16 plugin_name = | 321 base::string16 plugin_name = |
| 316 content::PluginService::GetInstance()->GetPluginDisplayNameByPath( | 322 content::PluginService::GetInstance()->GetPluginDisplayNameByPath( |
| 317 plugin_path); | 323 plugin_path); |
| 318 | 324 |
| 319 linked_ptr<PluginState> state(new PluginState(plugin_path, plugin_name)); | 325 linked_ptr<PluginState> state(new PluginState(plugin_path, plugin_name)); |
| 320 hung_plugins_[plugin_child_id] = state; | 326 hung_plugins_[plugin_child_id] = state; |
| 321 ShowBar(plugin_child_id, state.get()); | 327 ShowBar(plugin_child_id, state.get()); |
| 322 } | 328 } |
| 323 | 329 |
| 324 void HungPluginTabHelper::Observe( | |
| 325 int type, | |
| 326 const content::NotificationSource& source, | |
| 327 const content::NotificationDetails& details) { | |
| 328 DCHECK_EQ(chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, type); | |
| 329 infobars::InfoBar* infobar = | |
| 330 content::Details<infobars::InfoBar::RemovedDetails>(details)->first; | |
| 331 for (PluginStateMap::iterator i = hung_plugins_.begin(); | |
| 332 i != hung_plugins_.end(); ++i) { | |
| 333 PluginState* state = i->second.get(); | |
| 334 if (state->infobar == infobar) { | |
| 335 state->infobar = NULL; | |
| 336 | |
| 337 // Schedule the timer to re-show the infobar if the plugin continues to be | |
| 338 // hung. | |
| 339 state->timer.Start(FROM_HERE, state->next_reshow_delay, | |
| 340 base::Bind(&HungPluginTabHelper::OnReshowTimer, | |
| 341 base::Unretained(this), | |
| 342 i->first)); | |
| 343 | |
| 344 // Next time we do this, delay it twice as long to avoid being annoying. | |
| 345 state->next_reshow_delay *= 2; | |
| 346 return; | |
| 347 } | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 void HungPluginTabHelper::KillPlugin(int child_id) { | 330 void HungPluginTabHelper::KillPlugin(int child_id) { |
| 352 #if defined(OS_WIN) | 331 #if defined(OS_WIN) |
| 353 // Dump renderers that are sending or receiving pepper messages, in order to | 332 // Dump renderers that are sending or receiving pepper messages, in order to |
| 354 // diagnose inter-process deadlocks. | 333 // diagnose inter-process deadlocks. |
| 355 // Only do that on the Canary channel, for 20% of pepper plugin hangs. | 334 // Only do that on the Canary channel, for 20% of pepper plugin hangs. |
| 356 if (base::RandInt(0, 100) < 20) { | 335 if (base::RandInt(0, 100) < 20) { |
| 357 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); | 336 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); |
| 358 if (channel == chrome::VersionInfo::CHANNEL_CANARY) { | 337 if (channel == chrome::VersionInfo::CHANNEL_CANARY) { |
| 359 scoped_ptr<OwnedHandleVector> renderer_handles(new OwnedHandleVector); | 338 scoped_ptr<OwnedHandleVector> renderer_handles(new OwnedHandleVector); |
| 360 HANDLE current_process = ::GetCurrentProcess(); | 339 HANDLE current_process = ::GetCurrentProcess(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 415 } | 394 } |
| 416 | 395 |
| 417 void HungPluginTabHelper::CloseBar(PluginState* state) { | 396 void HungPluginTabHelper::CloseBar(PluginState* state) { |
| 418 InfoBarService* infobar_service = | 397 InfoBarService* infobar_service = |
| 419 InfoBarService::FromWebContents(web_contents()); | 398 InfoBarService::FromWebContents(web_contents()); |
| 420 if (infobar_service && state->infobar) { | 399 if (infobar_service && state->infobar) { |
| 421 infobar_service->RemoveInfoBar(state->infobar); | 400 infobar_service->RemoveInfoBar(state->infobar); |
| 422 state->infobar = NULL; | 401 state->infobar = NULL; |
| 423 } | 402 } |
| 424 } | 403 } |
| 404 | |
| 405 void HungPluginTabHelper::OnInfoBarRemoved(infobars::InfoBar* infobar, | |
| 406 bool animate) { | |
| 407 for (PluginStateMap::iterator i = hung_plugins_.begin(); | |
| 408 i != hung_plugins_.end(); ++i) { | |
| 409 PluginState* state = i->second.get(); | |
| 410 if (state->infobar == infobar) { | |
| 411 state->infobar = NULL; | |
| 412 | |
| 413 // Schedule the timer to re-show the infobar if the plugin continues to be | |
| 414 // hung. | |
| 415 state->timer.Start(FROM_HERE, | |
| 416 state->next_reshow_delay, | |
| 417 base::Bind(&HungPluginTabHelper::OnReshowTimer, | |
| 418 base::Unretained(this), | |
| 419 i->first)); | |
| 420 | |
| 421 // Next time we do this, delay it twice as long to avoid being annoying. | |
| 422 state->next_reshow_delay *= 2; | |
| 423 return; | |
| 424 } | |
| 425 } | |
| 426 } | |
| 427 | |
| 428 void HungPluginTabHelper::OnManagerShuttingDown( | |
| 429 infobars::InfoBarManager* manager) { | |
| 430 InfoBarService* infobar_service = | |
| 431 InfoBarService::FromWebContents(web_contents()); | |
| 432 if (!infobar_service) | |
| 433 return; | |
| 434 | |
| 435 if (observer_installed_) | |
| 436 infobar_service->RemoveObserver(this); | |
| 437 } | |
| OLD | NEW |