Home | History | Annotate | Download | only in browser_context_keyed_service
      1 // Copyright (c) 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 "components/browser_context_keyed_service/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/browser_context_keyed_service/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/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(); it != construction_order.end(); ++it) {
     52     BrowserContextKeyedBaseFactory* factory =
     53         static_cast<BrowserContextKeyedBaseFactory*>(*it);
     54     factory->RegisterProfilePrefsIfNecessaryForContext(context, pref_registry);
     55   }
     56 }
     57 
     58 void BrowserContextDependencyManager::CreateBrowserContextServices(
     59     content::BrowserContext* context) {
     60   DoCreateBrowserContextServices(context, false);
     61 }
     62 
     63 void BrowserContextDependencyManager::CreateBrowserContextServicesForTest(
     64     content::BrowserContext* context) {
     65   DoCreateBrowserContextServices(context, true);
     66 }
     67 
     68 void BrowserContextDependencyManager::DoCreateBrowserContextServices(
     69     content::BrowserContext* context,
     70     bool is_testing_context) {
     71   TRACE_EVENT0("browser",
     72     "BrowserContextDependencyManager::DoCreateBrowserContextServices")
     73 #ifndef NDEBUG
     74   // Unmark |context| as dead. This exists because of unit tests, which will
     75   // often have similar stack structures. 0xWhatever might be created, go out
     76   // of scope, and then a new BrowserContext object might be created
     77   // at 0xWhatever.
     78   dead_context_pointers_.erase(context);
     79 #endif
     80 
     81   std::vector<DependencyNode*> construction_order;
     82   if (!dependency_graph_.GetConstructionOrder(&construction_order)) {
     83     NOTREACHED();
     84   }
     85 
     86 #ifndef NDEBUG
     87   DumpBrowserContextDependencies(context);
     88 #endif
     89 
     90   for (size_t i = 0; i < construction_order.size(); i++) {
     91     BrowserContextKeyedBaseFactory* factory =
     92         static_cast<BrowserContextKeyedBaseFactory*>(construction_order[i]);
     93     if (is_testing_context && factory->ServiceIsNULLWhileTesting()) {
     94       factory->SetEmptyTestingFactory(context);
     95     } else if (factory->ServiceIsCreatedWithBrowserContext()) {
     96       // Create the service.
     97       factory->CreateServiceNow(context);
     98     }
     99   }
    100 }
    101 
    102 void BrowserContextDependencyManager::DestroyBrowserContextServices(
    103     content::BrowserContext* context) {
    104   std::vector<DependencyNode*> destruction_order;
    105   if (!dependency_graph_.GetDestructionOrder(&destruction_order)) {
    106     NOTREACHED();
    107   }
    108 
    109 #ifndef NDEBUG
    110   DumpBrowserContextDependencies(context);
    111 #endif
    112 
    113   for (size_t i = 0; i < destruction_order.size(); i++) {
    114     BrowserContextKeyedBaseFactory* factory =
    115         static_cast<BrowserContextKeyedBaseFactory*>(destruction_order[i]);
    116     factory->BrowserContextShutdown(context);
    117   }
    118 
    119 #ifndef NDEBUG
    120   // The context is now dead to the rest of the program.
    121   dead_context_pointers_.insert(context);
    122 #endif
    123 
    124   for (size_t i = 0; i < destruction_order.size(); i++) {
    125     BrowserContextKeyedBaseFactory* factory =
    126         static_cast<BrowserContextKeyedBaseFactory*>(destruction_order[i]);
    127     factory->BrowserContextDestroyed(context);
    128   }
    129 }
    130 
    131 #ifndef NDEBUG
    132 void BrowserContextDependencyManager::AssertBrowserContextWasntDestroyed(
    133     content::BrowserContext* context) {
    134   if (dead_context_pointers_.find(context) != dead_context_pointers_.end()) {
    135     NOTREACHED() << "Attempted to access a BrowserContext that was ShutDown(). "
    136                  << "This is most likely a heap smasher in progress. After "
    137                  << "BrowserContextKeyedService::Shutdown() completes, your "
    138                  << "service MUST NOT refer to depended BrowserContext "
    139                  << "services again.";
    140   }
    141 }
    142 #endif
    143 
    144 // static
    145 BrowserContextDependencyManager*
    146 BrowserContextDependencyManager::GetInstance() {
    147   return Singleton<BrowserContextDependencyManager>::get();
    148 }
    149 
    150 BrowserContextDependencyManager::BrowserContextDependencyManager() {
    151 }
    152 
    153 BrowserContextDependencyManager::~BrowserContextDependencyManager() {
    154 }
    155 
    156 #ifndef NDEBUG
    157 namespace {
    158 
    159 std::string BrowserContextKeyedBaseFactoryGetNodeName(DependencyNode* node) {
    160   return static_cast<BrowserContextKeyedBaseFactory*>(node)->name();
    161 }
    162 
    163 }  // namespace
    164 
    165 void BrowserContextDependencyManager::DumpBrowserContextDependencies(
    166     content::BrowserContext* context) {
    167   // Whenever we try to build a destruction ordering, we should also dump a
    168   // dependency graph to "/path/to/context/context-dependencies.dot".
    169   if (CommandLine::ForCurrentProcess()->HasSwitch(
    170           kDumpBrowserContextDependencyGraphFlag)) {
    171     base::FilePath dot_file =
    172         context->GetPath().AppendASCII("browser-context-dependencies.dot");
    173     std::string contents = dependency_graph_.DumpAsGraphviz(
    174         "BrowserContext",
    175         base::Bind(&BrowserContextKeyedBaseFactoryGetNodeName));
    176     file_util::WriteFile(dot_file, contents.c_str(), contents.size());
    177   }
    178 }
    179 #endif  // NDEBUG
    180