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 |