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