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