Home | History | Annotate | Download | only in content
      1 // Copyright 2014 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 "components/keyed_service/content/browser_context_dependency_manager.h"
      6 
      7 #include <algorithm>
      8 #include <deque>
      9 #include <iterator>
     10 
     11 #include "base/bind.h"
     12 #include "base/debug/trace_event.h"
     13 #include "components/keyed_service/content/browser_context_keyed_base_factory.h"
     14 #include "content/public/browser/browser_context.h"
     15 
     16 #ifndef NDEBUG
     17 #include "base/command_line.h"
     18 #include "base/files/file_util.h"
     19 
     20 // Dumps dependency information about our browser context keyed services
     21 // into a dot file in the browser context directory.
     22 const char kDumpBrowserContextDependencyGraphFlag[] =
     23     "dump-browser-context-graph";
     24 #endif  // NDEBUG
     25 
     26 void BrowserContextDependencyManager::AddComponent(
     27     BrowserContextKeyedBaseFactory* component) {
     28   dependency_graph_.AddNode(component);
     29 }
     30 
     31 void BrowserContextDependencyManager::RemoveComponent(
     32     BrowserContextKeyedBaseFactory* component) {
     33   dependency_graph_.RemoveNode(component);
     34 }
     35 
     36 void BrowserContextDependencyManager::AddEdge(
     37     BrowserContextKeyedBaseFactory* depended,
     38     BrowserContextKeyedBaseFactory* dependee) {
     39   dependency_graph_.AddEdge(depended, dependee);
     40 }
     41 
     42 void BrowserContextDependencyManager::RegisterProfilePrefsForServices(
     43     const content::BrowserContext* context,
     44     user_prefs::PrefRegistrySyncable* pref_registry) {
     45   std::vector<DependencyNode*> construction_order;
     46   if (!dependency_graph_.GetConstructionOrder(&construction_order)) {
     47     NOTREACHED();
     48   }
     49 
     50   for (std::vector<DependencyNode*>::const_iterator it =
     51            construction_order.begin();
     52        it != construction_order.end();
     53        ++it) {
     54     BrowserContextKeyedBaseFactory* factory =
     55         static_cast<BrowserContextKeyedBaseFactory*>(*it);
     56     factory->RegisterProfilePrefsIfNecessaryForContext(context, pref_registry);
     57   }
     58 }
     59 
     60 void BrowserContextDependencyManager::CreateBrowserContextServices(
     61     content::BrowserContext* context) {
     62   DoCreateBrowserContextServices(context, false);
     63 }
     64 
     65 void BrowserContextDependencyManager::CreateBrowserContextServicesForTest(
     66     content::BrowserContext* context) {
     67   DoCreateBrowserContextServices(context, true);
     68 }
     69 
     70 void BrowserContextDependencyManager::DoCreateBrowserContextServices(
     71     content::BrowserContext* context,
     72     bool is_testing_context) {
     73   TRACE_EVENT0(
     74       "browser",
     75       "BrowserContextDependencyManager::DoCreateBrowserContextServices")
     76 #ifndef NDEBUG
     77   MarkBrowserContextLiveForTesting(context);
     78 #endif
     79 
     80   will_create_browser_context_services_callbacks_.Notify(context);
     81 
     82   std::vector<DependencyNode*> construction_order;
     83   if (!dependency_graph_.GetConstructionOrder(&construction_order)) {
     84     NOTREACHED();
     85   }
     86 
     87 #ifndef NDEBUG
     88   DumpBrowserContextDependencies(context);
     89 #endif
     90 
     91   for (size_t i = 0; i < construction_order.size(); i++) {
     92     BrowserContextKeyedBaseFactory* factory =
     93         static_cast<BrowserContextKeyedBaseFactory*>(construction_order[i]);
     94     if (is_testing_context && factory->ServiceIsNULLWhileTesting() &&
     95         !factory->HasTestingFactory(context)) {
     96       factory->SetEmptyTestingFactory(context);
     97     } else if (factory->ServiceIsCreatedWithBrowserContext()) {
     98       // Create the service.
     99       factory->CreateServiceNow(context);
    100     }
    101   }
    102 }
    103 
    104 void BrowserContextDependencyManager::DestroyBrowserContextServices(
    105     content::BrowserContext* context) {
    106   std::vector<DependencyNode*> destruction_order;
    107   if (!dependency_graph_.GetDestructionOrder(&destruction_order)) {
    108     NOTREACHED();
    109   }
    110 
    111 #ifndef NDEBUG
    112   DumpBrowserContextDependencies(context);
    113 #endif
    114 
    115   for (size_t i = 0; i < destruction_order.size(); i++) {
    116     BrowserContextKeyedBaseFactory* factory =
    117         static_cast<BrowserContextKeyedBaseFactory*>(destruction_order[i]);
    118     factory->BrowserContextShutdown(context);
    119   }
    120 
    121 #ifndef NDEBUG
    122   // The context is now dead to the rest of the program.
    123   dead_context_pointers_.insert(context);
    124 #endif
    125 
    126   for (size_t i = 0; i < destruction_order.size(); i++) {
    127     BrowserContextKeyedBaseFactory* factory =
    128         static_cast<BrowserContextKeyedBaseFactory*>(destruction_order[i]);
    129     factory->BrowserContextDestroyed(context);
    130   }
    131 }
    132 
    133 scoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription>
    134 BrowserContextDependencyManager::
    135 RegisterWillCreateBrowserContextServicesCallbackForTesting(
    136     const base::Callback<void(content::BrowserContext*)>& callback) {
    137   return will_create_browser_context_services_callbacks_.Add(callback);
    138 }
    139 
    140 #ifndef NDEBUG
    141 void BrowserContextDependencyManager::AssertBrowserContextWasntDestroyed(
    142     content::BrowserContext* context) {
    143   if (dead_context_pointers_.find(context) != dead_context_pointers_.end()) {
    144     NOTREACHED() << "Attempted to access a BrowserContext that was ShutDown(). "
    145                  << "This is most likely a heap smasher in progress. After "
    146                  << "KeyedService::Shutdown() completes, your "
    147                  << "service MUST NOT refer to depended BrowserContext "
    148                  << "services again.";
    149   }
    150 }
    151 
    152 void BrowserContextDependencyManager::MarkBrowserContextLiveForTesting(
    153     content::BrowserContext* context) {
    154   dead_context_pointers_.erase(context);
    155 }
    156 #endif
    157 
    158 // static
    159 BrowserContextDependencyManager*
    160 BrowserContextDependencyManager::GetInstance() {
    161   return Singleton<BrowserContextDependencyManager>::get();
    162 }
    163 
    164 BrowserContextDependencyManager::BrowserContextDependencyManager() {}
    165 
    166 BrowserContextDependencyManager::~BrowserContextDependencyManager() {}
    167 
    168 #ifndef NDEBUG
    169 namespace {
    170 
    171 std::string BrowserContextKeyedBaseFactoryGetNodeName(DependencyNode* node) {
    172   return static_cast<BrowserContextKeyedBaseFactory*>(node)->name();
    173 }
    174 
    175 }  // namespace
    176 
    177 void BrowserContextDependencyManager::DumpBrowserContextDependencies(
    178     content::BrowserContext* context) {
    179   // Whenever we try to build a destruction ordering, we should also dump a
    180   // dependency graph to "/path/to/context/context-dependencies.dot".
    181   if (CommandLine::ForCurrentProcess()->HasSwitch(
    182           kDumpBrowserContextDependencyGraphFlag)) {
    183     base::FilePath dot_file =
    184         context->GetPath().AppendASCII("browser-context-dependencies.dot");
    185     std::string contents = dependency_graph_.DumpAsGraphviz(
    186         "BrowserContext",
    187         base::Bind(&BrowserContextKeyedBaseFactoryGetNodeName));
    188     base::WriteFile(dot_file, contents.c_str(), contents.size());
    189   }
    190 }
    191 #endif  // NDEBUG
    192