• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AddComponent(BrowserContextKeyedBaseFactory * component)26 void BrowserContextDependencyManager::AddComponent(
27     BrowserContextKeyedBaseFactory* component) {
28   dependency_graph_.AddNode(component);
29 }
30 
RemoveComponent(BrowserContextKeyedBaseFactory * component)31 void BrowserContextDependencyManager::RemoveComponent(
32     BrowserContextKeyedBaseFactory* component) {
33   dependency_graph_.RemoveNode(component);
34 }
35 
AddEdge(BrowserContextKeyedBaseFactory * depended,BrowserContextKeyedBaseFactory * dependee)36 void BrowserContextDependencyManager::AddEdge(
37     BrowserContextKeyedBaseFactory* depended,
38     BrowserContextKeyedBaseFactory* dependee) {
39   dependency_graph_.AddEdge(depended, dependee);
40 }
41 
RegisterProfilePrefsForServices(const content::BrowserContext * context,user_prefs::PrefRegistrySyncable * pref_registry)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 
CreateBrowserContextServices(content::BrowserContext * context)60 void BrowserContextDependencyManager::CreateBrowserContextServices(
61     content::BrowserContext* context) {
62   DoCreateBrowserContextServices(context, false);
63 }
64 
CreateBrowserContextServicesForTest(content::BrowserContext * context)65 void BrowserContextDependencyManager::CreateBrowserContextServicesForTest(
66     content::BrowserContext* context) {
67   DoCreateBrowserContextServices(context, true);
68 }
69 
DoCreateBrowserContextServices(content::BrowserContext * context,bool is_testing_context)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 
DestroyBrowserContextServices(content::BrowserContext * context)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::
RegisterWillCreateBrowserContextServicesCallbackForTesting(const base::Callback<void (content::BrowserContext *)> & callback)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
AssertBrowserContextWasntDestroyed(content::BrowserContext * context)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 
MarkBrowserContextLiveForTesting(content::BrowserContext * context)152 void BrowserContextDependencyManager::MarkBrowserContextLiveForTesting(
153     content::BrowserContext* context) {
154   dead_context_pointers_.erase(context);
155 }
156 #endif
157 
158 // static
159 BrowserContextDependencyManager*
GetInstance()160 BrowserContextDependencyManager::GetInstance() {
161   return Singleton<BrowserContextDependencyManager>::get();
162 }
163 
BrowserContextDependencyManager()164 BrowserContextDependencyManager::BrowserContextDependencyManager() {}
165 
~BrowserContextDependencyManager()166 BrowserContextDependencyManager::~BrowserContextDependencyManager() {}
167 
168 #ifndef NDEBUG
169 namespace {
170 
BrowserContextKeyedBaseFactoryGetNodeName(DependencyNode * node)171 std::string BrowserContextKeyedBaseFactoryGetNodeName(DependencyNode* node) {
172   return static_cast<BrowserContextKeyedBaseFactory*>(node)->name();
173 }
174 
175 }  // namespace
176 
DumpBrowserContextDependencies(content::BrowserContext * context)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