| 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 <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 #include "extensions/common/one_shot_event.h" | 41 #include "extensions/common/one_shot_event.h" |
| 42 | 42 |
| 43 using content::BrowserContext; | 43 using content::BrowserContext; |
| 44 | 44 |
| 45 namespace extensions { | 45 namespace extensions { |
| 46 | 46 |
| 47 namespace { | 47 namespace { |
| 48 | 48 |
| 49 // The time to delay between an extension becoming idle and | 49 // The time to delay between an extension becoming idle and |
| 50 // sending a ShouldSuspend message. | 50 // sending a ShouldSuspend message. |
| 51 // Note: Must be sufficiently larger (e.g. 2x) than | |
| 52 // kKeepaliveThrottleIntervalInSeconds in ppapi/proxy/plugin_globals. | |
| 53 unsigned g_event_page_idle_time_msec = 10000; | 51 unsigned g_event_page_idle_time_msec = 10000; |
| 54 | 52 |
| 55 // The time to delay between sending a ShouldSuspend message and | 53 // The time to delay between sending a ShouldSuspend message and |
| 56 // sending a Suspend message. | 54 // sending a Suspend message. |
| 57 unsigned g_event_page_suspending_time_msec = 5000; | 55 unsigned g_event_page_suspending_time_msec = 5000; |
| 58 | 56 |
| 59 std::string GetExtensionIdForSiteInstance( | 57 std::string GetExtensionIdForSiteInstance( |
| 60 content::SiteInstance* site_instance) { | 58 content::SiteInstance* site_instance) { |
| 61 if (!site_instance) | 59 if (!site_instance) |
| 62 return std::string(); | 60 return std::string(); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 | 111 |
| 114 void PropagateExtensionWakeResult(const base::Callback<void(bool)>& callback, | 112 void PropagateExtensionWakeResult(const base::Callback<void(bool)>& callback, |
| 115 extensions::ExtensionHost* host) { | 113 extensions::ExtensionHost* host) { |
| 116 callback.Run(host != nullptr); | 114 callback.Run(host != nullptr); |
| 117 } | 115 } |
| 118 | 116 |
| 119 } // namespace | 117 } // namespace |
| 120 | 118 |
| 121 struct ProcessManager::BackgroundPageData { | 119 struct ProcessManager::BackgroundPageData { |
| 122 // The count of things keeping the lazy background page alive. | 120 // The count of things keeping the lazy background page alive. |
| 123 int lazy_keepalive_count; | 121 int lazy_keepalive_count = 0; |
| 124 | |
| 125 // Tracks if an impulse event has occured since the last polling check. | |
| 126 bool keepalive_impulse; | |
| 127 bool previous_keepalive_impulse; | |
| 128 | 122 |
| 129 // True if the page responded to the ShouldSuspend message and is currently | 123 // True if the page responded to the ShouldSuspend message and is currently |
| 130 // dispatching the suspend event. During this time any events that arrive will | 124 // dispatching the suspend event. During this time any events that arrive will |
| 131 // cancel the suspend process and an onSuspendCanceled event will be | 125 // cancel the suspend process and an onSuspendCanceled event will be |
| 132 // dispatched to the page. | 126 // dispatched to the page. |
| 133 bool is_closing; | 127 bool is_closing = false; |
| 134 | 128 |
| 135 // Stores the value of the incremented | 129 // Stores the value of the incremented |
| 136 // ProcessManager::last_background_close_sequence_id_ whenever the extension | 130 // ProcessManager::last_background_close_sequence_id_ whenever the extension |
| 137 // is active. A copy of the ID is also passed in the callbacks and IPC | 131 // is active. A copy of the ID is also passed in the callbacks and IPC |
| 138 // messages leading up to CloseLazyBackgroundPageNow. The process is aborted | 132 // messages leading up to CloseLazyBackgroundPageNow. The process is aborted |
| 139 // if the IDs ever differ due to new activity. | 133 // if the IDs ever differ due to new activity. |
| 140 uint64_t close_sequence_id; | 134 uint64_t close_sequence_id = 0ull; |
| 141 | 135 |
| 142 // Keeps track of when this page was last suspended. Used for perf metrics. | 136 // Keeps track of when this page was last suspended. Used for perf metrics. |
| 143 std::unique_ptr<base::ElapsedTimer> since_suspended; | 137 std::unique_ptr<base::ElapsedTimer> since_suspended; |
| 144 | |
| 145 BackgroundPageData() | |
| 146 : lazy_keepalive_count(0), | |
| 147 keepalive_impulse(false), | |
| 148 previous_keepalive_impulse(false), | |
| 149 is_closing(false), | |
| 150 close_sequence_id(0) {} | |
| 151 }; | 138 }; |
| 152 | 139 |
| 153 // Data of a RenderFrameHost associated with an extension. | 140 // Data of a RenderFrameHost associated with an extension. |
| 154 struct ProcessManager::ExtensionRenderFrameData { | 141 struct ProcessManager::ExtensionRenderFrameData { |
| 155 // The type of the view. | 142 // The type of the view. |
| 156 extensions::ViewType view_type; | 143 extensions::ViewType view_type = VIEW_TYPE_INVALID; |
| 157 | 144 |
| 158 // Whether the view is keeping the lazy background page alive or not. | 145 // Whether the view is keeping the lazy background page alive or not. |
| 159 bool has_keepalive; | 146 bool has_keepalive = false; |
| 160 | |
| 161 ExtensionRenderFrameData() | |
| 162 : view_type(VIEW_TYPE_INVALID), has_keepalive(false) {} | |
| 163 | 147 |
| 164 // Returns whether the view can keep the lazy background page alive or not. | 148 // Returns whether the view can keep the lazy background page alive or not. |
| 165 bool CanKeepalive() const { | 149 bool CanKeepalive() const { |
| 166 switch (view_type) { | 150 switch (view_type) { |
| 167 case VIEW_TYPE_APP_WINDOW: | 151 case VIEW_TYPE_APP_WINDOW: |
| 168 case VIEW_TYPE_BACKGROUND_CONTENTS: | 152 case VIEW_TYPE_BACKGROUND_CONTENTS: |
| 169 case VIEW_TYPE_COMPONENT: | 153 case VIEW_TYPE_COMPONENT: |
| 170 case VIEW_TYPE_EXTENSION_DIALOG: | 154 case VIEW_TYPE_EXTENSION_DIALOG: |
| 171 case VIEW_TYPE_EXTENSION_GUEST: | 155 case VIEW_TYPE_EXTENSION_GUEST: |
| 172 case VIEW_TYPE_EXTENSION_POPUP: | 156 case VIEW_TYPE_EXTENSION_POPUP: |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, | 239 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, |
| 256 content::Source<BrowserContext>(original_context)); | 240 content::Source<BrowserContext>(original_context)); |
| 257 } | 241 } |
| 258 registrar_.Add(this, | 242 registrar_.Add(this, |
| 259 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, | 243 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, |
| 260 content::Source<BrowserContext>(context)); | 244 content::Source<BrowserContext>(context)); |
| 261 registrar_.Add(this, | 245 registrar_.Add(this, |
| 262 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, | 246 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
| 263 content::Source<BrowserContext>(context)); | 247 content::Source<BrowserContext>(context)); |
| 264 content::DevToolsAgentHost::AddObserver(this); | 248 content::DevToolsAgentHost::AddObserver(this); |
| 265 | |
| 266 OnKeepaliveImpulseCheck(); | |
| 267 } | 249 } |
| 268 | 250 |
| 269 ProcessManager::~ProcessManager() = default; | 251 ProcessManager::~ProcessManager() = default; |
| 270 | 252 |
| 271 void ProcessManager::Shutdown() { | 253 void ProcessManager::Shutdown() { |
| 272 extension_registry_->RemoveObserver(this); | 254 extension_registry_->RemoveObserver(this); |
| 273 CloseBackgroundHosts(); | 255 CloseBackgroundHosts(); |
| 274 DCHECK(background_hosts_.empty()); | 256 DCHECK(background_hosts_.empty()); |
| 275 content::DevToolsAgentHost::RemoveObserver(this); | 257 content::DevToolsAgentHost::RemoveObserver(this); |
| 276 site_instance_ = nullptr; | 258 site_instance_ = nullptr; |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 if (++count == 1) | 470 if (++count == 1) |
| 489 OnLazyBackgroundPageActive(extension->id()); | 471 OnLazyBackgroundPageActive(extension->id()); |
| 490 } | 472 } |
| 491 } | 473 } |
| 492 | 474 |
| 493 void ProcessManager::DecrementLazyKeepaliveCount(const Extension* extension) { | 475 void ProcessManager::DecrementLazyKeepaliveCount(const Extension* extension) { |
| 494 if (BackgroundInfo::HasLazyBackgroundPage(extension)) | 476 if (BackgroundInfo::HasLazyBackgroundPage(extension)) |
| 495 DecrementLazyKeepaliveCount(extension->id()); | 477 DecrementLazyKeepaliveCount(extension->id()); |
| 496 } | 478 } |
| 497 | 479 |
| 498 // This implementation layers on top of the keepalive count. An impulse sets | |
| 499 // a per extension flag. On a regular interval that flag is checked. Changes | |
| 500 // from the flag not being set to set cause an IncrementLazyKeepaliveCount. | |
| 501 void ProcessManager::KeepaliveImpulse(const Extension* extension) { | |
| 502 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) | |
| 503 return; | |
| 504 | |
| 505 BackgroundPageData& bd = background_page_data_[extension->id()]; | |
| 506 | |
| 507 if (!bd.keepalive_impulse) { | |
| 508 bd.keepalive_impulse = true; | |
| 509 if (!bd.previous_keepalive_impulse) { | |
| 510 IncrementLazyKeepaliveCount(extension); | |
| 511 } | |
| 512 } | |
| 513 | |
| 514 if (!keepalive_impulse_callback_for_testing_.is_null()) { | |
| 515 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly = | |
| 516 keepalive_impulse_callback_for_testing_; | |
| 517 callback_may_clear_callbacks_reentrantly.Run(extension->id()); | |
| 518 } | |
| 519 } | |
| 520 | |
| 521 // static | |
| 522 void ProcessManager::OnKeepaliveFromPlugin(int render_process_id, | |
| 523 int render_frame_id, | |
| 524 const std::string& extension_id) { | |
| 525 content::RenderFrameHost* render_frame_host = | |
| 526 content::RenderFrameHost::FromID(render_process_id, render_frame_id); | |
| 527 if (!render_frame_host) | |
| 528 return; | |
| 529 | |
| 530 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); | |
| 531 if (!site_instance) | |
| 532 return; | |
| 533 | |
| 534 BrowserContext* browser_context = site_instance->GetBrowserContext(); | |
| 535 const Extension* extension = | |
| 536 ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID( | |
| 537 extension_id); | |
| 538 if (!extension) | |
| 539 return; | |
| 540 | |
| 541 ProcessManager::Get(browser_context)->KeepaliveImpulse(extension); | |
| 542 } | |
| 543 | |
| 544 void ProcessManager::OnShouldSuspendAck(const std::string& extension_id, | 480 void ProcessManager::OnShouldSuspendAck(const std::string& extension_id, |
| 545 uint64_t sequence_id) { | 481 uint64_t sequence_id) { |
| 546 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); | 482 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
| 547 if (host && | 483 if (host && |
| 548 sequence_id == background_page_data_[extension_id].close_sequence_id) { | 484 sequence_id == background_page_data_[extension_id].close_sequence_id) { |
| 549 host->render_process_host()->Send(new ExtensionMsg_Suspend(extension_id)); | 485 host->render_process_host()->Send(new ExtensionMsg_Suspend(extension_id)); |
| 550 } | 486 } |
| 551 } | 487 } |
| 552 | 488 |
| 553 void ProcessManager::OnSuspendAck(const std::string& extension_id) { | 489 void ProcessManager::OnSuspendAck(const std::string& extension_id) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 // which will cause the removal of the host from the |background_hosts_| set | 559 // which will cause the removal of the host from the |background_hosts_| set |
| 624 // in the Observe() method below. | 560 // in the Observe() method below. |
| 625 delete host; | 561 delete host; |
| 626 DCHECK_EQ(0u, background_hosts_.count(host)); | 562 DCHECK_EQ(0u, background_hosts_.count(host)); |
| 627 } | 563 } |
| 628 | 564 |
| 629 // At this point there should be nothing left in |background_hosts_|. | 565 // At this point there should be nothing left in |background_hosts_|. |
| 630 DCHECK(background_hosts_.empty()); | 566 DCHECK(background_hosts_.empty()); |
| 631 } | 567 } |
| 632 | 568 |
| 633 void ProcessManager::SetKeepaliveImpulseCallbackForTesting( | |
| 634 const ImpulseCallbackForTesting& callback) { | |
| 635 keepalive_impulse_callback_for_testing_ = callback; | |
| 636 } | |
| 637 | |
| 638 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting( | |
| 639 const ImpulseCallbackForTesting& callback) { | |
| 640 keepalive_impulse_decrement_callback_for_testing_ = callback; | |
| 641 } | |
| 642 | |
| 643 // static | 569 // static |
| 644 void ProcessManager::SetEventPageIdleTimeForTesting(unsigned idle_time_msec) { | 570 void ProcessManager::SetEventPageIdleTimeForTesting(unsigned idle_time_msec) { |
| 645 CHECK_GT(idle_time_msec, 0u); // OnKeepaliveImpulseCheck requires non zero. | 571 CHECK_GT(idle_time_msec, 0u); |
| 646 g_event_page_idle_time_msec = idle_time_msec; | 572 g_event_page_idle_time_msec = idle_time_msec; |
| 647 } | 573 } |
| 648 | 574 |
| 649 // static | 575 // static |
| 650 void ProcessManager::SetEventPageSuspendingTimeForTesting( | 576 void ProcessManager::SetEventPageSuspendingTimeForTesting( |
| 651 unsigned suspending_time_msec) { | 577 unsigned suspending_time_msec) { |
| 652 g_event_page_suspending_time_msec = suspending_time_msec; | 578 g_event_page_suspending_time_msec = suspending_time_msec; |
| 653 } | 579 } |
| 654 | 580 |
| 655 //////////////////////////////////////////////////////////////////////////////// | 581 //////////////////////////////////////////////////////////////////////////////// |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 793 background_page_data_[extension_id].close_sequence_id = | 719 background_page_data_[extension_id].close_sequence_id = |
| 794 ++last_background_close_sequence_id_; | 720 ++last_background_close_sequence_id_; |
| 795 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 721 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 796 FROM_HERE, base::Bind(&ProcessManager::OnLazyBackgroundPageIdle, | 722 FROM_HERE, base::Bind(&ProcessManager::OnLazyBackgroundPageIdle, |
| 797 weak_ptr_factory_.GetWeakPtr(), extension_id, | 723 weak_ptr_factory_.GetWeakPtr(), extension_id, |
| 798 last_background_close_sequence_id_), | 724 last_background_close_sequence_id_), |
| 799 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec)); | 725 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec)); |
| 800 } | 726 } |
| 801 } | 727 } |
| 802 | 728 |
| 803 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse | |
| 804 // have been made for at least g_event_page_idle_time_msec. In the best case an | |
| 805 // impulse was made just before being cleared, and the decrement will occur | |
| 806 // g_event_page_idle_time_msec later, causing a 2 * g_event_page_idle_time_msec | |
| 807 // total time for extension to be shut down based on impulses. Worst case is | |
| 808 // an impulse just after a clear, adding one check cycle and resulting in 3x | |
| 809 // total time. | |
| 810 void ProcessManager::OnKeepaliveImpulseCheck() { | |
| 811 for (BackgroundPageDataMap::iterator i = background_page_data_.begin(); | |
| 812 i != background_page_data_.end(); | |
| 813 ++i) { | |
| 814 if (i->second.previous_keepalive_impulse && !i->second.keepalive_impulse) { | |
| 815 DecrementLazyKeepaliveCount(i->first); | |
| 816 if (!keepalive_impulse_decrement_callback_for_testing_.is_null()) { | |
| 817 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly = | |
| 818 keepalive_impulse_decrement_callback_for_testing_; | |
| 819 callback_may_clear_callbacks_reentrantly.Run(i->first); | |
| 820 } | |
| 821 } | |
| 822 | |
| 823 i->second.previous_keepalive_impulse = i->second.keepalive_impulse; | |
| 824 i->second.keepalive_impulse = false; | |
| 825 } | |
| 826 | |
| 827 // OnKeepaliveImpulseCheck() is always called in constructor, but in unit | |
| 828 // tests there will be no thread task runner handle. In that event don't | |
| 829 // schedule tasks. | |
| 830 if (base::ThreadTaskRunnerHandle::IsSet()) { | |
| 831 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 832 FROM_HERE, base::Bind(&ProcessManager::OnKeepaliveImpulseCheck, | |
| 833 weak_ptr_factory_.GetWeakPtr()), | |
| 834 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec)); | |
| 835 } | |
| 836 } | |
| 837 | |
| 838 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id, | 729 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id, |
| 839 uint64_t sequence_id) { | 730 uint64_t sequence_id) { |
| 840 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); | 731 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
| 841 if (host && !background_page_data_[extension_id].is_closing && | 732 if (host && !background_page_data_[extension_id].is_closing && |
| 842 sequence_id == background_page_data_[extension_id].close_sequence_id) { | 733 sequence_id == background_page_data_[extension_id].close_sequence_id) { |
| 843 // Tell the renderer we are about to close. This is a simple ping that the | 734 // Tell the renderer we are about to close. This is a simple ping that the |
| 844 // renderer will respond to. The purpose is to control sequencing: if the | 735 // renderer will respond to. The purpose is to control sequencing: if the |
| 845 // extension remains idle until the renderer responds with an ACK, then we | 736 // extension remains idle until the renderer responds with an ACK, then we |
| 846 // know that the extension process is ready to shut down. If our | 737 // know that the extension process is ready to shut down. If our |
| 847 // close_sequence_id has already changed, then we would ignore the | 738 // close_sequence_id has already changed, then we would ignore the |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 995 if (extension && !IncognitoInfo::IsSplitMode(extension)) { | 886 if (extension && !IncognitoInfo::IsSplitMode(extension)) { |
| 996 BrowserContext* original_context = | 887 BrowserContext* original_context = |
| 997 ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context()); | 888 ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context()); |
| 998 return ProcessManager::Get(original_context)->GetSiteInstanceForURL(url); | 889 return ProcessManager::Get(original_context)->GetSiteInstanceForURL(url); |
| 999 } | 890 } |
| 1000 | 891 |
| 1001 return ProcessManager::GetSiteInstanceForURL(url); | 892 return ProcessManager::GetSiteInstanceForURL(url); |
| 1002 } | 893 } |
| 1003 | 894 |
| 1004 } // namespace extensions | 895 } // namespace extensions |
| OLD | NEW |