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
3 // found in the LICENSE file.
5 #include "extensions/browser/process_manager.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/stl_util.h"
14 #include "base/time/time.h"
15 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/devtools_agent_host.h"
17 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "content/public/browser/site_instance.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/common/url_constants.h"
24 #include "extensions/browser/extension_host.h"
25 #include "extensions/browser/extension_registry.h"
26 #include "extensions/browser/extension_system.h"
27 #include "extensions/browser/extensions_browser_client.h"
28 #include "extensions/browser/lazy_background_task_queue.h"
29 #include "extensions/browser/notification_types.h"
30 #include "extensions/browser/process_manager_delegate.h"
31 #include "extensions/browser/process_manager_factory.h"
32 #include "extensions/browser/process_manager_observer.h"
33 #include "extensions/browser/view_type_utils.h"
34 #include "extensions/common/constants.h"
35 #include "extensions/common/extension.h"
36 #include "extensions/common/extension_messages.h"
37 #include "extensions/common/manifest_handlers/background_info.h"
38 #include "extensions/common/manifest_handlers/incognito_info.h"
39 #include "extensions/common/one_shot_event.h"
41 using content::BrowserContext
;
43 namespace extensions
{
47 // The time to delay between an extension becoming idle and
48 // sending a ShouldSuspend message.
49 // Note: Must be sufficiently larger (e.g. 2x) than
50 // kKeepaliveThrottleIntervalInSeconds in ppapi/proxy/plugin_globals.
51 unsigned g_event_page_idle_time_msec
= 10000;
53 // The time to delay between sending a ShouldSuspend message and
54 // sending a Suspend message.
55 unsigned g_event_page_suspending_time_msec
= 5000;
57 std::string
GetExtensionIdForSiteInstance(
58 content::SiteInstance
* site_instance
) {
62 // This works for both apps and extensions because the site has been
63 // normalized to the extension URL for hosted apps.
64 const GURL
& site_url
= site_instance
->GetSiteURL();
66 if (!site_url
.SchemeIs(kExtensionScheme
) &&
67 !site_url
.SchemeIs(content::kGuestScheme
))
70 return site_url
.host();
73 std::string
GetExtensionID(content::RenderFrameHost
* render_frame_host
) {
74 CHECK(render_frame_host
);
75 return GetExtensionIdForSiteInstance(render_frame_host
->GetSiteInstance());
78 bool IsFrameInExtensionHost(ExtensionHost
* extension_host
,
79 content::RenderFrameHost
* render_frame_host
) {
80 return content::WebContents::FromRenderFrameHost(render_frame_host
) ==
81 extension_host
->host_contents();
84 // Incognito profiles use this process manager. It is mostly a shim that decides
85 // whether to fall back on the original profile's ProcessManager based
86 // on whether a given extension uses "split" or "spanning" incognito behavior.
87 // TODO(devlin): Given how little this does and the amount of cruft it adds to
88 // the .h file (in the form of protected members), we should consider just
89 // moving the incognito logic into the base class.
90 class IncognitoProcessManager
: public ProcessManager
{
92 IncognitoProcessManager(BrowserContext
* incognito_context
,
93 BrowserContext
* original_context
,
94 ExtensionRegistry
* extension_registry
);
95 ~IncognitoProcessManager() override
{}
96 bool CreateBackgroundHost(const Extension
* extension
,
97 const GURL
& url
) override
;
98 scoped_refptr
<content::SiteInstance
> GetSiteInstanceForURL(const GURL
& url
)
102 DISALLOW_COPY_AND_ASSIGN(IncognitoProcessManager
);
105 static void CreateBackgroundHostForExtensionLoad(
106 ProcessManager
* manager
, const Extension
* extension
) {
107 DVLOG(1) << "CreateBackgroundHostForExtensionLoad";
108 if (BackgroundInfo::HasPersistentBackgroundPage(extension
))
109 manager
->CreateBackgroundHost(extension
,
110 BackgroundInfo::GetBackgroundURL(extension
));
113 void PropagateExtensionWakeResult(const base::Callback
<void(bool)>& callback
,
114 extensions::ExtensionHost
* host
) {
115 callback
.Run(host
!= nullptr);
120 struct ProcessManager::BackgroundPageData
{
121 // The count of things keeping the lazy background page alive.
122 int lazy_keepalive_count
;
124 // Tracks if an impulse event has occured since the last polling check.
125 bool keepalive_impulse
;
126 bool previous_keepalive_impulse
;
128 // True if the page responded to the ShouldSuspend message and is currently
129 // dispatching the suspend event. During this time any events that arrive will
130 // cancel the suspend process and an onSuspendCanceled event will be
131 // dispatched to the page.
134 // Stores the value of the incremented
135 // ProcessManager::last_background_close_sequence_id_ whenever the extension
136 // is active. A copy of the ID is also passed in the callbacks and IPC
137 // messages leading up to CloseLazyBackgroundPageNow. The process is aborted
138 // if the IDs ever differ due to new activity.
139 uint64 close_sequence_id
;
141 // Keeps track of when this page was last suspended. Used for perf metrics.
142 linked_ptr
<base::ElapsedTimer
> since_suspended
;
145 : lazy_keepalive_count(0),
146 keepalive_impulse(false),
147 previous_keepalive_impulse(false),
149 close_sequence_id(0) {}
152 // Data of a RenderFrameHost associated with an extension.
153 struct ProcessManager::ExtensionRenderFrameData
{
154 // The type of the view.
155 extensions::ViewType view_type
;
157 // Whether the view is keeping the lazy background page alive or not.
160 ExtensionRenderFrameData()
161 : view_type(VIEW_TYPE_INVALID
), has_keepalive(false) {}
163 // Returns whether the view can keep the lazy background page alive or not.
164 bool CanKeepalive() const {
166 case VIEW_TYPE_APP_WINDOW
:
167 case VIEW_TYPE_BACKGROUND_CONTENTS
:
168 case VIEW_TYPE_EXTENSION_DIALOG
:
169 case VIEW_TYPE_EXTENSION_POPUP
:
170 case VIEW_TYPE_LAUNCHER_PAGE
:
171 case VIEW_TYPE_PANEL
:
172 case VIEW_TYPE_TAB_CONTENTS
:
173 case VIEW_TYPE_VIRTUAL_KEYBOARD
:
176 case VIEW_TYPE_INVALID
:
177 case VIEW_TYPE_EXTENSION_BACKGROUND_PAGE
:
190 ProcessManager
* ProcessManager::Get(BrowserContext
* context
) {
191 return ProcessManagerFactory::GetForBrowserContext(context
);
195 ProcessManager
* ProcessManager::Create(BrowserContext
* context
) {
196 ExtensionRegistry
* extension_registry
= ExtensionRegistry::Get(context
);
197 ExtensionsBrowserClient
* client
= ExtensionsBrowserClient::Get();
198 if (client
->IsGuestSession(context
)) {
199 // In the guest session, there is a single off-the-record context. Unlike
200 // a regular incognito mode, background pages of extensions must be
201 // created regardless of whether extensions use "spanning" or "split"
202 // incognito behavior.
203 BrowserContext
* original_context
= client
->GetOriginalContext(context
);
204 return new ProcessManager(context
, original_context
, extension_registry
);
207 if (context
->IsOffTheRecord()) {
208 BrowserContext
* original_context
= client
->GetOriginalContext(context
);
209 return new IncognitoProcessManager(
210 context
, original_context
, extension_registry
);
213 return new ProcessManager(context
, context
, extension_registry
);
217 ProcessManager
* ProcessManager::CreateForTesting(
218 BrowserContext
* context
,
219 ExtensionRegistry
* extension_registry
) {
220 DCHECK(!context
->IsOffTheRecord());
221 return new ProcessManager(context
, context
, extension_registry
);
225 ProcessManager
* ProcessManager::CreateIncognitoForTesting(
226 BrowserContext
* incognito_context
,
227 BrowserContext
* original_context
,
228 ExtensionRegistry
* extension_registry
) {
229 DCHECK(incognito_context
->IsOffTheRecord());
230 DCHECK(!original_context
->IsOffTheRecord());
231 return new IncognitoProcessManager(incognito_context
,
236 ProcessManager::ProcessManager(BrowserContext
* context
,
237 BrowserContext
* original_context
,
238 ExtensionRegistry
* extension_registry
)
239 : extension_registry_(extension_registry
),
240 site_instance_(content::SiteInstance::Create(context
)),
241 browser_context_(context
),
242 startup_background_hosts_created_(false),
243 last_background_close_sequence_id_(0),
244 weak_ptr_factory_(this) {
245 // ExtensionRegistry is shared between incognito and regular contexts.
246 DCHECK_EQ(original_context
, extension_registry_
->browser_context());
247 extension_registry_
->AddObserver(this);
249 if (!context
->IsOffTheRecord()) {
250 // Only the original profile needs to listen for ready to create background
251 // pages for all spanning extensions.
253 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED
,
254 content::Source
<BrowserContext
>(original_context
));
257 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
,
258 content::Source
<BrowserContext
>(context
));
260 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE
,
261 content::Source
<BrowserContext
>(context
));
262 devtools_callback_
= base::Bind(&ProcessManager::OnDevToolsStateChanged
,
263 weak_ptr_factory_
.GetWeakPtr());
264 content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_
);
266 OnKeepaliveImpulseCheck();
269 ProcessManager::~ProcessManager() {
270 extension_registry_
->RemoveObserver(this);
271 CloseBackgroundHosts();
272 DCHECK(background_hosts_
.empty());
273 content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_
);
276 void ProcessManager::RegisterRenderFrameHost(
277 content::WebContents
* web_contents
,
278 content::RenderFrameHost
* render_frame_host
,
279 const Extension
* extension
) {
280 ExtensionRenderFrameData
* data
= &all_extension_frames_
[render_frame_host
];
281 data
->view_type
= GetViewType(web_contents
);
283 // Keep the lazy background page alive as long as any non-background-page
284 // extension views are visible. Keepalive count balanced in
285 // UnregisterRenderFrame.
286 AcquireLazyKeepaliveCountForFrame(render_frame_host
);
288 FOR_EACH_OBSERVER(ProcessManagerObserver
,
290 OnExtensionFrameRegistered(extension
->id(),
294 void ProcessManager::UnregisterRenderFrameHost(
295 content::RenderFrameHost
* render_frame_host
) {
296 ExtensionRenderFrames::iterator frame
=
297 all_extension_frames_
.find(render_frame_host
);
299 if (frame
!= all_extension_frames_
.end()) {
300 std::string extension_id
= GetExtensionID(render_frame_host
);
301 // Keepalive count, balanced in RegisterRenderFrame.
302 ReleaseLazyKeepaliveCountForFrame(render_frame_host
);
303 all_extension_frames_
.erase(frame
);
305 FOR_EACH_OBSERVER(ProcessManagerObserver
,
307 OnExtensionFrameUnregistered(extension_id
,
312 scoped_refptr
<content::SiteInstance
> ProcessManager::GetSiteInstanceForURL(
314 return make_scoped_refptr(site_instance_
->GetRelatedSiteInstance(url
));
317 const ProcessManager::FrameSet
ProcessManager::GetAllFrames() const {
319 for (const auto& key_value
: all_extension_frames_
)
320 result
.insert(key_value
.first
);
324 ProcessManager::FrameSet
ProcessManager::GetRenderFrameHostsForExtension(
325 const std::string
& extension_id
) {
327 scoped_refptr
<content::SiteInstance
> site_instance(GetSiteInstanceForURL(
328 Extension::GetBaseURLFromExtensionId(extension_id
)));
329 if (!site_instance
.get())
332 // Gather up all the frames for that site.
333 for (const auto& key_value
: all_extension_frames_
) {
334 if (key_value
.first
->GetSiteInstance() == site_instance
)
335 result
.insert(key_value
.first
);
341 void ProcessManager::AddObserver(ProcessManagerObserver
* observer
) {
342 observer_list_
.AddObserver(observer
);
345 void ProcessManager::RemoveObserver(ProcessManagerObserver
* observer
) {
346 observer_list_
.RemoveObserver(observer
);
349 bool ProcessManager::CreateBackgroundHost(const Extension
* extension
,
351 // Hosted apps are taken care of from BackgroundContentsService. Ignore them
353 if (extension
->is_hosted_app())
356 // Don't create hosts if the embedder doesn't allow it.
357 ProcessManagerDelegate
* delegate
=
358 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
359 if (delegate
&& !delegate
->IsBackgroundPageAllowed(browser_context_
))
362 // Don't create multiple background hosts for an extension.
363 if (GetBackgroundHostForExtension(extension
->id()))
364 return true; // TODO(kalman): return false here? It might break things...
366 ExtensionHost
* host
=
367 new ExtensionHost(extension
, GetSiteInstanceForURL(url
).get(), url
,
368 VIEW_TYPE_EXTENSION_BACKGROUND_PAGE
);
369 host
->CreateRenderViewSoon();
370 OnBackgroundHostCreated(host
);
374 void ProcessManager::MaybeCreateStartupBackgroundHosts() {
375 if (startup_background_hosts_created_
)
378 // The embedder might disallow background pages entirely.
379 ProcessManagerDelegate
* delegate
=
380 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
381 if (delegate
&& !delegate
->IsBackgroundPageAllowed(browser_context_
))
384 // The embedder might want to defer background page loading. For example,
385 // Chrome defers background page loading when it is launched to show the app
386 // list, then triggers a load later when a browser window opens.
388 delegate
->DeferCreatingStartupBackgroundHosts(browser_context_
))
391 CreateStartupBackgroundHosts();
392 startup_background_hosts_created_
= true;
394 // Background pages should only be loaded once. To prevent any further loads
395 // occurring, we remove the notification listeners.
396 BrowserContext
* original_context
=
397 ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context_
);
398 if (registrar_
.IsRegistered(
400 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED
,
401 content::Source
<BrowserContext
>(original_context
))) {
402 registrar_
.Remove(this,
403 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED
,
404 content::Source
<BrowserContext
>(original_context
));
408 ExtensionHost
* ProcessManager::GetBackgroundHostForExtension(
409 const std::string
& extension_id
) {
410 for (ExtensionHost
* host
: background_hosts_
) {
411 if (host
->extension_id() == extension_id
)
417 ExtensionHost
* ProcessManager::GetExtensionHostForRenderFrameHost(
418 content::RenderFrameHost
* render_frame_host
) {
419 content::WebContents
* web_contents
=
420 content::WebContents::FromRenderFrameHost(render_frame_host
);
421 for (ExtensionHost
* extension_host
: background_hosts_
) {
422 if (extension_host
->host_contents() == web_contents
)
423 return extension_host
;
428 bool ProcessManager::IsEventPageSuspended(const std::string
& extension_id
) {
429 return GetBackgroundHostForExtension(extension_id
) == nullptr;
432 bool ProcessManager::WakeEventPage(const std::string
& extension_id
,
433 const base::Callback
<void(bool)>& callback
) {
434 if (GetBackgroundHostForExtension(extension_id
)) {
435 // Run the callback immediately if the extension is already awake.
438 LazyBackgroundTaskQueue
* queue
=
439 LazyBackgroundTaskQueue::Get(browser_context_
);
440 queue
->AddPendingTask(browser_context_
, extension_id
,
441 base::Bind(&PropagateExtensionWakeResult
, callback
));
445 bool ProcessManager::IsBackgroundHostClosing(const std::string
& extension_id
) {
446 ExtensionHost
* host
= GetBackgroundHostForExtension(extension_id
);
447 return (host
&& background_page_data_
[extension_id
].is_closing
);
450 const Extension
* ProcessManager::GetExtensionForRenderFrameHost(
451 content::RenderFrameHost
* render_frame_host
) {
452 return extension_registry_
->enabled_extensions().GetByID(
453 GetExtensionID(render_frame_host
));
456 const Extension
* ProcessManager::GetExtensionForWebContents(
457 const content::WebContents
* web_contents
) {
458 if (!web_contents
->GetSiteInstance())
460 return extension_registry_
->enabled_extensions().GetByID(
461 GetExtensionIdForSiteInstance(web_contents
->GetSiteInstance()));
464 int ProcessManager::GetLazyKeepaliveCount(const Extension
* extension
) {
465 if (!BackgroundInfo::HasLazyBackgroundPage(extension
))
468 return background_page_data_
[extension
->id()].lazy_keepalive_count
;
471 void ProcessManager::IncrementLazyKeepaliveCount(const Extension
* extension
) {
472 if (BackgroundInfo::HasLazyBackgroundPage(extension
)) {
473 int& count
= background_page_data_
[extension
->id()].lazy_keepalive_count
;
475 OnLazyBackgroundPageActive(extension
->id());
479 void ProcessManager::DecrementLazyKeepaliveCount(const Extension
* extension
) {
480 if (BackgroundInfo::HasLazyBackgroundPage(extension
))
481 DecrementLazyKeepaliveCount(extension
->id());
484 // This implementation layers on top of the keepalive count. An impulse sets
485 // a per extension flag. On a regular interval that flag is checked. Changes
486 // from the flag not being set to set cause an IncrementLazyKeepaliveCount.
487 void ProcessManager::KeepaliveImpulse(const Extension
* extension
) {
488 if (!BackgroundInfo::HasLazyBackgroundPage(extension
))
491 BackgroundPageData
& bd
= background_page_data_
[extension
->id()];
493 if (!bd
.keepalive_impulse
) {
494 bd
.keepalive_impulse
= true;
495 if (!bd
.previous_keepalive_impulse
) {
496 IncrementLazyKeepaliveCount(extension
);
500 if (!keepalive_impulse_callback_for_testing_
.is_null()) {
501 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly
=
502 keepalive_impulse_callback_for_testing_
;
503 callback_may_clear_callbacks_reentrantly
.Run(extension
->id());
508 void ProcessManager::OnKeepaliveFromPlugin(int render_process_id
,
510 const std::string
& extension_id
) {
511 content::RenderFrameHost
* render_frame_host
=
512 content::RenderFrameHost::FromID(render_process_id
, render_frame_id
);
513 if (!render_frame_host
)
516 content::SiteInstance
* site_instance
= render_frame_host
->GetSiteInstance();
520 BrowserContext
* browser_context
= site_instance
->GetBrowserContext();
521 const Extension
* extension
=
522 ExtensionRegistry::Get(browser_context
)->enabled_extensions().GetByID(
527 ProcessManager::Get(browser_context
)->KeepaliveImpulse(extension
);
530 void ProcessManager::OnShouldSuspendAck(const std::string
& extension_id
,
531 uint64 sequence_id
) {
532 ExtensionHost
* host
= GetBackgroundHostForExtension(extension_id
);
534 sequence_id
== background_page_data_
[extension_id
].close_sequence_id
) {
535 host
->render_process_host()->Send(new ExtensionMsg_Suspend(extension_id
));
539 void ProcessManager::OnSuspendAck(const std::string
& extension_id
) {
540 background_page_data_
[extension_id
].is_closing
= true;
541 uint64 sequence_id
= background_page_data_
[extension_id
].close_sequence_id
;
542 base::MessageLoop::current()->PostDelayedTask(
544 base::Bind(&ProcessManager::CloseLazyBackgroundPageNow
,
545 weak_ptr_factory_
.GetWeakPtr(),
548 base::TimeDelta::FromMilliseconds(g_event_page_suspending_time_msec
));
551 void ProcessManager::OnNetworkRequestStarted(
552 content::RenderFrameHost
* render_frame_host
,
554 ExtensionHost
* host
= GetBackgroundHostForExtension(
555 GetExtensionID(render_frame_host
));
556 if (host
&& IsFrameInExtensionHost(host
, render_frame_host
)) {
557 IncrementLazyKeepaliveCount(host
->extension());
558 host
->OnNetworkRequestStarted(request_id
);
562 void ProcessManager::OnNetworkRequestDone(
563 content::RenderFrameHost
* render_frame_host
,
565 ExtensionHost
* host
= GetBackgroundHostForExtension(
566 GetExtensionID(render_frame_host
));
567 if (host
&& IsFrameInExtensionHost(host
, render_frame_host
)) {
568 host
->OnNetworkRequestDone(request_id
);
569 DecrementLazyKeepaliveCount(host
->extension());
573 void ProcessManager::CancelSuspend(const Extension
* extension
) {
574 bool& is_closing
= background_page_data_
[extension
->id()].is_closing
;
575 ExtensionHost
* host
= GetBackgroundHostForExtension(extension
->id());
576 if (host
&& is_closing
) {
578 host
->render_process_host()->Send(
579 new ExtensionMsg_CancelSuspend(extension
->id()));
580 // This increment / decrement is to simulate an instantaneous event. This
581 // has the effect of invalidating close_sequence_id, preventing any in
582 // progress closes from completing and starting a new close process if
584 IncrementLazyKeepaliveCount(extension
);
585 DecrementLazyKeepaliveCount(extension
);
589 void ProcessManager::CloseBackgroundHosts() {
590 STLDeleteElements(&background_hosts_
);
593 void ProcessManager::SetKeepaliveImpulseCallbackForTesting(
594 const ImpulseCallbackForTesting
& callback
) {
595 keepalive_impulse_callback_for_testing_
= callback
;
598 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting(
599 const ImpulseCallbackForTesting
& callback
) {
600 keepalive_impulse_decrement_callback_for_testing_
= callback
;
604 void ProcessManager::SetEventPageIdleTimeForTesting(unsigned idle_time_msec
) {
605 CHECK_GT(idle_time_msec
, 0u); // OnKeepaliveImpulseCheck requires non zero.
606 g_event_page_idle_time_msec
= idle_time_msec
;
610 void ProcessManager::SetEventPageSuspendingTimeForTesting(
611 unsigned suspending_time_msec
) {
612 g_event_page_suspending_time_msec
= suspending_time_msec
;
615 ////////////////////////////////////////////////////////////////////////////////
618 void ProcessManager::Observe(int type
,
619 const content::NotificationSource
& source
,
620 const content::NotificationDetails
& details
) {
621 TRACE_EVENT0("browser,startup", "ProcessManager::Observe");
623 case extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED
: {
624 // TODO(jamescook): Convert this to use ExtensionSystem::ready() instead
625 // of a notification.
626 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.ProcessManagerStartupHostsTime");
627 MaybeCreateStartupBackgroundHosts();
630 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
: {
631 ExtensionHost
* host
= content::Details
<ExtensionHost
>(details
).ptr();
632 if (background_hosts_
.erase(host
)) {
633 ClearBackgroundPageData(host
->extension()->id());
634 background_page_data_
[host
->extension()->id()].since_suspended
.reset(
635 new base::ElapsedTimer());
639 case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE
: {
640 ExtensionHost
* host
= content::Details
<ExtensionHost
>(details
).ptr();
641 if (host
->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE
) {
642 CloseBackgroundHost(host
);
651 void ProcessManager::OnExtensionLoaded(BrowserContext
* browser_context
,
652 const Extension
* extension
) {
653 if (ExtensionSystem::Get(browser_context
)->ready().is_signaled()) {
654 // The extension system is ready, so create the background host.
655 CreateBackgroundHostForExtensionLoad(this, extension
);
659 void ProcessManager::OnExtensionUnloaded(
660 BrowserContext
* browser_context
,
661 const Extension
* extension
,
662 UnloadedExtensionInfo::Reason reason
) {
663 ExtensionHost
* host
= GetBackgroundHostForExtension(extension
->id());
665 CloseBackgroundHost(host
);
666 UnregisterExtension(extension
->id());
669 void ProcessManager::CreateStartupBackgroundHosts() {
670 DCHECK(!startup_background_hosts_created_
);
671 for (const scoped_refptr
<const Extension
>& extension
:
672 extension_registry_
->enabled_extensions()) {
673 CreateBackgroundHostForExtensionLoad(this, extension
.get());
674 FOR_EACH_OBSERVER(ProcessManagerObserver
,
676 OnBackgroundHostStartup(extension
.get()));
680 void ProcessManager::OnBackgroundHostCreated(ExtensionHost
* host
) {
681 DCHECK_EQ(browser_context_
, host
->browser_context());
682 background_hosts_
.insert(host
);
684 if (BackgroundInfo::HasLazyBackgroundPage(host
->extension())) {
685 linked_ptr
<base::ElapsedTimer
> since_suspended(
686 background_page_data_
[host
->extension()->id()].
687 since_suspended
.release());
688 if (since_suspended
.get()) {
689 UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime",
690 since_suspended
->Elapsed());
693 FOR_EACH_OBSERVER(ProcessManagerObserver
, observer_list_
,
694 OnBackgroundHostCreated(host
));
697 void ProcessManager::CloseBackgroundHost(ExtensionHost
* host
) {
698 ExtensionId extension_id
= host
->extension_id();
699 CHECK(host
->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE
);
701 // |host| should deregister itself from our structures.
702 CHECK(background_hosts_
.find(host
) == background_hosts_
.end());
704 FOR_EACH_OBSERVER(ProcessManagerObserver
,
706 OnBackgroundHostClose(extension_id
));
709 void ProcessManager::AcquireLazyKeepaliveCountForFrame(
710 content::RenderFrameHost
* render_frame_host
) {
711 ExtensionRenderFrames::iterator it
=
712 all_extension_frames_
.find(render_frame_host
);
713 if (it
== all_extension_frames_
.end())
716 ExtensionRenderFrameData
& data
= it
->second
;
717 if (data
.CanKeepalive() && !data
.has_keepalive
) {
718 const Extension
* extension
=
719 GetExtensionForRenderFrameHost(render_frame_host
);
721 IncrementLazyKeepaliveCount(extension
);
722 data
.has_keepalive
= true;
727 void ProcessManager::ReleaseLazyKeepaliveCountForFrame(
728 content::RenderFrameHost
* render_frame_host
) {
729 ExtensionRenderFrames::iterator iter
=
730 all_extension_frames_
.find(render_frame_host
);
731 if (iter
== all_extension_frames_
.end())
734 ExtensionRenderFrameData
& data
= iter
->second
;
735 if (data
.CanKeepalive() && data
.has_keepalive
) {
736 const Extension
* extension
=
737 GetExtensionForRenderFrameHost(render_frame_host
);
739 DecrementLazyKeepaliveCount(extension
);
740 data
.has_keepalive
= false;
745 void ProcessManager::DecrementLazyKeepaliveCount(
746 const std::string
& extension_id
) {
747 int& count
= background_page_data_
[extension_id
].lazy_keepalive_count
;
749 !extension_registry_
->enabled_extensions().Contains(extension_id
));
751 // If we reach a zero keepalive count when the lazy background page is about
752 // to be closed, incrementing close_sequence_id will cancel the close
753 // sequence and cause the background page to linger. So check is_closing
754 // before initiating another close sequence.
755 if (--count
== 0 && !background_page_data_
[extension_id
].is_closing
) {
756 background_page_data_
[extension_id
].close_sequence_id
=
757 ++last_background_close_sequence_id_
;
758 base::MessageLoop::current()->PostDelayedTask(
760 base::Bind(&ProcessManager::OnLazyBackgroundPageIdle
,
761 weak_ptr_factory_
.GetWeakPtr(),
763 last_background_close_sequence_id_
),
764 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec
));
768 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse
769 // have been made for at least g_event_page_idle_time_msec. In the best case an
770 // impulse was made just before being cleared, and the decrement will occur
771 // g_event_page_idle_time_msec later, causing a 2 * g_event_page_idle_time_msec
772 // total time for extension to be shut down based on impulses. Worst case is
773 // an impulse just after a clear, adding one check cycle and resulting in 3x
775 void ProcessManager::OnKeepaliveImpulseCheck() {
776 for (BackgroundPageDataMap::iterator i
= background_page_data_
.begin();
777 i
!= background_page_data_
.end();
779 if (i
->second
.previous_keepalive_impulse
&& !i
->second
.keepalive_impulse
) {
780 DecrementLazyKeepaliveCount(i
->first
);
781 if (!keepalive_impulse_decrement_callback_for_testing_
.is_null()) {
782 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly
=
783 keepalive_impulse_decrement_callback_for_testing_
;
784 callback_may_clear_callbacks_reentrantly
.Run(i
->first
);
788 i
->second
.previous_keepalive_impulse
= i
->second
.keepalive_impulse
;
789 i
->second
.keepalive_impulse
= false;
792 // OnKeepaliveImpulseCheck() is always called in constructor, but in unit
793 // tests there will be no message loop. In that event don't schedule tasks.
794 if (base::MessageLoop::current()) {
795 base::MessageLoop::current()->PostDelayedTask(
797 base::Bind(&ProcessManager::OnKeepaliveImpulseCheck
,
798 weak_ptr_factory_
.GetWeakPtr()),
799 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec
));
803 void ProcessManager::OnLazyBackgroundPageIdle(const std::string
& extension_id
,
804 uint64 sequence_id
) {
805 ExtensionHost
* host
= GetBackgroundHostForExtension(extension_id
);
806 if (host
&& !background_page_data_
[extension_id
].is_closing
&&
807 sequence_id
== background_page_data_
[extension_id
].close_sequence_id
) {
808 // Tell the renderer we are about to close. This is a simple ping that the
809 // renderer will respond to. The purpose is to control sequencing: if the
810 // extension remains idle until the renderer responds with an ACK, then we
811 // know that the extension process is ready to shut down. If our
812 // close_sequence_id has already changed, then we would ignore the
813 // ShouldSuspendAck, so we don't send the ping.
814 host
->render_process_host()->Send(new ExtensionMsg_ShouldSuspend(
815 extension_id
, sequence_id
));
819 void ProcessManager::OnLazyBackgroundPageActive(
820 const std::string
& extension_id
) {
821 if (!background_page_data_
[extension_id
].is_closing
) {
822 // Cancel the current close sequence by changing the close_sequence_id,
823 // which causes us to ignore the next ShouldSuspendAck.
824 background_page_data_
[extension_id
].close_sequence_id
=
825 ++last_background_close_sequence_id_
;
829 void ProcessManager::CloseLazyBackgroundPageNow(const std::string
& extension_id
,
830 uint64 sequence_id
) {
831 ExtensionHost
* host
= GetBackgroundHostForExtension(extension_id
);
833 sequence_id
== background_page_data_
[extension_id
].close_sequence_id
) {
834 // Handle the case where the keepalive count was increased after the
835 // OnSuspend event was sent.
836 if (background_page_data_
[extension_id
].lazy_keepalive_count
> 0) {
837 CancelSuspend(host
->extension());
841 // Close remaining views.
842 std::vector
<content::RenderFrameHost
*> frames_to_close
;
843 for (const auto& key_value
: all_extension_frames_
) {
844 if (key_value
.second
.CanKeepalive() &&
845 GetExtensionID(key_value
.first
) == extension_id
) {
846 DCHECK(!key_value
.second
.has_keepalive
);
847 frames_to_close
.push_back(key_value
.first
);
850 for (content::RenderFrameHost
* frame
: frames_to_close
) {
851 content::WebContents::FromRenderFrameHost(frame
)->ClosePage();
852 // WebContents::ClosePage() may result in calling
853 // UnregisterRenderViewHost() asynchronously and may cause race conditions
854 // when the background page is reloaded.
855 // To avoid this, unregister the view now.
856 UnregisterRenderFrameHost(frame
);
859 ExtensionHost
* host
= GetBackgroundHostForExtension(extension_id
);
861 CloseBackgroundHost(host
);
865 void ProcessManager::OnDevToolsStateChanged(
866 content::DevToolsAgentHost
* agent_host
,
868 content::WebContents
* web_contents
= agent_host
->GetWebContents();
869 // Ignore unrelated notifications.
870 if (!web_contents
|| web_contents
->GetBrowserContext() != browser_context_
)
872 if (GetViewType(web_contents
) != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE
)
874 const Extension
* extension
=
875 extension_registry_
->enabled_extensions().GetByID(
876 GetExtensionIdForSiteInstance(web_contents
->GetSiteInstance()));
880 // Keep the lazy background page alive while it's being inspected.
881 CancelSuspend(extension
);
882 IncrementLazyKeepaliveCount(extension
);
884 DecrementLazyKeepaliveCount(extension
);
888 void ProcessManager::UnregisterExtension(const std::string
& extension_id
) {
889 // The lazy_keepalive_count may be greater than zero at this point because
890 // RenderFrameHosts are still alive. During extension reloading, they will
891 // decrement the lazy_keepalive_count to negative for the new extension
892 // instance when they are destroyed. Since we are erasing the background page
893 // data for the unloaded extension, unregister the RenderFrameHosts too.
894 for (ExtensionRenderFrames::iterator it
= all_extension_frames_
.begin();
895 it
!= all_extension_frames_
.end(); ) {
896 content::RenderFrameHost
* host
= it
->first
;
897 if (GetExtensionID(host
) == extension_id
) {
898 all_extension_frames_
.erase(it
++);
899 FOR_EACH_OBSERVER(ProcessManagerObserver
,
901 OnExtensionFrameUnregistered(extension_id
, host
));
907 background_page_data_
.erase(extension_id
);
910 void ProcessManager::ClearBackgroundPageData(const std::string
& extension_id
) {
911 background_page_data_
.erase(extension_id
);
913 // Re-register all RenderViews for this extension. We do this to restore
914 // the lazy_keepalive_count (if any) to properly reflect the number of open
916 for (const auto& key_value
: all_extension_frames_
) {
917 // Do not increment the count when |has_keepalive| is false
918 // (i.e. ReleaseLazyKeepaliveCountForView() was called).
919 if (GetExtensionID(key_value
.first
) == extension_id
&&
920 key_value
.second
.has_keepalive
) {
921 const Extension
* extension
=
922 GetExtensionForRenderFrameHost(key_value
.first
);
924 IncrementLazyKeepaliveCount(extension
);
930 // IncognitoProcessManager
933 IncognitoProcessManager::IncognitoProcessManager(
934 BrowserContext
* incognito_context
,
935 BrowserContext
* original_context
,
936 ExtensionRegistry
* extension_registry
)
937 : ProcessManager(incognito_context
, original_context
, extension_registry
) {
938 DCHECK(incognito_context
->IsOffTheRecord());
941 bool IncognitoProcessManager::CreateBackgroundHost(const Extension
* extension
,
943 if (IncognitoInfo::IsSplitMode(extension
)) {
944 if (ExtensionsBrowserClient::Get()->IsExtensionIncognitoEnabled(
945 extension
->id(), browser_context()))
946 return ProcessManager::CreateBackgroundHost(extension
, url
);
948 // Do nothing. If an extension is spanning, then its original-profile
949 // background page is shared with incognito, so we don't create another.
954 scoped_refptr
<content::SiteInstance
>
955 IncognitoProcessManager::GetSiteInstanceForURL(const GURL
& url
) {
956 const Extension
* extension
=
957 extension_registry_
->enabled_extensions().GetExtensionOrAppByURL(url
);
958 if (extension
&& !IncognitoInfo::IsSplitMode(extension
)) {
959 BrowserContext
* original_context
=
960 ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context());
961 return ProcessManager::Get(original_context
)->GetSiteInstanceForURL(url
);
964 return ProcessManager::GetSiteInstanceForURL(url
);
967 } // namespace extensions