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"
8 #include "base/command_line.h"
9 #include "base/lazy_instance.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/strings/string_number_conversions.h"
15 #include "base/time/time.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/devtools_agent_host.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/site_instance.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/browser/web_contents_delegate.h"
26 #include "content/public/browser/web_contents_observer.h"
27 #include "content/public/browser/web_contents_user_data.h"
28 #include "content/public/common/renderer_preferences.h"
29 #include "content/public/common/url_constants.h"
30 #include "extensions/browser/extension_host.h"
31 #include "extensions/browser/extension_registry.h"
32 #include "extensions/browser/extension_system.h"
33 #include "extensions/browser/extensions_browser_client.h"
34 #include "extensions/browser/notification_types.h"
35 #include "extensions/browser/process_manager_delegate.h"
36 #include "extensions/browser/process_manager_factory.h"
37 #include "extensions/browser/process_manager_observer.h"
38 #include "extensions/browser/view_type_utils.h"
39 #include "extensions/common/constants.h"
40 #include "extensions/common/extension.h"
41 #include "extensions/common/extension_messages.h"
42 #include "extensions/common/manifest_handlers/background_info.h"
43 #include "extensions/common/manifest_handlers/incognito_info.h"
44 #include "extensions/common/one_shot_event.h"
46 using content::BrowserContext
;
47 using content::RenderViewHost
;
48 using content::SiteInstance
;
49 using content::WebContents
;
51 namespace extensions
{
52 class RenderViewHostDestructionObserver
;
54 DEFINE_WEB_CONTENTS_USER_DATA_KEY(
55 extensions::RenderViewHostDestructionObserver
);
57 namespace extensions
{
61 // The time to delay between an extension becoming idle and
62 // sending a ShouldSuspend message.
63 // Note: Must be sufficiently larger (e.g. 2x) than
64 // kKeepaliveThrottleIntervalInSeconds in ppapi/proxy/plugin_globals.
65 unsigned g_event_page_idle_time_msec
= 10000;
67 // The time to delay between sending a ShouldSuspend message and
68 // sending a Suspend message.
69 unsigned g_event_page_suspending_time_msec
= 5000;
71 std::string
GetExtensionID(RenderViewHost
* render_view_host
) {
72 // This works for both apps and extensions because the site has been
73 // normalized to the extension URL for hosted apps.
74 content::SiteInstance
* site_instance
= render_view_host
->GetSiteInstance();
78 const GURL
& site_url
= site_instance
->GetSiteURL();
80 if (!site_url
.SchemeIs(kExtensionScheme
) &&
81 !site_url
.SchemeIs(content::kGuestScheme
))
84 return site_url
.host();
87 std::string
GetExtensionIDFromFrame(
88 content::RenderFrameHost
* render_frame_host
) {
89 // This works for both apps and extensions because the site has been
90 // normalized to the extension URL for apps.
91 if (!render_frame_host
->GetSiteInstance())
94 return render_frame_host
->GetSiteInstance()->GetSiteURL().host();
97 bool IsFrameInExtensionHost(ExtensionHost
* extension_host
,
98 content::RenderFrameHost
* render_frame_host
) {
99 return WebContents::FromRenderFrameHost(render_frame_host
) ==
100 extension_host
->host_contents();
103 void OnRenderViewHostUnregistered(BrowserContext
* context
,
104 RenderViewHost
* render_view_host
) {
105 content::NotificationService::current()->Notify(
106 extensions::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED
,
107 content::Source
<BrowserContext
>(context
),
108 content::Details
<RenderViewHost
>(render_view_host
));
111 // Incognito profiles use this process manager. It is mostly a shim that decides
112 // whether to fall back on the original profile's ProcessManager based
113 // on whether a given extension uses "split" or "spanning" incognito behavior.
114 class IncognitoProcessManager
: public ProcessManager
{
116 IncognitoProcessManager(BrowserContext
* incognito_context
,
117 BrowserContext
* original_context
,
118 ExtensionRegistry
* extension_registry
);
119 ~IncognitoProcessManager() override
{}
120 bool CreateBackgroundHost(const Extension
* extension
,
121 const GURL
& url
) override
;
122 scoped_refptr
<SiteInstance
> GetSiteInstanceForURL(const GURL
& url
) override
;
125 DISALLOW_COPY_AND_ASSIGN(IncognitoProcessManager
);
128 static void CreateBackgroundHostForExtensionLoad(
129 ProcessManager
* manager
, const Extension
* extension
) {
130 DVLOG(1) << "CreateBackgroundHostForExtensionLoad";
131 if (BackgroundInfo::HasPersistentBackgroundPage(extension
))
132 manager
->CreateBackgroundHost(extension
,
133 BackgroundInfo::GetBackgroundURL(extension
));
138 class RenderViewHostDestructionObserver
139 : public content::WebContentsObserver
,
140 public content::WebContentsUserData
<RenderViewHostDestructionObserver
> {
142 ~RenderViewHostDestructionObserver() override
{}
145 explicit RenderViewHostDestructionObserver(WebContents
* web_contents
)
146 : WebContentsObserver(web_contents
) {
147 BrowserContext
* context
= web_contents
->GetBrowserContext();
148 process_manager_
= ProcessManager::Get(context
);
151 friend class content::WebContentsUserData
<RenderViewHostDestructionObserver
>;
153 // content::WebContentsObserver overrides.
154 void RenderViewDeleted(RenderViewHost
* render_view_host
) override
{
155 process_manager_
->UnregisterRenderViewHost(render_view_host
);
158 ProcessManager
* process_manager_
;
160 DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestructionObserver
);
163 struct ProcessManager::BackgroundPageData
{
164 // The count of things keeping the lazy background page alive.
165 int lazy_keepalive_count
;
167 // Tracks if an impulse event has occured since the last polling check.
168 bool keepalive_impulse
;
169 bool previous_keepalive_impulse
;
171 // True if the page responded to the ShouldSuspend message and is currently
172 // dispatching the suspend event. During this time any events that arrive will
173 // cancel the suspend process and an onSuspendCanceled event will be
174 // dispatched to the page.
177 // Stores the value of the incremented
178 // ProcessManager::last_background_close_sequence_id_ whenever the extension
179 // is active. A copy of the ID is also passed in the callbacks and IPC
180 // messages leading up to CloseLazyBackgroundPageNow. The process is aborted
181 // if the IDs ever differ due to new activity.
182 uint64 close_sequence_id
;
184 // Keeps track of when this page was last suspended. Used for perf metrics.
185 linked_ptr
<base::ElapsedTimer
> since_suspended
;
188 : lazy_keepalive_count(0),
189 keepalive_impulse(false),
190 previous_keepalive_impulse(false),
192 close_sequence_id(0) {}
195 // Data of a RenderViewHost associated with an extension.
196 struct ProcessManager::ExtensionRenderViewData
{
197 // The type of the view.
198 extensions::ViewType view_type
;
200 // Whether the view is keeping the lazy background page alive or not.
203 ExtensionRenderViewData()
204 : view_type(VIEW_TYPE_INVALID
), has_keepalive(false) {}
206 // Returns whether the view can keep the lazy background page alive or not.
207 bool CanKeepalive() const {
209 case VIEW_TYPE_APP_WINDOW
:
210 case VIEW_TYPE_BACKGROUND_CONTENTS
:
211 case VIEW_TYPE_EXTENSION_DIALOG
:
212 case VIEW_TYPE_EXTENSION_INFOBAR
:
213 case VIEW_TYPE_EXTENSION_POPUP
:
214 case VIEW_TYPE_LAUNCHER_PAGE
:
215 case VIEW_TYPE_PANEL
:
216 case VIEW_TYPE_TAB_CONTENTS
:
217 case VIEW_TYPE_VIRTUAL_KEYBOARD
:
220 case VIEW_TYPE_INVALID
:
221 case VIEW_TYPE_EXTENSION_BACKGROUND_PAGE
:
234 ProcessManager
* ProcessManager::Get(BrowserContext
* context
) {
235 return ProcessManagerFactory::GetForBrowserContext(context
);
239 ProcessManager
* ProcessManager::Create(BrowserContext
* context
) {
240 ExtensionRegistry
* extension_registry
= ExtensionRegistry::Get(context
);
241 ExtensionsBrowserClient
* client
= ExtensionsBrowserClient::Get();
242 if (client
->IsGuestSession(context
)) {
243 // In the guest session, there is a single off-the-record context. Unlike
244 // a regular incognito mode, background pages of extensions must be
245 // created regardless of whether extensions use "spanning" or "split"
246 // incognito behavior.
247 BrowserContext
* original_context
= client
->GetOriginalContext(context
);
248 return new ProcessManager(context
, original_context
, extension_registry
);
251 if (context
->IsOffTheRecord()) {
252 BrowserContext
* original_context
= client
->GetOriginalContext(context
);
253 return new IncognitoProcessManager(
254 context
, original_context
, extension_registry
);
257 return new ProcessManager(context
, context
, extension_registry
);
261 ProcessManager
* ProcessManager::CreateForTesting(
262 BrowserContext
* context
,
263 ExtensionRegistry
* extension_registry
) {
264 DCHECK(!context
->IsOffTheRecord());
265 return new ProcessManager(context
, context
, extension_registry
);
269 ProcessManager
* ProcessManager::CreateIncognitoForTesting(
270 BrowserContext
* incognito_context
,
271 BrowserContext
* original_context
,
272 ExtensionRegistry
* extension_registry
) {
273 DCHECK(incognito_context
->IsOffTheRecord());
274 DCHECK(!original_context
->IsOffTheRecord());
275 return new IncognitoProcessManager(incognito_context
,
280 ProcessManager::ProcessManager(BrowserContext
* context
,
281 BrowserContext
* original_context
,
282 ExtensionRegistry
* extension_registry
)
283 : site_instance_(SiteInstance::Create(context
)),
284 extension_registry_(extension_registry
),
285 startup_background_hosts_created_(false),
286 devtools_callback_(base::Bind(&ProcessManager::OnDevToolsStateChanged
,
287 base::Unretained(this))),
288 last_background_close_sequence_id_(0),
289 weak_ptr_factory_(this) {
290 // ExtensionRegistry is shared between incognito and regular contexts.
291 DCHECK_EQ(original_context
, extension_registry_
->browser_context());
293 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED
,
294 content::Source
<BrowserContext
>(original_context
));
296 extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED
,
297 content::Source
<BrowserContext
>(original_context
));
299 extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
,
300 content::Source
<BrowserContext
>(original_context
));
302 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
,
303 content::Source
<BrowserContext
>(context
));
305 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE
,
306 content::Source
<BrowserContext
>(context
));
307 registrar_
.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
308 content::NotificationService::AllSources());
309 registrar_
.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED
,
310 content::NotificationService::AllSources());
312 content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_
);
314 OnKeepaliveImpulseCheck();
317 ProcessManager::~ProcessManager() {
318 CloseBackgroundHosts();
319 DCHECK(background_hosts_
.empty());
320 content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_
);
323 const ProcessManager::ViewSet
ProcessManager::GetAllViews() const {
325 for (ExtensionRenderViews::const_iterator iter
=
326 all_extension_views_
.begin();
327 iter
!= all_extension_views_
.end(); ++iter
) {
328 result
.insert(iter
->first
);
333 void ProcessManager::AddObserver(ProcessManagerObserver
* observer
) {
334 observer_list_
.AddObserver(observer
);
337 void ProcessManager::RemoveObserver(ProcessManagerObserver
* observer
) {
338 observer_list_
.RemoveObserver(observer
);
341 bool ProcessManager::CreateBackgroundHost(const Extension
* extension
,
343 // Hosted apps are taken care of from BackgroundContentsService. Ignore them
345 if (extension
->is_hosted_app())
348 // Don't create hosts if the embedder doesn't allow it.
349 ProcessManagerDelegate
* delegate
=
350 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
351 if (delegate
&& !delegate
->IsBackgroundPageAllowed(GetBrowserContext()))
354 // Don't create multiple background hosts for an extension.
355 if (GetBackgroundHostForExtension(extension
->id()))
356 return true; // TODO(kalman): return false here? It might break things...
358 ExtensionHost
* host
=
359 new ExtensionHost(extension
, GetSiteInstanceForURL(url
).get(), url
,
360 VIEW_TYPE_EXTENSION_BACKGROUND_PAGE
);
361 host
->CreateRenderViewSoon();
362 OnBackgroundHostCreated(host
);
366 ExtensionHost
* ProcessManager::GetBackgroundHostForExtension(
367 const std::string
& extension_id
) {
368 for (ExtensionHostSet::iterator iter
= background_hosts_
.begin();
369 iter
!= background_hosts_
.end(); ++iter
) {
370 ExtensionHost
* host
= *iter
;
371 if (host
->extension_id() == extension_id
)
377 std::set
<RenderViewHost
*> ProcessManager::GetRenderViewHostsForExtension(
378 const std::string
& extension_id
) {
379 std::set
<RenderViewHost
*> result
;
381 scoped_refptr
<SiteInstance
> site_instance(GetSiteInstanceForURL(
382 Extension::GetBaseURLFromExtensionId(extension_id
)));
383 if (!site_instance
.get())
386 // Gather up all the views for that site.
387 for (ExtensionRenderViews::iterator view
= all_extension_views_
.begin();
388 view
!= all_extension_views_
.end(); ++view
) {
389 if (view
->first
->GetSiteInstance() == site_instance
)
390 result
.insert(view
->first
);
396 const Extension
* ProcessManager::GetExtensionForRenderViewHost(
397 RenderViewHost
* render_view_host
) {
398 if (!render_view_host
->GetSiteInstance())
401 return extension_registry_
->enabled_extensions().GetByID(
402 GetExtensionID(render_view_host
));
405 void ProcessManager::AcquireLazyKeepaliveCountForView(
406 content::RenderViewHost
* render_view_host
) {
407 auto it
= all_extension_views_
.find(render_view_host
);
408 if (it
== all_extension_views_
.end())
411 ExtensionRenderViewData
* data
= &it
->second
;
412 if (data
->CanKeepalive() && !data
->has_keepalive
) {
413 const Extension
* extension
=
414 GetExtensionForRenderViewHost(render_view_host
);
416 IncrementLazyKeepaliveCount(extension
);
417 data
->has_keepalive
= true;
422 void ProcessManager::ReleaseLazyKeepaliveCountForView(
423 content::RenderViewHost
* render_view_host
) {
424 auto it
= all_extension_views_
.find(render_view_host
);
425 if (it
== all_extension_views_
.end())
428 ExtensionRenderViewData
* data
= &it
->second
;
429 if (data
->CanKeepalive() && data
->has_keepalive
) {
430 const Extension
* extension
=
431 GetExtensionForRenderViewHost(render_view_host
);
433 DecrementLazyKeepaliveCount(extension
);
434 data
->has_keepalive
= false;
439 void ProcessManager::UnregisterRenderViewHost(
440 RenderViewHost
* render_view_host
) {
441 ExtensionRenderViews::iterator view
=
442 all_extension_views_
.find(render_view_host
);
443 if (view
== all_extension_views_
.end())
446 OnRenderViewHostUnregistered(GetBrowserContext(), render_view_host
);
448 // Keepalive count, balanced in RegisterRenderViewHost.
449 ReleaseLazyKeepaliveCountForView(render_view_host
);
450 all_extension_views_
.erase(view
);
453 bool ProcessManager::RegisterRenderViewHost(RenderViewHost
* render_view_host
) {
454 const Extension
* extension
= GetExtensionForRenderViewHost(
459 WebContents
* web_contents
= WebContents::FromRenderViewHost(render_view_host
);
460 ExtensionRenderViewData
* data
= &all_extension_views_
[render_view_host
];
461 data
->view_type
= GetViewType(web_contents
);
463 // Keep the lazy background page alive as long as any non-background-page
464 // extension views are visible. Keepalive count balanced in
465 // UnregisterRenderViewHost.
466 AcquireLazyKeepaliveCountForView(render_view_host
);
470 scoped_refptr
<SiteInstance
> ProcessManager::GetSiteInstanceForURL(
472 return make_scoped_refptr(site_instance_
->GetRelatedSiteInstance(url
));
475 bool ProcessManager::IsBackgroundHostClosing(const std::string
& extension_id
) {
476 ExtensionHost
* host
= GetBackgroundHostForExtension(extension_id
);
477 return (host
&& background_page_data_
[extension_id
].is_closing
);
480 int ProcessManager::GetLazyKeepaliveCount(const Extension
* extension
) {
481 if (!BackgroundInfo::HasLazyBackgroundPage(extension
))
484 return background_page_data_
[extension
->id()].lazy_keepalive_count
;
487 void ProcessManager::IncrementLazyKeepaliveCount(const Extension
* extension
) {
488 if (!BackgroundInfo::HasLazyBackgroundPage(extension
))
491 int& count
= background_page_data_
[extension
->id()].lazy_keepalive_count
;
493 OnLazyBackgroundPageActive(extension
->id());
496 void ProcessManager::DecrementLazyKeepaliveCount(const Extension
* extension
) {
497 if (!BackgroundInfo::HasLazyBackgroundPage(extension
))
499 DecrementLazyKeepaliveCount(extension
->id());
502 void ProcessManager::DecrementLazyKeepaliveCount(
503 const std::string
& extension_id
) {
504 int& count
= background_page_data_
[extension_id
].lazy_keepalive_count
;
506 !extension_registry_
->enabled_extensions().Contains(extension_id
));
508 // If we reach a zero keepalive count when the lazy background page is about
509 // to be closed, incrementing close_sequence_id will cancel the close
510 // sequence and cause the background page to linger. So check is_closing
511 // before initiating another close sequence.
512 if (--count
== 0 && !background_page_data_
[extension_id
].is_closing
) {
513 background_page_data_
[extension_id
].close_sequence_id
=
514 ++last_background_close_sequence_id_
;
515 base::MessageLoop::current()->PostDelayedTask(
517 base::Bind(&ProcessManager::OnLazyBackgroundPageIdle
,
518 weak_ptr_factory_
.GetWeakPtr(),
520 last_background_close_sequence_id_
),
521 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec
));
525 // This implementation layers on top of the keepalive count. An impulse sets
526 // a per extension flag. On a regular interval that flag is checked. Changes
527 // from the flag not being set to set cause an IncrementLazyKeepaliveCount.
528 void ProcessManager::KeepaliveImpulse(const Extension
* extension
) {
529 if (!BackgroundInfo::HasLazyBackgroundPage(extension
))
532 BackgroundPageData
& bd
= background_page_data_
[extension
->id()];
534 if (!bd
.keepalive_impulse
) {
535 bd
.keepalive_impulse
= true;
536 if (!bd
.previous_keepalive_impulse
) {
537 IncrementLazyKeepaliveCount(extension
);
541 if (!keepalive_impulse_callback_for_testing_
.is_null()) {
542 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly
=
543 keepalive_impulse_callback_for_testing_
;
544 callback_may_clear_callbacks_reentrantly
.Run(extension
->id());
549 void ProcessManager::OnKeepaliveFromPlugin(int render_process_id
,
551 const std::string
& extension_id
) {
552 content::RenderFrameHost
* render_frame_host
=
553 content::RenderFrameHost::FromID(render_process_id
, render_frame_id
);
554 if (!render_frame_host
)
557 content::SiteInstance
* site_instance
= render_frame_host
->GetSiteInstance();
561 BrowserContext
* browser_context
= site_instance
->GetBrowserContext();
562 const Extension
* extension
=
563 ExtensionRegistry::Get(browser_context
)->enabled_extensions().GetByID(
568 ProcessManager::Get(browser_context
)->KeepaliveImpulse(extension
);
571 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse
572 // have been made for at least g_event_page_idle_time_msec. In the best case an
573 // impulse was made just before being cleared, and the decrement will occur
574 // g_event_page_idle_time_msec later, causing a 2 * g_event_page_idle_time_msec
575 // total time for extension to be shut down based on impulses. Worst case is
576 // an impulse just after a clear, adding one check cycle and resulting in 3x
578 void ProcessManager::OnKeepaliveImpulseCheck() {
579 for (BackgroundPageDataMap::iterator i
= background_page_data_
.begin();
580 i
!= background_page_data_
.end();
582 if (i
->second
.previous_keepalive_impulse
&& !i
->second
.keepalive_impulse
) {
583 DecrementLazyKeepaliveCount(i
->first
);
584 if (!keepalive_impulse_decrement_callback_for_testing_
.is_null()) {
585 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly
=
586 keepalive_impulse_decrement_callback_for_testing_
;
587 callback_may_clear_callbacks_reentrantly
.Run(i
->first
);
591 i
->second
.previous_keepalive_impulse
= i
->second
.keepalive_impulse
;
592 i
->second
.keepalive_impulse
= false;
595 // OnKeepaliveImpulseCheck() is always called in constructor, but in unit
596 // tests there will be no message loop. In that event don't schedule tasks.
597 if (base::MessageLoop::current()) {
598 base::MessageLoop::current()->PostDelayedTask(
600 base::Bind(&ProcessManager::OnKeepaliveImpulseCheck
,
601 weak_ptr_factory_
.GetWeakPtr()),
602 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec
));
606 void ProcessManager::OnLazyBackgroundPageIdle(const std::string
& extension_id
,
607 uint64 sequence_id
) {
608 ExtensionHost
* host
= GetBackgroundHostForExtension(extension_id
);
609 if (host
&& !background_page_data_
[extension_id
].is_closing
&&
610 sequence_id
== background_page_data_
[extension_id
].close_sequence_id
) {
611 // Tell the renderer we are about to close. This is a simple ping that the
612 // renderer will respond to. The purpose is to control sequencing: if the
613 // extension remains idle until the renderer responds with an ACK, then we
614 // know that the extension process is ready to shut down. If our
615 // close_sequence_id has already changed, then we would ignore the
616 // ShouldSuspendAck, so we don't send the ping.
617 host
->render_view_host()->Send(new ExtensionMsg_ShouldSuspend(
618 extension_id
, sequence_id
));
622 void ProcessManager::OnLazyBackgroundPageActive(
623 const std::string
& extension_id
) {
624 if (!background_page_data_
[extension_id
].is_closing
) {
625 // Cancel the current close sequence by changing the close_sequence_id,
626 // which causes us to ignore the next ShouldSuspendAck.
627 background_page_data_
[extension_id
].close_sequence_id
=
628 ++last_background_close_sequence_id_
;
632 void ProcessManager::OnShouldSuspendAck(const std::string
& extension_id
,
633 uint64 sequence_id
) {
634 ExtensionHost
* host
= GetBackgroundHostForExtension(extension_id
);
636 sequence_id
== background_page_data_
[extension_id
].close_sequence_id
) {
637 host
->render_view_host()->Send(new ExtensionMsg_Suspend(extension_id
));
641 void ProcessManager::OnSuspendAck(const std::string
& extension_id
) {
642 background_page_data_
[extension_id
].is_closing
= true;
643 uint64 sequence_id
= background_page_data_
[extension_id
].close_sequence_id
;
644 base::MessageLoop::current()->PostDelayedTask(
646 base::Bind(&ProcessManager::CloseLazyBackgroundPageNow
,
647 weak_ptr_factory_
.GetWeakPtr(),
650 base::TimeDelta::FromMilliseconds(g_event_page_suspending_time_msec
));
653 void ProcessManager::CloseLazyBackgroundPageNow(const std::string
& extension_id
,
654 uint64 sequence_id
) {
655 ExtensionHost
* host
= GetBackgroundHostForExtension(extension_id
);
657 sequence_id
== background_page_data_
[extension_id
].close_sequence_id
) {
658 // Close remaining views.
659 std::vector
<RenderViewHost
*> views_to_close
;
660 for (const auto& view
: all_extension_views_
) {
661 if (view
.second
.CanKeepalive() &&
662 GetExtensionID(view
.first
) == extension_id
) {
663 DCHECK(!view
.second
.has_keepalive
);
664 views_to_close
.push_back(view
.first
);
667 for (auto view
: views_to_close
) {
669 // RenderViewHost::ClosePage() may result in calling
670 // UnregisterRenderViewHost() asynchronously and may cause race conditions
671 // when the background page is reloaded.
672 // To avoid this, unregister the view now.
673 UnregisterRenderViewHost(view
);
676 ExtensionHost
* host
= GetBackgroundHostForExtension(extension_id
);
678 CloseBackgroundHost(host
);
682 void ProcessManager::OnNetworkRequestStarted(
683 content::RenderFrameHost
* render_frame_host
,
685 ExtensionHost
* host
= GetBackgroundHostForExtension(
686 GetExtensionIDFromFrame(render_frame_host
));
687 if (host
&& IsFrameInExtensionHost(host
, render_frame_host
)) {
688 IncrementLazyKeepaliveCount(host
->extension());
689 host
->OnNetworkRequestStarted(request_id
);
693 void ProcessManager::OnNetworkRequestDone(
694 content::RenderFrameHost
* render_frame_host
,
696 ExtensionHost
* host
= GetBackgroundHostForExtension(
697 GetExtensionIDFromFrame(render_frame_host
));
698 if (host
&& IsFrameInExtensionHost(host
, render_frame_host
)) {
699 host
->OnNetworkRequestDone(request_id
);
700 DecrementLazyKeepaliveCount(host
->extension());
704 void ProcessManager::CancelSuspend(const Extension
* extension
) {
705 bool& is_closing
= background_page_data_
[extension
->id()].is_closing
;
706 ExtensionHost
* host
= GetBackgroundHostForExtension(extension
->id());
707 if (host
&& is_closing
) {
709 host
->render_view_host()->Send(
710 new ExtensionMsg_CancelSuspend(extension
->id()));
711 // This increment / decrement is to simulate an instantaneous event. This
712 // has the effect of invalidating close_sequence_id, preventing any in
713 // progress closes from completing and starting a new close process if
715 IncrementLazyKeepaliveCount(extension
);
716 DecrementLazyKeepaliveCount(extension
);
720 void ProcessManager::CloseBackgroundHosts() {
721 for (ExtensionHostSet::iterator iter
= background_hosts_
.begin();
722 iter
!= background_hosts_
.end();) {
723 ExtensionHostSet::iterator current
= iter
++;
728 content::BrowserContext
* ProcessManager::GetBrowserContext() const {
729 return site_instance_
->GetBrowserContext();
732 void ProcessManager::SetKeepaliveImpulseCallbackForTesting(
733 const ImpulseCallbackForTesting
& callback
) {
734 keepalive_impulse_callback_for_testing_
= callback
;
737 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting(
738 const ImpulseCallbackForTesting
& callback
) {
739 keepalive_impulse_decrement_callback_for_testing_
= callback
;
743 void ProcessManager::SetEventPageIdleTimeForTesting(unsigned idle_time_msec
) {
744 CHECK_GT(idle_time_msec
, 0u); // OnKeepaliveImpulseCheck requires non zero.
745 g_event_page_idle_time_msec
= idle_time_msec
;
749 void ProcessManager::SetEventPageSuspendingTimeForTesting(
750 unsigned suspending_time_msec
) {
751 g_event_page_suspending_time_msec
= suspending_time_msec
;
754 void ProcessManager::Observe(int type
,
755 const content::NotificationSource
& source
,
756 const content::NotificationDetails
& details
) {
758 case extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED
: {
759 // TODO(jamescook): Convert this to use ExtensionSystem::ready() instead
760 // of a notification.
761 const base::TimeTicks start_time
= base::TimeTicks::Now();
762 MaybeCreateStartupBackgroundHosts();
763 UMA_HISTOGRAM_TIMES("Extensions.ProcessManagerStartupHostsTime",
764 base::TimeTicks::Now() - start_time
);
768 case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED
: {
769 BrowserContext
* context
= content::Source
<BrowserContext
>(source
).ptr();
770 ExtensionSystem
* system
= ExtensionSystem::Get(context
);
771 if (system
->ready().is_signaled()) {
772 // The extension system is ready, so create the background host.
773 const Extension
* extension
=
774 content::Details
<const Extension
>(details
).ptr();
775 CreateBackgroundHostForExtensionLoad(this, extension
);
780 case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED
: {
781 const Extension
* extension
=
782 content::Details
<UnloadedExtensionInfo
>(details
)->extension
;
783 for (ExtensionHostSet::iterator iter
= background_hosts_
.begin();
784 iter
!= background_hosts_
.end(); ++iter
) {
785 ExtensionHost
* host
= *iter
;
786 if (host
->extension_id() == extension
->id()) {
787 CloseBackgroundHost(host
);
791 UnregisterExtension(extension
->id());
795 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
: {
796 ExtensionHost
* host
= content::Details
<ExtensionHost
>(details
).ptr();
797 if (background_hosts_
.erase(host
)) {
798 ClearBackgroundPageData(host
->extension()->id());
799 background_page_data_
[host
->extension()->id()].since_suspended
.reset(
800 new base::ElapsedTimer());
805 case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE
: {
806 ExtensionHost
* host
= content::Details
<ExtensionHost
>(details
).ptr();
807 if (host
->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE
) {
808 CloseBackgroundHost(host
);
813 case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
: {
814 // We get this notification both for new WebContents and when one
815 // has its RenderViewHost replaced (e.g. when a user does a cross-site
816 // navigation away from an extension URL). For the replaced case, we must
817 // unregister the old RVH so it doesn't count as an active view that would
818 // keep the event page alive.
819 WebContents
* contents
= content::Source
<WebContents
>(source
).ptr();
820 if (contents
->GetBrowserContext() != GetBrowserContext())
823 typedef std::pair
<RenderViewHost
*, RenderViewHost
*> RVHPair
;
824 RVHPair
* switched_details
= content::Details
<RVHPair
>(details
).ptr();
825 if (switched_details
->first
)
826 UnregisterRenderViewHost(switched_details
->first
);
828 // The above will unregister a RVH when it gets swapped out with a new
829 // one. However we need to watch the WebContents to know when a RVH is
830 // deleted because the WebContents has gone away.
831 if (RegisterRenderViewHost(switched_details
->second
)) {
832 RenderViewHostDestructionObserver::CreateForWebContents(contents
);
837 case content::NOTIFICATION_WEB_CONTENTS_CONNECTED
: {
838 WebContents
* contents
= content::Source
<WebContents
>(source
).ptr();
839 if (contents
->GetBrowserContext() != GetBrowserContext())
841 const Extension
* extension
= GetExtensionForRenderViewHost(
842 contents
->GetRenderViewHost());
846 // RegisterRenderViewHost is called too early (before the process is
847 // available), so we need to wait until now to notify.
848 content::NotificationService::current()->Notify(
849 extensions::NOTIFICATION_EXTENSION_VIEW_REGISTERED
,
850 content::Source
<BrowserContext
>(GetBrowserContext()),
851 content::Details
<RenderViewHost
>(contents
->GetRenderViewHost()));
860 void ProcessManager::OnDevToolsStateChanged(
861 content::DevToolsAgentHost
* agent_host
,
863 WebContents
* web_contents
= agent_host
->GetWebContents();
864 // Ignore unrelated notifications.
865 if (!web_contents
|| web_contents
->GetBrowserContext() != GetBrowserContext())
867 if (GetViewType(web_contents
) != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE
)
869 const Extension
* extension
=
870 GetExtensionForRenderViewHost(web_contents
->GetRenderViewHost());
874 // Keep the lazy background page alive while it's being inspected.
875 CancelSuspend(extension
);
876 IncrementLazyKeepaliveCount(extension
);
878 DecrementLazyKeepaliveCount(extension
);
882 void ProcessManager::MaybeCreateStartupBackgroundHosts() {
883 if (startup_background_hosts_created_
)
886 // The embedder might disallow background pages entirely.
887 ProcessManagerDelegate
* delegate
=
888 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
889 if (delegate
&& !delegate
->IsBackgroundPageAllowed(GetBrowserContext()))
892 // The embedder might want to defer background page loading. For example,
893 // Chrome defers background page loading when it is launched to show the app
894 // list, then triggers a load later when a browser window opens.
896 delegate
->DeferCreatingStartupBackgroundHosts(GetBrowserContext()))
899 CreateStartupBackgroundHosts();
900 startup_background_hosts_created_
= true;
902 // Background pages should only be loaded once. To prevent any further loads
903 // occurring, we remove the notification listeners.
904 BrowserContext
* original_context
=
905 ExtensionsBrowserClient::Get()->GetOriginalContext(GetBrowserContext());
906 if (registrar_
.IsRegistered(
908 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED
,
909 content::Source
<BrowserContext
>(original_context
))) {
910 registrar_
.Remove(this,
911 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED
,
912 content::Source
<BrowserContext
>(original_context
));
916 void ProcessManager::CreateStartupBackgroundHosts() {
917 DCHECK(!startup_background_hosts_created_
);
918 const ExtensionSet
& enabled_extensions
=
919 extension_registry_
->enabled_extensions();
920 for (ExtensionSet::const_iterator extension
= enabled_extensions
.begin();
921 extension
!= enabled_extensions
.end();
923 CreateBackgroundHostForExtensionLoad(this, extension
->get());
925 FOR_EACH_OBSERVER(ProcessManagerObserver
,
927 OnBackgroundHostStartup(extension
->get()));
931 void ProcessManager::OnBackgroundHostCreated(ExtensionHost
* host
) {
932 DCHECK_EQ(GetBrowserContext(), host
->browser_context());
933 background_hosts_
.insert(host
);
935 if (BackgroundInfo::HasLazyBackgroundPage(host
->extension())) {
936 linked_ptr
<base::ElapsedTimer
> since_suspended(
937 background_page_data_
[host
->extension()->id()].
938 since_suspended
.release());
939 if (since_suspended
.get()) {
940 UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime",
941 since_suspended
->Elapsed());
944 FOR_EACH_OBSERVER(ProcessManagerObserver
, observer_list_
,
945 OnBackgroundHostCreated(host
));
948 void ProcessManager::CloseBackgroundHost(ExtensionHost
* host
) {
949 ExtensionId extension_id
= host
->extension_id();
950 CHECK(host
->extension_host_type() ==
951 VIEW_TYPE_EXTENSION_BACKGROUND_PAGE
);
953 // |host| should deregister itself from our structures.
954 CHECK(background_hosts_
.find(host
) == background_hosts_
.end());
956 FOR_EACH_OBSERVER(ProcessManagerObserver
,
958 OnBackgroundHostClose(extension_id
));
961 void ProcessManager::UnregisterExtension(const std::string
& extension_id
) {
962 // The lazy_keepalive_count may be greater than zero at this point because
963 // RenderViewHosts are still alive. During extension reloading, they will
964 // decrement the lazy_keepalive_count to negative for the new extension
965 // instance when they are destroyed. Since we are erasing the background page
966 // data for the unloaded extension, unregister the RenderViewHosts too.
967 BrowserContext
* context
= GetBrowserContext();
968 for (ExtensionRenderViews::iterator it
= all_extension_views_
.begin();
969 it
!= all_extension_views_
.end(); ) {
970 if (GetExtensionID(it
->first
) == extension_id
) {
971 OnRenderViewHostUnregistered(context
, it
->first
);
972 all_extension_views_
.erase(it
++);
978 background_page_data_
.erase(extension_id
);
981 void ProcessManager::ClearBackgroundPageData(const std::string
& extension_id
) {
982 background_page_data_
.erase(extension_id
);
984 // Re-register all RenderViews for this extension. We do this to restore
985 // the lazy_keepalive_count (if any) to properly reflect the number of open
987 for (ExtensionRenderViews::const_iterator it
= all_extension_views_
.begin();
988 it
!= all_extension_views_
.end(); ++it
) {
989 RenderViewHost
* view
= it
->first
;
990 const ExtensionRenderViewData
& data
= it
->second
;
991 // Do not increment the count when |has_keepalive| is false
992 // (i.e. ReleaseLazyKeepaliveCountForView() was called).
993 if (GetExtensionID(view
) == extension_id
&& data
.has_keepalive
) {
994 const Extension
* extension
= GetExtensionForRenderViewHost(view
);
996 IncrementLazyKeepaliveCount(extension
);
1002 // IncognitoProcessManager
1005 IncognitoProcessManager::IncognitoProcessManager(
1006 BrowserContext
* incognito_context
,
1007 BrowserContext
* original_context
,
1008 ExtensionRegistry
* extension_registry
)
1009 : ProcessManager(incognito_context
, original_context
, extension_registry
) {
1010 DCHECK(incognito_context
->IsOffTheRecord());
1012 // The original profile will have its own ProcessManager to
1013 // load the background pages of the spanning extensions. This process
1014 // manager need only worry about the split mode extensions, which is handled
1015 // in the NOTIFICATION_BROWSER_WINDOW_READY notification handler.
1016 registrar_
.Remove(this,
1017 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED
,
1018 content::Source
<BrowserContext
>(original_context
));
1021 bool IncognitoProcessManager::CreateBackgroundHost(const Extension
* extension
,
1023 if (IncognitoInfo::IsSplitMode(extension
)) {
1024 if (ExtensionsBrowserClient::Get()->IsExtensionIncognitoEnabled(
1025 extension
->id(), GetBrowserContext()))
1026 return ProcessManager::CreateBackgroundHost(extension
, url
);
1028 // Do nothing. If an extension is spanning, then its original-profile
1029 // background page is shared with incognito, so we don't create another.
1034 scoped_refptr
<SiteInstance
> IncognitoProcessManager::GetSiteInstanceForURL(
1036 const Extension
* extension
=
1037 extension_registry_
->enabled_extensions().GetExtensionOrAppByURL(url
);
1038 if (extension
&& !IncognitoInfo::IsSplitMode(extension
)) {
1039 BrowserContext
* original_context
=
1040 ExtensionsBrowserClient::Get()->GetOriginalContext(GetBrowserContext());
1041 return ProcessManager::Get(original_context
)->GetSiteInstanceForURL(url
);
1044 return ProcessManager::GetSiteInstanceForURL(url
);
1047 } // namespace extensions