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