Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / extensions / browser / process_manager.cc
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.
4
5 #include "extensions/browser/process_manager.h"
6
7 #include "base/bind.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.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_observer.h"
37 #include "extensions/browser/view_type_utils.h"
38 #include "extensions/common/constants.h"
39 #include "extensions/common/extension.h"
40 #include "extensions/common/extension_messages.h"
41 #include "extensions/common/manifest_handlers/background_info.h"
42 #include "extensions/common/manifest_handlers/incognito_info.h"
43 #include "extensions/common/one_shot_event.h"
44
45 using content::BrowserContext;
46 using content::RenderViewHost;
47 using content::SiteInstance;
48 using content::WebContents;
49
50 namespace extensions {
51 class RenderViewHostDestructionObserver;
52 }
53 DEFINE_WEB_CONTENTS_USER_DATA_KEY(
54     extensions::RenderViewHostDestructionObserver);
55
56 namespace extensions {
57
58 namespace {
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
70 std::string GetExtensionID(RenderViewHost* render_view_host) {
71   // This works for both apps and extensions because the site has been
72   // normalized to the extension URL for hosted apps.
73   content::SiteInstance* site_instance = render_view_host->GetSiteInstance();
74   if (!site_instance)
75     return std::string();
76
77   const GURL& site_url = site_instance->GetSiteURL();
78
79   if (!site_url.SchemeIs(kExtensionScheme) &&
80       !site_url.SchemeIs(content::kGuestScheme))
81     return std::string();
82
83   return site_url.host();
84 }
85
86 std::string GetExtensionIDFromFrame(
87     content::RenderFrameHost* render_frame_host) {
88   // This works for both apps and extensions because the site has been
89   // normalized to the extension URL for apps.
90   if (!render_frame_host->GetSiteInstance())
91     return std::string();
92
93   return render_frame_host->GetSiteInstance()->GetSiteURL().host();
94 }
95
96 bool IsFrameInExtensionHost(ExtensionHost* extension_host,
97                             content::RenderFrameHost* render_frame_host) {
98   return WebContents::FromRenderFrameHost(render_frame_host) ==
99       extension_host->host_contents();
100 }
101
102 void OnRenderViewHostUnregistered(BrowserContext* context,
103                                   RenderViewHost* render_view_host) {
104   content::NotificationService::current()->Notify(
105       extensions::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
106       content::Source<BrowserContext>(context),
107       content::Details<RenderViewHost>(render_view_host));
108 }
109
110 // Incognito profiles use this process manager. It is mostly a shim that decides
111 // whether to fall back on the original profile's ProcessManager based
112 // on whether a given extension uses "split" or "spanning" incognito behavior.
113 class IncognitoProcessManager : public ProcessManager {
114  public:
115   IncognitoProcessManager(BrowserContext* incognito_context,
116                           BrowserContext* original_context,
117                           ProcessManager* original_manager,
118                           ExtensionRegistry* extension_registry);
119   virtual ~IncognitoProcessManager() {}
120   virtual bool CreateBackgroundHost(const Extension* extension,
121                                     const GURL& url) OVERRIDE;
122   virtual SiteInstance* GetSiteInstanceForURL(const GURL& url) OVERRIDE;
123
124  private:
125   ProcessManager* original_manager_;
126
127   DISALLOW_COPY_AND_ASSIGN(IncognitoProcessManager);
128 };
129
130 static void CreateBackgroundHostForExtensionLoad(
131     ProcessManager* manager, const Extension* extension) {
132   DVLOG(1) << "CreateBackgroundHostForExtensionLoad";
133   if (BackgroundInfo::HasPersistentBackgroundPage(extension))
134     manager->CreateBackgroundHost(extension,
135                                   BackgroundInfo::GetBackgroundURL(extension));
136 }
137
138 }  // namespace
139
140 class RenderViewHostDestructionObserver
141     : public content::WebContentsObserver,
142       public content::WebContentsUserData<RenderViewHostDestructionObserver> {
143  public:
144   virtual ~RenderViewHostDestructionObserver() {}
145
146  private:
147   explicit RenderViewHostDestructionObserver(WebContents* web_contents)
148       : WebContentsObserver(web_contents) {
149     BrowserContext* context = web_contents->GetBrowserContext();
150     process_manager_ = ExtensionSystem::Get(context)->process_manager();
151   }
152
153   friend class content::WebContentsUserData<RenderViewHostDestructionObserver>;
154
155   // content::WebContentsObserver overrides.
156   virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE {
157     process_manager_->UnregisterRenderViewHost(render_view_host);
158   }
159
160   ProcessManager* process_manager_;
161
162   DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestructionObserver);
163 };
164
165 struct ProcessManager::BackgroundPageData {
166   // The count of things keeping the lazy background page alive.
167   int lazy_keepalive_count;
168
169   // Tracks if an impulse event has occured since the last polling check.
170   bool keepalive_impulse;
171   bool previous_keepalive_impulse;
172
173   // True if the page responded to the ShouldSuspend message and is currently
174   // dispatching the suspend event. During this time any events that arrive will
175   // cancel the suspend process and an onSuspendCanceled event will be
176   // dispatched to the page.
177   bool is_closing;
178
179   // Stores the value of the incremented
180   // ProcessManager::last_background_close_sequence_id_ whenever the extension
181   // is active. A copy of the ID is also passed in the callbacks and IPC
182   // messages leading up to CloseLazyBackgroundPageNow. The process is aborted
183   // if the IDs ever differ due to new activity.
184   uint64 close_sequence_id;
185
186   // Keeps track of when this page was last suspended. Used for perf metrics.
187   linked_ptr<base::ElapsedTimer> since_suspended;
188
189   BackgroundPageData()
190       : lazy_keepalive_count(0),
191         keepalive_impulse(false),
192         previous_keepalive_impulse(false),
193         is_closing(false),
194         close_sequence_id(0) {}
195 };
196
197 //
198 // ProcessManager
199 //
200
201 // static
202 ProcessManager* ProcessManager::Create(BrowserContext* context) {
203   ExtensionRegistry* extension_registry = ExtensionRegistry::Get(context);
204   ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get();
205   if (client->IsGuestSession(context)) {
206     // In the guest session, there is a single off-the-record context.  Unlike
207     // a regular incognito mode, background pages of extensions must be
208     // created regardless of whether extensions use "spanning" or "split"
209     // incognito behavior.
210     BrowserContext* original_context = client->GetOriginalContext(context);
211     return new ProcessManager(context, original_context, extension_registry);
212   }
213
214   if (context->IsOffTheRecord()) {
215     BrowserContext* original_context = client->GetOriginalContext(context);
216     ProcessManager* original_manager =
217         ExtensionSystem::Get(original_context)->process_manager();
218     return new IncognitoProcessManager(
219         context, original_context, original_manager, extension_registry);
220   }
221
222   return new ProcessManager(context, context, extension_registry);
223 }
224
225 // static
226 ProcessManager* ProcessManager::CreateForTesting(
227     BrowserContext* context,
228     ExtensionRegistry* extension_registry) {
229   DCHECK(!context->IsOffTheRecord());
230   return new ProcessManager(context, context, extension_registry);
231 }
232
233 // static
234 ProcessManager* ProcessManager::CreateIncognitoForTesting(
235     BrowserContext* incognito_context,
236     BrowserContext* original_context,
237     ProcessManager* original_manager,
238     ExtensionRegistry* extension_registry) {
239   DCHECK(incognito_context->IsOffTheRecord());
240   DCHECK(!original_context->IsOffTheRecord());
241   return new IncognitoProcessManager(incognito_context,
242                                      original_context,
243                                      original_manager,
244                                      extension_registry);
245 }
246
247 ProcessManager::ProcessManager(BrowserContext* context,
248                                BrowserContext* original_context,
249                                ExtensionRegistry* extension_registry)
250     : site_instance_(SiteInstance::Create(context)),
251       extension_registry_(extension_registry),
252       startup_background_hosts_created_(false),
253       devtools_callback_(base::Bind(&ProcessManager::OnDevToolsStateChanged,
254                                     base::Unretained(this))),
255       last_background_close_sequence_id_(0),
256       weak_ptr_factory_(this) {
257   // ExtensionRegistry is shared between incognito and regular contexts.
258   DCHECK_EQ(original_context, extension_registry_->browser_context());
259   registrar_.Add(this,
260                  extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
261                  content::Source<BrowserContext>(original_context));
262   registrar_.Add(this,
263                  extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
264                  content::Source<BrowserContext>(original_context));
265   registrar_.Add(this,
266                  extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
267                  content::Source<BrowserContext>(original_context));
268   registrar_.Add(this,
269                  extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
270                  content::Source<BrowserContext>(context));
271   registrar_.Add(this,
272                  extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
273                  content::Source<BrowserContext>(context));
274   registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
275                  content::NotificationService::AllSources());
276   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
277                  content::NotificationService::AllSources());
278
279   content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_);
280
281   OnKeepaliveImpulseCheck();
282 }
283
284 ProcessManager::~ProcessManager() {
285   CloseBackgroundHosts();
286   DCHECK(background_hosts_.empty());
287   content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_);
288 }
289
290 const ProcessManager::ViewSet ProcessManager::GetAllViews() const {
291   ViewSet result;
292   for (ExtensionRenderViews::const_iterator iter =
293            all_extension_views_.begin();
294        iter != all_extension_views_.end(); ++iter) {
295     result.insert(iter->first);
296   }
297   return result;
298 }
299
300 void ProcessManager::AddObserver(ProcessManagerObserver* observer) {
301   observer_list_.AddObserver(observer);
302 }
303
304 void ProcessManager::RemoveObserver(ProcessManagerObserver* observer) {
305   observer_list_.RemoveObserver(observer);
306 }
307
308 bool ProcessManager::CreateBackgroundHost(const Extension* extension,
309                                           const GURL& url) {
310   // Hosted apps are taken care of from BackgroundContentsService. Ignore them
311   // here.
312   if (extension->is_hosted_app())
313     return false;
314
315   // Don't create hosts if the embedder doesn't allow it.
316   ProcessManagerDelegate* delegate =
317       ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
318   if (delegate && !delegate->IsBackgroundPageAllowed(GetBrowserContext()))
319     return false;
320
321   // Don't create multiple background hosts for an extension.
322   if (GetBackgroundHostForExtension(extension->id()))
323     return true;  // TODO(kalman): return false here? It might break things...
324
325   ExtensionHost* host =
326       new ExtensionHost(extension, GetSiteInstanceForURL(url), url,
327                         VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
328   host->CreateRenderViewSoon();
329   OnBackgroundHostCreated(host);
330   return true;
331 }
332
333 ExtensionHost* ProcessManager::GetBackgroundHostForExtension(
334     const std::string& extension_id) {
335   for (ExtensionHostSet::iterator iter = background_hosts_.begin();
336        iter != background_hosts_.end(); ++iter) {
337     ExtensionHost* host = *iter;
338     if (host->extension_id() == extension_id)
339       return host;
340   }
341   return NULL;
342 }
343
344 std::set<RenderViewHost*> ProcessManager::GetRenderViewHostsForExtension(
345     const std::string& extension_id) {
346   std::set<RenderViewHost*> result;
347
348   SiteInstance* site_instance = GetSiteInstanceForURL(
349       Extension::GetBaseURLFromExtensionId(extension_id));
350   if (!site_instance)
351     return result;
352
353   // Gather up all the views for that site.
354   for (ExtensionRenderViews::iterator view = all_extension_views_.begin();
355        view != all_extension_views_.end(); ++view) {
356     if (view->first->GetSiteInstance() == site_instance)
357       result.insert(view->first);
358   }
359
360   return result;
361 }
362
363 const Extension* ProcessManager::GetExtensionForRenderViewHost(
364     RenderViewHost* render_view_host) {
365   if (!render_view_host->GetSiteInstance())
366     return NULL;
367
368   return extension_registry_->enabled_extensions().GetByID(
369       GetExtensionID(render_view_host));
370 }
371
372 void ProcessManager::UnregisterRenderViewHost(
373     RenderViewHost* render_view_host) {
374   ExtensionRenderViews::iterator view =
375       all_extension_views_.find(render_view_host);
376   if (view == all_extension_views_.end())
377     return;
378
379   OnRenderViewHostUnregistered(GetBrowserContext(), render_view_host);
380   ViewType view_type = view->second;
381   all_extension_views_.erase(view);
382
383   // Keepalive count, balanced in RegisterRenderViewHost.
384   if (view_type != VIEW_TYPE_INVALID &&
385       view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
386     const Extension* extension = GetExtensionForRenderViewHost(
387         render_view_host);
388     if (extension)
389       DecrementLazyKeepaliveCount(extension);
390   }
391 }
392
393 bool ProcessManager::RegisterRenderViewHost(RenderViewHost* render_view_host) {
394   const Extension* extension = GetExtensionForRenderViewHost(
395       render_view_host);
396   if (!extension)
397     return false;
398
399   WebContents* web_contents = WebContents::FromRenderViewHost(render_view_host);
400   all_extension_views_[render_view_host] = GetViewType(web_contents);
401
402   // Keep the lazy background page alive as long as any non-background-page
403   // extension views are visible. Keepalive count balanced in
404   // UnregisterRenderViewHost.
405   IncrementLazyKeepaliveCountForView(render_view_host);
406   return true;
407 }
408
409 SiteInstance* ProcessManager::GetSiteInstanceForURL(const GURL& url) {
410   return site_instance_->GetRelatedSiteInstance(url);
411 }
412
413 bool ProcessManager::IsBackgroundHostClosing(const std::string& extension_id) {
414   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
415   return (host && background_page_data_[extension_id].is_closing);
416 }
417
418 int ProcessManager::GetLazyKeepaliveCount(const Extension* extension) {
419   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
420     return 0;
421
422   return background_page_data_[extension->id()].lazy_keepalive_count;
423 }
424
425 void ProcessManager::IncrementLazyKeepaliveCount(const Extension* extension) {
426   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
427     return;
428
429   int& count = background_page_data_[extension->id()].lazy_keepalive_count;
430   if (++count == 1)
431     OnLazyBackgroundPageActive(extension->id());
432 }
433
434 void ProcessManager::DecrementLazyKeepaliveCount(const Extension* extension) {
435   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
436     return;
437   DecrementLazyKeepaliveCount(extension->id());
438 }
439
440 void ProcessManager::DecrementLazyKeepaliveCount(
441     const std::string& extension_id) {
442   int& count = background_page_data_[extension_id].lazy_keepalive_count;
443   DCHECK(count > 0 ||
444          !extension_registry_->enabled_extensions().Contains(extension_id));
445
446   // If we reach a zero keepalive count when the lazy background page is about
447   // to be closed, incrementing close_sequence_id will cancel the close
448   // sequence and cause the background page to linger. So check is_closing
449   // before initiating another close sequence.
450   if (--count == 0 && !background_page_data_[extension_id].is_closing) {
451     background_page_data_[extension_id].close_sequence_id =
452         ++last_background_close_sequence_id_;
453     base::MessageLoop::current()->PostDelayedTask(
454         FROM_HERE,
455         base::Bind(&ProcessManager::OnLazyBackgroundPageIdle,
456                    weak_ptr_factory_.GetWeakPtr(),
457                    extension_id,
458                    last_background_close_sequence_id_),
459         base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec));
460   }
461 }
462
463 void ProcessManager::IncrementLazyKeepaliveCountForView(
464     RenderViewHost* render_view_host) {
465   WebContents* web_contents =
466       WebContents::FromRenderViewHost(render_view_host);
467   ViewType view_type = GetViewType(web_contents);
468   if (view_type != VIEW_TYPE_INVALID &&
469       view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
470     const Extension* extension = GetExtensionForRenderViewHost(
471         render_view_host);
472     if (extension)
473       IncrementLazyKeepaliveCount(extension);
474   }
475 }
476
477 // This implementation layers on top of the keepalive count. An impulse sets
478 // a per extension flag. On a regular interval that flag is checked. Changes
479 // from the flag not being set to set cause an IncrementLazyKeepaliveCount.
480 void ProcessManager::KeepaliveImpulse(const Extension* extension) {
481   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
482     return;
483
484   BackgroundPageData& bd = background_page_data_[extension->id()];
485
486   if (!bd.keepalive_impulse) {
487     bd.keepalive_impulse = true;
488     if (!bd.previous_keepalive_impulse) {
489       IncrementLazyKeepaliveCount(extension);
490     }
491   }
492
493   if (!keepalive_impulse_callback_for_testing_.is_null()) {
494     ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly =
495       keepalive_impulse_callback_for_testing_;
496     callback_may_clear_callbacks_reentrantly.Run(extension->id());
497   }
498 }
499
500 // static
501 void ProcessManager::OnKeepaliveFromPlugin(int render_process_id,
502                                            int render_frame_id,
503                                            const std::string& extension_id) {
504   content::RenderFrameHost* render_frame_host =
505       content::RenderFrameHost::FromID(render_process_id, render_frame_id);
506   if (!render_frame_host)
507     return;
508
509   content::SiteInstance* site_instance = render_frame_host->GetSiteInstance();
510   if (!site_instance)
511     return;
512
513   BrowserContext* browser_context = site_instance->GetBrowserContext();
514   const Extension* extension =
515       ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID(
516           extension_id);
517   if (!extension)
518     return;
519
520   ProcessManager* pm = ExtensionSystem::Get(browser_context)->process_manager();
521   if (!pm)
522     return;
523
524   pm->KeepaliveImpulse(extension);
525 }
526
527 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse
528 // have been made for at least g_event_page_idle_time_msec. In the best case an
529 // impulse was made just before being cleared, and the decrement will occur
530 // g_event_page_idle_time_msec later, causing a 2 * g_event_page_idle_time_msec
531 // total time for extension to be shut down based on impulses. Worst case is
532 // an impulse just after a clear, adding one check cycle and resulting in 3x
533 // total time.
534 void ProcessManager::OnKeepaliveImpulseCheck() {
535   for (BackgroundPageDataMap::iterator i = background_page_data_.begin();
536        i != background_page_data_.end();
537        ++i) {
538     if (i->second.previous_keepalive_impulse && !i->second.keepalive_impulse) {
539       DecrementLazyKeepaliveCount(i->first);
540       if (!keepalive_impulse_decrement_callback_for_testing_.is_null()) {
541         ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly =
542           keepalive_impulse_decrement_callback_for_testing_;
543         callback_may_clear_callbacks_reentrantly.Run(i->first);
544       }
545     }
546
547     i->second.previous_keepalive_impulse = i->second.keepalive_impulse;
548     i->second.keepalive_impulse = false;
549   }
550
551   // OnKeepaliveImpulseCheck() is always called in constructor, but in unit
552   // tests there will be no message loop. In that event don't schedule tasks.
553   if (base::MessageLoop::current()) {
554     base::MessageLoop::current()->PostDelayedTask(
555         FROM_HERE,
556         base::Bind(&ProcessManager::OnKeepaliveImpulseCheck,
557                    weak_ptr_factory_.GetWeakPtr()),
558         base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec));
559   }
560 }
561
562 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id,
563                                               uint64 sequence_id) {
564   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
565   if (host && !background_page_data_[extension_id].is_closing &&
566       sequence_id == background_page_data_[extension_id].close_sequence_id) {
567     // Tell the renderer we are about to close. This is a simple ping that the
568     // renderer will respond to. The purpose is to control sequencing: if the
569     // extension remains idle until the renderer responds with an ACK, then we
570     // know that the extension process is ready to shut down. If our
571     // close_sequence_id has already changed, then we would ignore the
572     // ShouldSuspendAck, so we don't send the ping.
573     host->render_view_host()->Send(new ExtensionMsg_ShouldSuspend(
574         extension_id, sequence_id));
575   }
576 }
577
578 void ProcessManager::OnLazyBackgroundPageActive(
579     const std::string& extension_id) {
580   if (!background_page_data_[extension_id].is_closing) {
581     // Cancel the current close sequence by changing the close_sequence_id,
582     // which causes us to ignore the next ShouldSuspendAck.
583     background_page_data_[extension_id].close_sequence_id =
584         ++last_background_close_sequence_id_;
585   }
586 }
587
588 void ProcessManager::OnShouldSuspendAck(const std::string& extension_id,
589                                         uint64 sequence_id) {
590   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
591   if (host &&
592       sequence_id == background_page_data_[extension_id].close_sequence_id) {
593     host->render_view_host()->Send(new ExtensionMsg_Suspend(extension_id));
594   }
595 }
596
597 void ProcessManager::OnSuspendAck(const std::string& extension_id) {
598   background_page_data_[extension_id].is_closing = true;
599   uint64 sequence_id = background_page_data_[extension_id].close_sequence_id;
600   base::MessageLoop::current()->PostDelayedTask(
601       FROM_HERE,
602       base::Bind(&ProcessManager::CloseLazyBackgroundPageNow,
603                  weak_ptr_factory_.GetWeakPtr(),
604                  extension_id,
605                  sequence_id),
606       base::TimeDelta::FromMilliseconds(g_event_page_suspending_time_msec));
607 }
608
609 void ProcessManager::CloseLazyBackgroundPageNow(const std::string& extension_id,
610                                                 uint64 sequence_id) {
611   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
612   if (host &&
613       sequence_id == background_page_data_[extension_id].close_sequence_id) {
614     ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
615     if (host)
616       CloseBackgroundHost(host);
617   }
618 }
619
620 void ProcessManager::OnNetworkRequestStarted(
621     content::RenderFrameHost* render_frame_host) {
622   ExtensionHost* host = GetBackgroundHostForExtension(
623       GetExtensionIDFromFrame(render_frame_host));
624   if (host && IsFrameInExtensionHost(host, render_frame_host))
625     IncrementLazyKeepaliveCount(host->extension());
626 }
627
628 void ProcessManager::OnNetworkRequestDone(
629     content::RenderFrameHost* render_frame_host) {
630   ExtensionHost* host = GetBackgroundHostForExtension(
631       GetExtensionIDFromFrame(render_frame_host));
632   if (host && IsFrameInExtensionHost(host, render_frame_host))
633     DecrementLazyKeepaliveCount(host->extension());
634 }
635
636 void ProcessManager::CancelSuspend(const Extension* extension) {
637   bool& is_closing = background_page_data_[extension->id()].is_closing;
638   ExtensionHost* host = GetBackgroundHostForExtension(extension->id());
639   if (host && is_closing) {
640     is_closing = false;
641     host->render_view_host()->Send(
642         new ExtensionMsg_CancelSuspend(extension->id()));
643     // This increment / decrement is to simulate an instantaneous event. This
644     // has the effect of invalidating close_sequence_id, preventing any in
645     // progress closes from completing and starting a new close process if
646     // necessary.
647     IncrementLazyKeepaliveCount(extension);
648     DecrementLazyKeepaliveCount(extension);
649   }
650 }
651
652 void ProcessManager::CloseBackgroundHosts() {
653   for (ExtensionHostSet::iterator iter = background_hosts_.begin();
654        iter != background_hosts_.end();) {
655     ExtensionHostSet::iterator current = iter++;
656     delete *current;
657   }
658 }
659
660 content::BrowserContext* ProcessManager::GetBrowserContext() const {
661   return site_instance_->GetBrowserContext();
662 }
663
664 void ProcessManager::SetKeepaliveImpulseCallbackForTesting(
665     const ImpulseCallbackForTesting& callback) {
666   keepalive_impulse_callback_for_testing_ = callback;
667 }
668
669 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting(
670     const ImpulseCallbackForTesting& callback) {
671   keepalive_impulse_decrement_callback_for_testing_ = callback;
672 }
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
686 void ProcessManager::Observe(int type,
687                              const content::NotificationSource& source,
688                              const content::NotificationDetails& details) {
689   switch (type) {
690     case extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED: {
691       // TODO(jamescook): Convert this to use ExtensionSystem::ready() instead
692       // of a notification.
693       MaybeCreateStartupBackgroundHosts();
694       break;
695     }
696
697     case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: {
698       BrowserContext* context = content::Source<BrowserContext>(source).ptr();
699       ExtensionSystem* system = ExtensionSystem::Get(context);
700       if (system->ready().is_signaled()) {
701         // The extension system is ready, so create the background host.
702         const Extension* extension =
703             content::Details<const Extension>(details).ptr();
704         CreateBackgroundHostForExtensionLoad(this, extension);
705       }
706       break;
707     }
708
709     case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
710       const Extension* extension =
711           content::Details<UnloadedExtensionInfo>(details)->extension;
712       for (ExtensionHostSet::iterator iter = background_hosts_.begin();
713            iter != background_hosts_.end(); ++iter) {
714         ExtensionHost* host = *iter;
715         if (host->extension_id() == extension->id()) {
716           CloseBackgroundHost(host);
717           break;
718         }
719       }
720       UnregisterExtension(extension->id());
721       break;
722     }
723
724     case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
725       ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
726       if (background_hosts_.erase(host)) {
727         ClearBackgroundPageData(host->extension()->id());
728         background_page_data_[host->extension()->id()].since_suspended.reset(
729             new base::ElapsedTimer());
730       }
731       break;
732     }
733
734     case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
735       ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
736       if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
737         CloseBackgroundHost(host);
738       }
739       break;
740     }
741
742     case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: {
743       // We get this notification both for new WebContents and when one
744       // has its RenderViewHost replaced (e.g. when a user does a cross-site
745       // navigation away from an extension URL). For the replaced case, we must
746       // unregister the old RVH so it doesn't count as an active view that would
747       // keep the event page alive.
748       WebContents* contents = content::Source<WebContents>(source).ptr();
749       if (contents->GetBrowserContext() != GetBrowserContext())
750         break;
751
752       typedef std::pair<RenderViewHost*, RenderViewHost*> RVHPair;
753       RVHPair* switched_details = content::Details<RVHPair>(details).ptr();
754       if (switched_details->first)
755         UnregisterRenderViewHost(switched_details->first);
756
757       // The above will unregister a RVH when it gets swapped out with a new
758       // one. However we need to watch the WebContents to know when a RVH is
759       // deleted because the WebContents has gone away.
760       if (RegisterRenderViewHost(switched_details->second)) {
761         RenderViewHostDestructionObserver::CreateForWebContents(contents);
762       }
763       break;
764     }
765
766     case content::NOTIFICATION_WEB_CONTENTS_CONNECTED: {
767       WebContents* contents = content::Source<WebContents>(source).ptr();
768       if (contents->GetBrowserContext() != GetBrowserContext())
769         break;
770       const Extension* extension = GetExtensionForRenderViewHost(
771           contents->GetRenderViewHost());
772       if (!extension)
773         return;
774
775       // RegisterRenderViewHost is called too early (before the process is
776       // available), so we need to wait until now to notify.
777       content::NotificationService::current()->Notify(
778           extensions::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
779           content::Source<BrowserContext>(GetBrowserContext()),
780           content::Details<RenderViewHost>(contents->GetRenderViewHost()));
781       break;
782     }
783
784     default:
785       NOTREACHED();
786   }
787 }
788
789 void ProcessManager::OnDevToolsStateChanged(
790     content::DevToolsAgentHost* agent_host,
791     bool attached) {
792   WebContents* web_contents = agent_host->GetWebContents();
793   // Ignore unrelated notifications.
794   if (!web_contents || web_contents->GetBrowserContext() != GetBrowserContext())
795     return;
796   if (GetViewType(web_contents) != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE)
797     return;
798   const Extension* extension =
799       GetExtensionForRenderViewHost(web_contents->GetRenderViewHost());
800   if (!extension)
801     return;
802   if (attached) {
803     // Keep the lazy background page alive while it's being inspected.
804     CancelSuspend(extension);
805     IncrementLazyKeepaliveCount(extension);
806   } else {
807     DecrementLazyKeepaliveCount(extension);
808   }
809 }
810
811 void ProcessManager::MaybeCreateStartupBackgroundHosts() {
812   if (startup_background_hosts_created_)
813     return;
814
815   // The embedder might disallow background pages entirely.
816   ProcessManagerDelegate* delegate =
817       ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
818   if (delegate && !delegate->IsBackgroundPageAllowed(GetBrowserContext()))
819     return;
820
821   // The embedder might want to defer background page loading. For example,
822   // Chrome defers background page loading when it is launched to show the app
823   // list, then triggers a load later when a browser window opens.
824   if (delegate &&
825       delegate->DeferCreatingStartupBackgroundHosts(GetBrowserContext()))
826     return;
827
828   CreateStartupBackgroundHosts();
829   startup_background_hosts_created_ = true;
830
831   // Background pages should only be loaded once. To prevent any further loads
832   // occurring, we remove the notification listeners.
833   BrowserContext* original_context =
834       ExtensionsBrowserClient::Get()->GetOriginalContext(GetBrowserContext());
835   if (registrar_.IsRegistered(
836           this,
837           extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
838           content::Source<BrowserContext>(original_context))) {
839     registrar_.Remove(this,
840                       extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
841                       content::Source<BrowserContext>(original_context));
842   }
843 }
844
845 void ProcessManager::CreateStartupBackgroundHosts() {
846   DCHECK(!startup_background_hosts_created_);
847   const ExtensionSet& enabled_extensions =
848       extension_registry_->enabled_extensions();
849   for (ExtensionSet::const_iterator extension = enabled_extensions.begin();
850        extension != enabled_extensions.end();
851        ++extension) {
852     CreateBackgroundHostForExtensionLoad(this, extension->get());
853
854     FOR_EACH_OBSERVER(ProcessManagerObserver,
855                       observer_list_,
856                       OnBackgroundHostStartup(extension->get()));
857   }
858 }
859
860 void ProcessManager::OnBackgroundHostCreated(ExtensionHost* host) {
861   DCHECK_EQ(GetBrowserContext(), host->browser_context());
862   background_hosts_.insert(host);
863
864   if (BackgroundInfo::HasLazyBackgroundPage(host->extension())) {
865     linked_ptr<base::ElapsedTimer> since_suspended(
866         background_page_data_[host->extension()->id()].
867             since_suspended.release());
868     if (since_suspended.get()) {
869       UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime",
870                                since_suspended->Elapsed());
871     }
872   }
873 }
874
875 void ProcessManager::CloseBackgroundHost(ExtensionHost* host) {
876   CHECK(host->extension_host_type() ==
877         VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
878   delete host;
879   // |host| should deregister itself from our structures.
880   CHECK(background_hosts_.find(host) == background_hosts_.end());
881 }
882
883 void ProcessManager::UnregisterExtension(const std::string& extension_id) {
884   // The lazy_keepalive_count may be greater than zero at this point because
885   // RenderViewHosts are still alive. During extension reloading, they will
886   // decrement the lazy_keepalive_count to negative for the new extension
887   // instance when they are destroyed. Since we are erasing the background page
888   // data for the unloaded extension, unregister the RenderViewHosts too.
889   BrowserContext* context = GetBrowserContext();
890   for (ExtensionRenderViews::iterator it = all_extension_views_.begin();
891        it != all_extension_views_.end(); ) {
892     if (GetExtensionID(it->first) == extension_id) {
893       OnRenderViewHostUnregistered(context, it->first);
894       all_extension_views_.erase(it++);
895     } else {
896       ++it;
897     }
898   }
899
900   background_page_data_.erase(extension_id);
901 }
902
903 void ProcessManager::ClearBackgroundPageData(const std::string& extension_id) {
904   background_page_data_.erase(extension_id);
905
906   // Re-register all RenderViews for this extension. We do this to restore
907   // the lazy_keepalive_count (if any) to properly reflect the number of open
908   // views.
909   for (ExtensionRenderViews::const_iterator it = all_extension_views_.begin();
910        it != all_extension_views_.end(); ++it) {
911     if (GetExtensionID(it->first) == extension_id)
912       IncrementLazyKeepaliveCountForView(it->first);
913   }
914 }
915
916 //
917 // IncognitoProcessManager
918 //
919
920 IncognitoProcessManager::IncognitoProcessManager(
921     BrowserContext* incognito_context,
922     BrowserContext* original_context,
923     ProcessManager* original_manager,
924     ExtensionRegistry* extension_registry)
925     : ProcessManager(incognito_context, original_context, extension_registry),
926       original_manager_(original_manager) {
927   DCHECK(incognito_context->IsOffTheRecord());
928
929   // The original profile will have its own ProcessManager to
930   // load the background pages of the spanning extensions. This process
931   // manager need only worry about the split mode extensions, which is handled
932   // in the NOTIFICATION_BROWSER_WINDOW_READY notification handler.
933   registrar_.Remove(this,
934                     extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
935                     content::Source<BrowserContext>(original_context));
936 }
937
938 bool IncognitoProcessManager::CreateBackgroundHost(const Extension* extension,
939                                                    const GURL& url) {
940   if (IncognitoInfo::IsSplitMode(extension)) {
941     if (ExtensionsBrowserClient::Get()->IsExtensionIncognitoEnabled(
942             extension->id(), GetBrowserContext()))
943       return ProcessManager::CreateBackgroundHost(extension, url);
944   } else {
945     // Do nothing. If an extension is spanning, then its original-profile
946     // background page is shared with incognito, so we don't create another.
947   }
948   return false;
949 }
950
951 SiteInstance* IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) {
952   const Extension* extension =
953       extension_registry_->enabled_extensions().GetExtensionOrAppByURL(url);
954   if (extension && !IncognitoInfo::IsSplitMode(extension))
955     return original_manager_->GetSiteInstanceForURL(url);
956
957   return ProcessManager::GetSiteInstanceForURL(url);
958 }
959
960 }  // namespace extensions