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