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. |
| 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 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 return (host && background_page_data_[extension_id].is_closing); | 350 return (host && background_page_data_[extension_id].is_closing); |
340 } | 351 } |
341 | 352 |
342 int ProcessManager::GetLazyKeepaliveCount(const Extension* extension) { | 353 int ProcessManager::GetLazyKeepaliveCount(const Extension* extension) { |
343 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) | 354 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
344 return 0; | 355 return 0; |
345 | 356 |
346 return background_page_data_[extension->id()].lazy_keepalive_count; | 357 return background_page_data_[extension->id()].lazy_keepalive_count; |
347 } | 358 } |
348 | 359 |
349 int ProcessManager::IncrementLazyKeepaliveCount(const Extension* extension) { | 360 void ProcessManager::IncrementLazyKeepaliveCount(const Extension* extension) { |
350 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) | 361 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
351 return 0; | 362 return; |
352 | 363 |
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 | |
357 return count; | |
358 } | 367 } |
359 | 368 |
360 int ProcessManager::DecrementLazyKeepaliveCount(const Extension* extension) { | 369 void ProcessManager::DecrementLazyKeepaliveCount(const Extension* extension) { |
361 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) | 370 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
362 return 0; | 371 return; |
| 372 DecrementLazyKeepaliveCount(extension->id()); |
| 373 } |
363 | 374 |
364 int& count = background_page_data_[extension->id()].lazy_keepalive_count; | 375 void ProcessManager::DecrementLazyKeepaliveCount( |
| 376 const std::string& extension_id) { |
| 377 int& count = background_page_data_[extension_id].lazy_keepalive_count; |
365 DCHECK_GT(count, 0); | 378 DCHECK_GT(count, 0); |
366 | 379 |
367 // If we reach a zero keepalive count when the lazy background page is about | 380 // 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 | 381 // to be closed, incrementing close_sequence_id will cancel the close |
369 // sequence and cause the background page to linger. So check is_closing | 382 // sequence and cause the background page to linger. So check is_closing |
370 // before initiating another close sequence. | 383 // before initiating another close sequence. |
371 if (--count == 0 && !background_page_data_[extension->id()].is_closing) { | 384 if (--count == 0 && !background_page_data_[extension_id].is_closing) { |
372 base::MessageLoop::current()->PostDelayedTask( | 385 base::MessageLoop::current()->PostDelayedTask( |
373 FROM_HERE, | 386 FROM_HERE, |
374 base::Bind(&ProcessManager::OnLazyBackgroundPageIdle, | 387 base::Bind(&ProcessManager::OnLazyBackgroundPageIdle, |
375 weak_ptr_factory_.GetWeakPtr(), extension->id(), | 388 weak_ptr_factory_.GetWeakPtr(), extension_id, |
376 ++background_page_data_[extension->id()].close_sequence_id), | 389 ++background_page_data_[extension_id].close_sequence_id), |
377 event_page_idle_time_); | 390 event_page_idle_time_); |
378 } | 391 } |
379 | |
380 return count; | |
381 } | 392 } |
382 | 393 |
383 void ProcessManager::IncrementLazyKeepaliveCountForView( | 394 void ProcessManager::IncrementLazyKeepaliveCountForView( |
384 RenderViewHost* render_view_host) { | 395 RenderViewHost* render_view_host) { |
385 WebContents* web_contents = | 396 WebContents* web_contents = |
386 WebContents::FromRenderViewHost(render_view_host); | 397 WebContents::FromRenderViewHost(render_view_host); |
387 ViewType view_type = GetViewType(web_contents); | 398 ViewType view_type = GetViewType(web_contents); |
388 if (view_type != VIEW_TYPE_INVALID && | 399 if (view_type != VIEW_TYPE_INVALID && |
389 view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { | 400 view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
390 const Extension* extension = GetExtensionForRenderViewHost( | 401 const Extension* extension = GetExtensionForRenderViewHost( |
391 render_view_host); | 402 render_view_host); |
392 if (extension) | 403 if (extension) |
393 IncrementLazyKeepaliveCount(extension); | 404 IncrementLazyKeepaliveCount(extension); |
394 } | 405 } |
395 } | 406 } |
396 | 407 |
| 408 // This implementation layers on top of the keepalive count. An impulse sets |
| 409 // a per extension flag. On a regular interval that flag is checked. Changes |
| 410 // from the flag not being set to set cause an IncrementLazyKeepaliveCount. |
| 411 void ProcessManager::KeepaliveImpulse(const Extension* extension) { |
| 412 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
| 413 return; |
| 414 |
| 415 BackgroundPageData& bd = background_page_data_[extension->id()]; |
| 416 |
| 417 if (!bd.keepalive_impulse) { |
| 418 bd.keepalive_impulse = true; |
| 419 if (!bd.previous_keepalive_impulse) { |
| 420 IncrementLazyKeepaliveCount(extension); |
| 421 } |
| 422 } |
| 423 } |
| 424 |
| 425 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse |
| 426 // have been made for at least event_page_idle_time_. In the best case an |
| 427 // impulse was made just before being cleared, and the decrement will occur |
| 428 // event_page_idle_time_ later, causing a 2 * event_page_idle_time_ total time |
| 429 // for extension to be shut down based on impulses. Worst case is an impulse |
| 430 // just after a clear, adding one check cycle and resulting in 3x total time. |
| 431 void ProcessManager::OnKeepaliveImpulseCheck() { |
| 432 for (BackgroundPageDataMap::iterator i = background_page_data_.begin(); |
| 433 i != background_page_data_.end(); |
| 434 ++i) { |
| 435 if (i->second.previous_keepalive_impulse && !i->second.keepalive_impulse) |
| 436 DecrementLazyKeepaliveCount(i->first); |
| 437 |
| 438 i->second.previous_keepalive_impulse = i->second.keepalive_impulse; |
| 439 i->second.keepalive_impulse = false; |
| 440 } |
| 441 |
| 442 // OnKeepaliveImpulseCheck() is always called in constructor, but in unit |
| 443 // tests there will be no message loop. In that event don't schedule tasks. |
| 444 if (base::MessageLoop::current()) { |
| 445 base::MessageLoop::current()->PostDelayedTask( |
| 446 FROM_HERE, |
| 447 base::Bind(&ProcessManager::OnKeepaliveImpulseCheck, |
| 448 weak_ptr_factory_.GetWeakPtr()), |
| 449 event_page_idle_time_); |
| 450 } |
| 451 } |
| 452 |
397 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id, | 453 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id, |
398 int sequence_id) { | 454 int sequence_id) { |
399 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); | 455 ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
400 if (host && !background_page_data_[extension_id].is_closing && | 456 if (host && !background_page_data_[extension_id].is_closing && |
401 sequence_id == background_page_data_[extension_id].close_sequence_id) { | 457 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 | 458 // 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 | 459 // 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 | 460 // 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 | 461 // know that the extension process is ready to shut down. If our |
406 // close_sequence_id has already changed, then we would ignore the | 462 // 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 } | 862 } |
807 | 863 |
808 bool IncognitoProcessManager::IsIncognitoEnabled(const Extension* extension) { | 864 bool IncognitoProcessManager::IsIncognitoEnabled(const Extension* extension) { |
809 // Keep in sync with duplicate in extension_info_map.cc. | 865 // Keep in sync with duplicate in extension_info_map.cc. |
810 ExtensionService* service = ExtensionSystem::GetForBrowserContext( | 866 ExtensionService* service = ExtensionSystem::GetForBrowserContext( |
811 GetBrowserContext())->extension_service(); | 867 GetBrowserContext())->extension_service(); |
812 return extension_util::IsIncognitoEnabled(extension->id(), service); | 868 return extension_util::IsIncognitoEnabled(extension->id(), service); |
813 } | 869 } |
814 | 870 |
815 } // namespace extensions | 871 } // namespace extensions |
OLD | NEW |