| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 "extensions/browser/process_manager.h" | 5 #include "extensions/browser/process_manager.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 #include "extensions/browser/notification_types.h" | 34 #include "extensions/browser/notification_types.h" |
| 35 #include "extensions/browser/process_manager_delegate.h" | 35 #include "extensions/browser/process_manager_delegate.h" |
| 36 #include "extensions/browser/process_manager_observer.h" | 36 #include "extensions/browser/process_manager_observer.h" |
| 37 #include "extensions/browser/view_type_utils.h" | 37 #include "extensions/browser/view_type_utils.h" |
| 38 #include "extensions/common/constants.h" | 38 #include "extensions/common/constants.h" |
| 39 #include "extensions/common/extension.h" | 39 #include "extensions/common/extension.h" |
| 40 #include "extensions/common/extension_messages.h" | 40 #include "extensions/common/extension_messages.h" |
| 41 #include "extensions/common/manifest_handlers/background_info.h" | 41 #include "extensions/common/manifest_handlers/background_info.h" |
| 42 #include "extensions/common/manifest_handlers/incognito_info.h" | 42 #include "extensions/common/manifest_handlers/incognito_info.h" |
| 43 #include "extensions/common/one_shot_event.h" | 43 #include "extensions/common/one_shot_event.h" |
| 44 #include "extensions/common/switches.h" | |
| 45 | 44 |
| 46 using content::BrowserContext; | 45 using content::BrowserContext; |
| 47 using content::RenderViewHost; | 46 using content::RenderViewHost; |
| 48 using content::SiteInstance; | 47 using content::SiteInstance; |
| 49 using content::WebContents; | 48 using content::WebContents; |
| 50 | 49 |
| 51 namespace extensions { | 50 namespace extensions { |
| 52 class RenderViewHostDestructionObserver; | 51 class RenderViewHostDestructionObserver; |
| 53 } | 52 } |
| 54 DEFINE_WEB_CONTENTS_USER_DATA_KEY( | 53 DEFINE_WEB_CONTENTS_USER_DATA_KEY( |
| 55 extensions::RenderViewHostDestructionObserver); | 54 extensions::RenderViewHostDestructionObserver); |
| 56 | 55 |
| 57 namespace extensions { | 56 namespace extensions { |
| 58 | 57 |
| 59 namespace { | 58 namespace { |
| 60 | 59 |
| 60 // The time to delay between an extension becoming idle and |
| 61 // sending a ShouldSuspend message. |
| 62 // Note: Must be sufficiently larger (e.g. 2x) than |
| 63 // kKeepaliveThrottleIntervalInSeconds in ppapi/proxy/plugin_globals. |
| 64 unsigned g_event_page_idle_time_msec = 10000; |
| 65 |
| 66 // The time to delay between sending a ShouldSuspend message and |
| 67 // sending a Suspend message. |
| 68 unsigned g_event_page_suspending_time_msec = 5000; |
| 69 |
| 61 std::string GetExtensionID(RenderViewHost* render_view_host) { | 70 std::string GetExtensionID(RenderViewHost* render_view_host) { |
| 62 // This works for both apps and extensions because the site has been | 71 // This works for both apps and extensions because the site has been |
| 63 // normalized to the extension URL for hosted apps. | 72 // normalized to the extension URL for hosted apps. |
| 64 content::SiteInstance* site_instance = render_view_host->GetSiteInstance(); | 73 content::SiteInstance* site_instance = render_view_host->GetSiteInstance(); |
| 65 if (!site_instance) | 74 if (!site_instance) |
| 66 return std::string(); | 75 return std::string(); |
| 67 | 76 |
| 68 const GURL& site_url = site_instance->GetSiteURL(); | 77 const GURL& site_url = site_instance->GetSiteURL(); |
| 69 | 78 |
| 70 if (!site_url.SchemeIs(kExtensionScheme) && | 79 if (!site_url.SchemeIs(kExtensionScheme) && |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, | 269 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, |
| 261 content::Source<BrowserContext>(context)); | 270 content::Source<BrowserContext>(context)); |
| 262 registrar_.Add(this, | 271 registrar_.Add(this, |
| 263 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, | 272 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
| 264 content::Source<BrowserContext>(context)); | 273 content::Source<BrowserContext>(context)); |
| 265 registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, | 274 registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, |
| 266 content::NotificationService::AllSources()); | 275 content::NotificationService::AllSources()); |
| 267 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED, | 276 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED, |
| 268 content::NotificationService::AllSources()); | 277 content::NotificationService::AllSources()); |
| 269 | 278 |
| 270 // Note: event_page_idle_time_ must be sufficiently larger (e.g. 2x) than | |
| 271 // kKeepaliveThrottleIntervalInSeconds in ppapi/proxy/plugin_globals. | |
| 272 event_page_idle_time_ = base::TimeDelta::FromSeconds(10); | |
| 273 unsigned idle_time_msec = 0; | |
| 274 if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 275 extensions::switches::kEventPageIdleTime), &idle_time_msec)) { | |
| 276 CHECK_GT(idle_time_msec, 0u); // OnKeepaliveImpulseCheck requires non zero. | |
| 277 event_page_idle_time_ = base::TimeDelta::FromMilliseconds(idle_time_msec); | |
| 278 } | |
| 279 event_page_suspending_time_ = base::TimeDelta::FromSeconds(5); | |
| 280 unsigned suspending_time_msec = 0; | |
| 281 if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 282 extensions::switches::kEventPageSuspendingTime), | |
| 283 &suspending_time_msec)) { | |
| 284 event_page_suspending_time_ = | |
| 285 base::TimeDelta::FromMilliseconds(suspending_time_msec); | |
| 286 } | |
| 287 | |
| 288 content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_); | 279 content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_); |
| 289 | 280 |
| 290 OnKeepaliveImpulseCheck(); | 281 OnKeepaliveImpulseCheck(); |
| 291 } | 282 } |
| 292 | 283 |
| 293 ProcessManager::~ProcessManager() { | 284 ProcessManager::~ProcessManager() { |
| 294 CloseBackgroundHosts(); | 285 CloseBackgroundHosts(); |
| 295 DCHECK(background_hosts_.empty()); | 286 DCHECK(background_hosts_.empty()); |
| 296 content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_); | 287 content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_); |
| 297 } | 288 } |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 // before initiating another close sequence. | 449 // before initiating another close sequence. |
| 459 if (--count == 0 && !background_page_data_[extension_id].is_closing) { | 450 if (--count == 0 && !background_page_data_[extension_id].is_closing) { |
| 460 background_page_data_[extension_id].close_sequence_id = | 451 background_page_data_[extension_id].close_sequence_id = |
| 461 ++last_background_close_sequence_id_; | 452 ++last_background_close_sequence_id_; |
| 462 base::MessageLoop::current()->PostDelayedTask( | 453 base::MessageLoop::current()->PostDelayedTask( |
| 463 FROM_HERE, | 454 FROM_HERE, |
| 464 base::Bind(&ProcessManager::OnLazyBackgroundPageIdle, | 455 base::Bind(&ProcessManager::OnLazyBackgroundPageIdle, |
| 465 weak_ptr_factory_.GetWeakPtr(), | 456 weak_ptr_factory_.GetWeakPtr(), |
| 466 extension_id, | 457 extension_id, |
| 467 last_background_close_sequence_id_), | 458 last_background_close_sequence_id_), |
| 468 event_page_idle_time_); | 459 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec)); |
| 469 } | 460 } |
| 470 } | 461 } |
| 471 | 462 |
| 472 void ProcessManager::IncrementLazyKeepaliveCountForView( | 463 void ProcessManager::IncrementLazyKeepaliveCountForView( |
| 473 RenderViewHost* render_view_host) { | 464 RenderViewHost* render_view_host) { |
| 474 WebContents* web_contents = | 465 WebContents* web_contents = |
| 475 WebContents::FromRenderViewHost(render_view_host); | 466 WebContents::FromRenderViewHost(render_view_host); |
| 476 ViewType view_type = GetViewType(web_contents); | 467 ViewType view_type = GetViewType(web_contents); |
| 477 if (view_type != VIEW_TYPE_INVALID && | 468 if (view_type != VIEW_TYPE_INVALID && |
| 478 view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { | 469 view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 return; | 518 return; |
| 528 | 519 |
| 529 ProcessManager* pm = ExtensionSystem::Get(browser_context)->process_manager(); | 520 ProcessManager* pm = ExtensionSystem::Get(browser_context)->process_manager(); |
| 530 if (!pm) | 521 if (!pm) |
| 531 return; | 522 return; |
| 532 | 523 |
| 533 pm->KeepaliveImpulse(extension); | 524 pm->KeepaliveImpulse(extension); |
| 534 } | 525 } |
| 535 | 526 |
| 536 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse | 527 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse |
| 537 // have been made for at least event_page_idle_time_. In the best case an | 528 // have been made for at least g_event_page_idle_time_msec. In the best case an |
| 538 // impulse was made just before being cleared, and the decrement will occur | 529 // impulse was made just before being cleared, and the decrement will occur |
| 539 // event_page_idle_time_ later, causing a 2 * event_page_idle_time_ total time | 530 // g_event_page_idle_time_msec later, causing a 2 * g_event_page_idle_time_msec |
| 540 // for extension to be shut down based on impulses. Worst case is an impulse | 531 // total time for extension to be shut down based on impulses. Worst case is |
| 541 // just after a clear, adding one check cycle and resulting in 3x total time. | 532 // an impulse just after a clear, adding one check cycle and resulting in 3x |
| 533 // total time. |
| 542 void ProcessManager::OnKeepaliveImpulseCheck() { | 534 void ProcessManager::OnKeepaliveImpulseCheck() { |
| 543 for (BackgroundPageDataMap::iterator i = background_page_data_.begin(); | 535 for (BackgroundPageDataMap::iterator i = background_page_data_.begin(); |
| 544 i != background_page_data_.end(); | 536 i != background_page_data_.end(); |
| 545 ++i) { | 537 ++i) { |
| 546 if (i->second.previous_keepalive_impulse && !i->second.keepalive_impulse) { | 538 if (i->second.previous_keepalive_impulse && !i->second.keepalive_impulse) { |
| 547 DecrementLazyKeepaliveCount(i->first); | 539 DecrementLazyKeepaliveCount(i->first); |
| 548 if (!keepalive_impulse_decrement_callback_for_testing_.is_null()) { | 540 if (!keepalive_impulse_decrement_callback_for_testing_.is_null()) { |
| 549 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly = | 541 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly = |
| 550 keepalive_impulse_decrement_callback_for_testing_; | 542 keepalive_impulse_decrement_callback_for_testing_; |
| 551 callback_may_clear_callbacks_reentrantly.Run(i->first); | 543 callback_may_clear_callbacks_reentrantly.Run(i->first); |
| 552 } | 544 } |
| 553 } | 545 } |
| 554 | 546 |
| 555 i->second.previous_keepalive_impulse = i->second.keepalive_impulse; | 547 i->second.previous_keepalive_impulse = i->second.keepalive_impulse; |
| 556 i->second.keepalive_impulse = false; | 548 i->second.keepalive_impulse = false; |
| 557 } | 549 } |
| 558 | 550 |
| 559 // OnKeepaliveImpulseCheck() is always called in constructor, but in unit | 551 // OnKeepaliveImpulseCheck() is always called in constructor, but in unit |
| 560 // tests there will be no message loop. In that event don't schedule tasks. | 552 // tests there will be no message loop. In that event don't schedule tasks. |
| 561 if (base::MessageLoop::current()) { | 553 if (base::MessageLoop::current()) { |
| 562 base::MessageLoop::current()->PostDelayedTask( | 554 base::MessageLoop::current()->PostDelayedTask( |
| 563 FROM_HERE, | 555 FROM_HERE, |
| 564 base::Bind(&ProcessManager::OnKeepaliveImpulseCheck, | 556 base::Bind(&ProcessManager::OnKeepaliveImpulseCheck, |
| 565 weak_ptr_factory_.GetWeakPtr()), | 557 weak_ptr_factory_.GetWeakPtr()), |
| 566 event_page_idle_time_); | 558 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec)); |
| 567 } | 559 } |
| 568 } | 560 } |
| 569 | 561 |
| 570 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id, | 562 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id, |
| 571 uint64 sequence_id) { | 563 uint64 sequence_id) { |
| 572 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); | 564 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
| 573 if (host && !background_page_data_[extension_id].is_closing && | 565 if (host && !background_page_data_[extension_id].is_closing && |
| 574 sequence_id == background_page_data_[extension_id].close_sequence_id) { | 566 sequence_id == background_page_data_[extension_id].close_sequence_id) { |
| 575 // Tell the renderer we are about to close. This is a simple ping that the | 567 // Tell the renderer we are about to close. This is a simple ping that the |
| 576 // renderer will respond to. The purpose is to control sequencing: if the | 568 // renderer will respond to. The purpose is to control sequencing: if the |
| (...skipping 24 matching lines...) Expand all Loading... |
| 601 host->render_view_host()->Send(new ExtensionMsg_Suspend(extension_id)); | 593 host->render_view_host()->Send(new ExtensionMsg_Suspend(extension_id)); |
| 602 } | 594 } |
| 603 } | 595 } |
| 604 | 596 |
| 605 void ProcessManager::OnSuspendAck(const std::string& extension_id) { | 597 void ProcessManager::OnSuspendAck(const std::string& extension_id) { |
| 606 background_page_data_[extension_id].is_closing = true; | 598 background_page_data_[extension_id].is_closing = true; |
| 607 uint64 sequence_id = background_page_data_[extension_id].close_sequence_id; | 599 uint64 sequence_id = background_page_data_[extension_id].close_sequence_id; |
| 608 base::MessageLoop::current()->PostDelayedTask( | 600 base::MessageLoop::current()->PostDelayedTask( |
| 609 FROM_HERE, | 601 FROM_HERE, |
| 610 base::Bind(&ProcessManager::CloseLazyBackgroundPageNow, | 602 base::Bind(&ProcessManager::CloseLazyBackgroundPageNow, |
| 611 weak_ptr_factory_.GetWeakPtr(), extension_id, sequence_id), | 603 weak_ptr_factory_.GetWeakPtr(), |
| 612 event_page_suspending_time_); | 604 extension_id, |
| 605 sequence_id), |
| 606 base::TimeDelta::FromMilliseconds(g_event_page_suspending_time_msec)); |
| 613 } | 607 } |
| 614 | 608 |
| 615 void ProcessManager::CloseLazyBackgroundPageNow(const std::string& extension_id, | 609 void ProcessManager::CloseLazyBackgroundPageNow(const std::string& extension_id, |
| 616 uint64 sequence_id) { | 610 uint64 sequence_id) { |
| 617 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); | 611 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
| 618 if (host && | 612 if (host && |
| 619 sequence_id == background_page_data_[extension_id].close_sequence_id) { | 613 sequence_id == background_page_data_[extension_id].close_sequence_id) { |
| 620 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); | 614 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
| 621 if (host) | 615 if (host) |
| 622 CloseBackgroundHost(host); | 616 CloseBackgroundHost(host); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 670 void ProcessManager::SetKeepaliveImpulseCallbackForTesting( | 664 void ProcessManager::SetKeepaliveImpulseCallbackForTesting( |
| 671 const ImpulseCallbackForTesting& callback) { | 665 const ImpulseCallbackForTesting& callback) { |
| 672 keepalive_impulse_callback_for_testing_ = callback; | 666 keepalive_impulse_callback_for_testing_ = callback; |
| 673 } | 667 } |
| 674 | 668 |
| 675 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting( | 669 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting( |
| 676 const ImpulseCallbackForTesting& callback) { | 670 const ImpulseCallbackForTesting& callback) { |
| 677 keepalive_impulse_decrement_callback_for_testing_ = callback; | 671 keepalive_impulse_decrement_callback_for_testing_ = callback; |
| 678 } | 672 } |
| 679 | 673 |
| 674 // static |
| 675 void ProcessManager::SetEventPageIdleTimeForTesting(unsigned idle_time_msec) { |
| 676 CHECK_GT(idle_time_msec, 0u); // OnKeepaliveImpulseCheck requires non zero. |
| 677 g_event_page_idle_time_msec = idle_time_msec; |
| 678 } |
| 679 |
| 680 // static |
| 681 void ProcessManager::SetEventPageSuspendingTimeForTesting( |
| 682 unsigned suspending_time_msec) { |
| 683 g_event_page_suspending_time_msec = suspending_time_msec; |
| 684 } |
| 685 |
| 680 void ProcessManager::Observe(int type, | 686 void ProcessManager::Observe(int type, |
| 681 const content::NotificationSource& source, | 687 const content::NotificationSource& source, |
| 682 const content::NotificationDetails& details) { | 688 const content::NotificationDetails& details) { |
| 683 switch (type) { | 689 switch (type) { |
| 684 case extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED: { | 690 case extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED: { |
| 685 // TODO(jamescook): Convert this to use ExtensionSystem::ready() instead | 691 // TODO(jamescook): Convert this to use ExtensionSystem::ready() instead |
| 686 // of a notification. | 692 // of a notification. |
| 687 MaybeCreateStartupBackgroundHosts(); | 693 MaybeCreateStartupBackgroundHosts(); |
| 688 break; | 694 break; |
| 689 } | 695 } |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 945 SiteInstance* IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) { | 951 SiteInstance* IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) { |
| 946 const Extension* extension = | 952 const Extension* extension = |
| 947 extension_registry_->enabled_extensions().GetExtensionOrAppByURL(url); | 953 extension_registry_->enabled_extensions().GetExtensionOrAppByURL(url); |
| 948 if (extension && !IncognitoInfo::IsSplitMode(extension)) | 954 if (extension && !IncognitoInfo::IsSplitMode(extension)) |
| 949 return original_manager_->GetSiteInstanceForURL(url); | 955 return original_manager_->GetSiteInstanceForURL(url); |
| 950 | 956 |
| 951 return ProcessManager::GetSiteInstanceForURL(url); | 957 return ProcessManager::GetSiteInstanceForURL(url); |
| 952 } | 958 } |
| 953 | 959 |
| 954 } // namespace extensions | 960 } // namespace extensions |
| OLD | NEW |