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 |