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 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 | 126 |
127 ProcessManager* process_manager_; | 127 ProcessManager* process_manager_; |
128 | 128 |
129 DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestructionObserver); | 129 DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestructionObserver); |
130 }; | 130 }; |
131 | 131 |
132 struct ProcessManager::BackgroundPageData { | 132 struct ProcessManager::BackgroundPageData { |
133 // The count of things keeping the lazy background page alive. | 133 // The count of things keeping the lazy background page alive. |
134 int lazy_keepalive_count; | 134 int lazy_keepalive_count; |
135 | 135 |
136 // Tracks if an impulse event has occured since the last polling check. | |
137 bool keepalive_impulse; | |
138 bool previous_keepalive_impulse; | |
139 | |
136 // This is used with the ShouldSuspend message, to ensure that the extension | 140 // This is used with the ShouldSuspend message, to ensure that the extension |
137 // remained idle between sending the message and receiving the ack. | 141 // remained idle between sending the message and receiving the ack. |
138 int close_sequence_id; | 142 int close_sequence_id; |
139 | 143 |
140 // True if the page responded to the ShouldSuspend message and is currently | 144 // True if the page responded to the ShouldSuspend message and is currently |
141 // dispatching the suspend event. During this time any events that arrive will | 145 // dispatching the suspend event. During this time any events that arrive will |
142 // cancel the suspend process and an onSuspendCanceled event will be | 146 // cancel the suspend process and an onSuspendCanceled event will be |
143 // dispatched to the page. | 147 // dispatched to the page. |
144 bool is_closing; | 148 bool is_closing; |
145 | 149 |
146 // Keeps track of when this page was last suspended. Used for perf metrics. | 150 // Keeps track of when this page was last suspended. Used for perf metrics. |
147 linked_ptr<base::ElapsedTimer> since_suspended; | 151 linked_ptr<base::ElapsedTimer> since_suspended; |
148 | 152 |
149 BackgroundPageData() | 153 BackgroundPageData() |
150 : lazy_keepalive_count(0), close_sequence_id(0), is_closing(false) {} | 154 : lazy_keepalive_count(0), |
155 keepalive_impulse(false), | |
156 previous_keepalive_impulse(false), | |
157 close_sequence_id(0), | |
158 is_closing(false) {} | |
151 }; | 159 }; |
152 | 160 |
153 // | 161 // |
154 // ProcessManager | 162 // ProcessManager |
155 // | 163 // |
156 | 164 |
157 // static | 165 // static |
158 ProcessManager* ProcessManager::Create(BrowserContext* context) { | 166 ProcessManager* ProcessManager::Create(BrowserContext* context) { |
159 if (context->IsOffTheRecord()) { | 167 if (context->IsOffTheRecord()) { |
160 BrowserContext* original_context = | 168 BrowserContext* original_context = |
(...skipping 29 matching lines...) Expand all Loading... | |
190 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, | 198 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, |
191 content::Source<BrowserContext>(original_context)); | 199 content::Source<BrowserContext>(original_context)); |
192 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | 200 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
193 content::Source<BrowserContext>(context)); | 201 content::Source<BrowserContext>(context)); |
194 if (context->IsOffTheRecord()) { | 202 if (context->IsOffTheRecord()) { |
195 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | 203 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
196 content::Source<BrowserContext>(original_context)); | 204 content::Source<BrowserContext>(original_context)); |
197 } | 205 } |
198 | 206 |
199 event_page_idle_time_ = base::TimeDelta::FromSeconds(10); | 207 event_page_idle_time_ = base::TimeDelta::FromSeconds(10); |
200 unsigned idle_time_sec = 0; | 208 unsigned idle_time_msec = 0; |
201 if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 209 if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
202 extensions::switches::kEventPageIdleTime), &idle_time_sec)) { | 210 extensions::switches::kEventPageIdleTime), &idle_time_msec)) { |
203 event_page_idle_time_ = base::TimeDelta::FromSeconds(idle_time_sec); | 211 CHECK(idle_time_msec > 0); // OnKeepaliveImpulseCheck requires non zero. |
tapted
2013/11/28 03:03:37
optional nit: maybe CHECK_NE(0u, idle_time_msec)?
scheib
2013/12/02 21:22:38
I think this check output is pretty clear as is wi
| |
212 event_page_idle_time_ = base::TimeDelta::FromMilliseconds(idle_time_msec); | |
204 } | 213 } |
205 event_page_suspending_time_ = base::TimeDelta::FromSeconds(5); | 214 event_page_suspending_time_ = base::TimeDelta::FromSeconds(5); |
206 unsigned suspending_time_sec = 0; | 215 unsigned suspending_time_msec = 0; |
207 if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 216 if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
208 extensions::switches::kEventPageSuspendingTime), | 217 extensions::switches::kEventPageSuspendingTime), |
209 &suspending_time_sec)) { | 218 &suspending_time_msec)) { |
210 event_page_suspending_time_ = | 219 event_page_suspending_time_ = |
211 base::TimeDelta::FromSeconds(suspending_time_sec); | 220 base::TimeDelta::FromMilliseconds(suspending_time_msec); |
212 } | 221 } |
213 | 222 |
214 content::DevToolsManager::GetInstance()->AddAgentStateCallback( | 223 content::DevToolsManager::GetInstance()->AddAgentStateCallback( |
215 devtools_callback_); | 224 devtools_callback_); |
225 | |
226 OnKeepaliveImpulseCheck(); | |
216 } | 227 } |
217 | 228 |
218 ProcessManager::~ProcessManager() { | 229 ProcessManager::~ProcessManager() { |
219 CloseBackgroundHosts(); | 230 CloseBackgroundHosts(); |
220 DCHECK(background_hosts_.empty()); | 231 DCHECK(background_hosts_.empty()); |
221 content::DevToolsManager::GetInstance()->RemoveAgentStateCallback( | 232 content::DevToolsManager::GetInstance()->RemoveAgentStateCallback( |
222 devtools_callback_); | 233 devtools_callback_); |
223 } | 234 } |
224 | 235 |
225 const ProcessManager::ViewSet ProcessManager::GetAllViews() const { | 236 const ProcessManager::ViewSet ProcessManager::GetAllViews() const { |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
353 int& count = background_page_data_[extension->id()].lazy_keepalive_count; | 364 int& count = background_page_data_[extension->id()].lazy_keepalive_count; |
354 if (++count == 1) | 365 if (++count == 1) |
355 OnLazyBackgroundPageActive(extension->id()); | 366 OnLazyBackgroundPageActive(extension->id()); |
356 | 367 |
357 return count; | 368 return count; |
358 } | 369 } |
359 | 370 |
360 int ProcessManager::DecrementLazyKeepaliveCount(const Extension* extension) { | 371 int ProcessManager::DecrementLazyKeepaliveCount(const Extension* extension) { |
361 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) | 372 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
362 return 0; | 373 return 0; |
374 return DecrementLazyKeepaliveCount(extension->id()); | |
375 } | |
363 | 376 |
364 int& count = background_page_data_[extension->id()].lazy_keepalive_count; | 377 int ProcessManager::DecrementLazyKeepaliveCount(std::string extension_id) { |
378 int& count = background_page_data_[extension_id].lazy_keepalive_count; | |
365 DCHECK_GT(count, 0); | 379 DCHECK_GT(count, 0); |
366 | 380 |
367 // If we reach a zero keepalive count when the lazy background page is about | 381 // If we reach a zero keepalive count when the lazy background page is about |
368 // to be closed, incrementing close_sequence_id will cancel the close | 382 // to be closed, incrementing close_sequence_id will cancel the close |
369 // sequence and cause the background page to linger. So check is_closing | 383 // sequence and cause the background page to linger. So check is_closing |
370 // before initiating another close sequence. | 384 // before initiating another close sequence. |
371 if (--count == 0 && !background_page_data_[extension->id()].is_closing) { | 385 if (--count == 0 && !background_page_data_[extension_id].is_closing) { |
372 base::MessageLoop::current()->PostDelayedTask( | 386 base::MessageLoop::current()->PostDelayedTask( |
373 FROM_HERE, | 387 FROM_HERE, |
374 base::Bind(&ProcessManager::OnLazyBackgroundPageIdle, | 388 base::Bind(&ProcessManager::OnLazyBackgroundPageIdle, |
375 weak_ptr_factory_.GetWeakPtr(), extension->id(), | 389 weak_ptr_factory_.GetWeakPtr(), extension_id, |
376 ++background_page_data_[extension->id()].close_sequence_id), | 390 ++background_page_data_[extension_id].close_sequence_id), |
377 event_page_idle_time_); | 391 event_page_idle_time_); |
378 } | 392 } |
379 | 393 |
380 return count; | 394 return count; |
381 } | 395 } |
382 | 396 |
383 void ProcessManager::IncrementLazyKeepaliveCountForView( | 397 void ProcessManager::IncrementLazyKeepaliveCountForView( |
384 RenderViewHost* render_view_host) { | 398 RenderViewHost* render_view_host) { |
385 WebContents* web_contents = | 399 WebContents* web_contents = |
386 WebContents::FromRenderViewHost(render_view_host); | 400 WebContents::FromRenderViewHost(render_view_host); |
387 ViewType view_type = GetViewType(web_contents); | 401 ViewType view_type = GetViewType(web_contents); |
388 if (view_type != VIEW_TYPE_INVALID && | 402 if (view_type != VIEW_TYPE_INVALID && |
389 view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { | 403 view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
390 const Extension* extension = GetExtensionForRenderViewHost( | 404 const Extension* extension = GetExtensionForRenderViewHost( |
391 render_view_host); | 405 render_view_host); |
392 if (extension) | 406 if (extension) |
393 IncrementLazyKeepaliveCount(extension); | 407 IncrementLazyKeepaliveCount(extension); |
394 } | 408 } |
395 } | 409 } |
396 | 410 |
411 // This implementation layers on top of the keepalive count. An impulse sets | |
412 // a per extension flag. On a regular interval that flag is checked. Changes | |
413 // from the flag not being set to set cause an IncrementLazyKeepaliveCount. | |
414 void ProcessManager::KeepaliveImpulse(const Extension* extension) { | |
415 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) | |
416 return; | |
417 | |
418 BackgroundPageData& bd = background_page_data_[extension->id()]; | |
419 | |
420 if (!bd.keepalive_impulse) { | |
421 bd.keepalive_impulse = true; | |
422 if (!bd.previous_keepalive_impulse) { | |
423 IncrementLazyKeepaliveCount(extension); | |
424 } | |
425 } | |
426 } | |
427 | |
428 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse | |
429 // have been made for at least event_page_idle_time_. In the best case an | |
430 // impulse was made just before being cleared, and the decrement will occur | |
431 // event_page_idle_time_ later, causing a 2 * event_page_idle_time_ total time | |
432 // for extension to be shut down based on impulses. Worst case is an impulse | |
433 // just after a clear, adding one check cycle and resulting in 3x total time. | |
434 void ProcessManager::OnKeepaliveImpulseCheck() { | |
435 for (BackgroundPageDataMap::iterator i = background_page_data_.begin(); | |
436 i != background_page_data_.end(); | |
437 ++i) { | |
438 bool this_impulse = i->second.keepalive_impulse; | |
tapted
2013/11/28 03:03:37
(optional) This might be easier to read without th
scheib
2013/12/02 21:22:38
Done; your first suggestion. The latter didn't reu
| |
439 bool previous_impulse = i->second.previous_keepalive_impulse; | |
440 i->second.keepalive_impulse = false; | |
441 i->second.previous_keepalive_impulse = this_impulse; | |
442 | |
443 if (previous_impulse && !this_impulse) | |
444 DecrementLazyKeepaliveCount(i->first); | |
tapted
2013/11/28 03:03:37
I thought it weird that the return value wasn't ch
scheib
2013/12/02 21:22:38
Done.
| |
445 } | |
446 | |
447 if (base::MessageLoop::current()) { | |
tapted
2013/11/28 03:03:37
Maybe a comment here to explain this check (e.g. S
scheib
2013/12/02 21:22:38
Done.
| |
448 base::MessageLoop::current()->PostDelayedTask( | |
449 FROM_HERE, | |
450 base::Bind(&ProcessManager::OnKeepaliveImpulseCheck, | |
451 weak_ptr_factory_.GetWeakPtr()), | |
452 event_page_idle_time_); | |
453 } | |
454 } | |
455 | |
397 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id, | 456 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id, |
398 int sequence_id) { | 457 int sequence_id) { |
399 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); | 458 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
400 if (host && !background_page_data_[extension_id].is_closing && | 459 if (host && !background_page_data_[extension_id].is_closing && |
401 sequence_id == background_page_data_[extension_id].close_sequence_id) { | 460 sequence_id == background_page_data_[extension_id].close_sequence_id) { |
402 // Tell the renderer we are about to close. This is a simple ping that the | 461 // Tell the renderer we are about to close. This is a simple ping that the |
403 // renderer will respond to. The purpose is to control sequencing: if the | 462 // renderer will respond to. The purpose is to control sequencing: if the |
404 // extension remains idle until the renderer responds with an ACK, then we | 463 // extension remains idle until the renderer responds with an ACK, then we |
405 // know that the extension process is ready to shut down. If our | 464 // know that the extension process is ready to shut down. If our |
406 // close_sequence_id has already changed, then we would ignore the | 465 // close_sequence_id has already changed, then we would ignore the |
(...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
806 } | 865 } |
807 | 866 |
808 bool IncognitoProcessManager::IsIncognitoEnabled(const Extension* extension) { | 867 bool IncognitoProcessManager::IsIncognitoEnabled(const Extension* extension) { |
809 // Keep in sync with duplicate in extension_info_map.cc. | 868 // Keep in sync with duplicate in extension_info_map.cc. |
810 ExtensionService* service = ExtensionSystem::GetForBrowserContext( | 869 ExtensionService* service = ExtensionSystem::GetForBrowserContext( |
811 GetBrowserContext())->extension_service(); | 870 GetBrowserContext())->extension_service(); |
812 return extension_util::IsIncognitoEnabled(extension->id(), service); | 871 return extension_util::IsIncognitoEnabled(extension->id(), service); |
813 } | 872 } |
814 | 873 |
815 } // namespace extensions | 874 } // namespace extensions |
OLD | NEW |