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/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