browser_context_dependency_manager.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// Copyright 2014 The Chromium Authors. All rights reserved.
224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// Use of this source code is governed by a BSD-style license that can be
324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// found in the LICENSE file.
424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "components/keyed_service/content/browser_context_dependency_manager.h"
624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <algorithm>
824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <deque>
924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <iterator>
10144188bc458a35997d2f2e52206ab69747439073Greg Clayton
1124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "base/bind.h"
1224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "base/debug/trace_event.h"
1324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "components/keyed_service/content/browser_context_keyed_base_factory.h"
1424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "content/public/browser/browser_context.h"
1524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
16257663e753af15633e48c7b00eb7b5880168090bGreg Clayton#ifndef NDEBUG
17257663e753af15633e48c7b00eb7b5880168090bGreg Clayton#include "base/command_line.h"
1824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "base/files/file_util.h"
1924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
2024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// Dumps dependency information about our browser context keyed services
2124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// into a dot file in the browser context directory.
22257663e753af15633e48c7b00eb7b5880168090bGreg Claytonconst char kDumpBrowserContextDependencyGraphFlag[] =
23be42123fa214b039b86ad152bd21d910db7a7af2Greg Clayton    "dump-browser-context-graph";
24257663e753af15633e48c7b00eb7b5880168090bGreg Clayton#endif  // NDEBUG
2524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
26257663e753af15633e48c7b00eb7b5880168090bGreg Claytonvoid BrowserContextDependencyManager::AddComponent(
27257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    BrowserContextKeyedBaseFactory* component) {
28257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  dependency_graph_.AddNode(component);
29257663e753af15633e48c7b00eb7b5880168090bGreg Clayton}
30257663e753af15633e48c7b00eb7b5880168090bGreg Clayton
31257663e753af15633e48c7b00eb7b5880168090bGreg Claytonvoid BrowserContextDependencyManager::RemoveComponent(
32257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    BrowserContextKeyedBaseFactory* component) {
3324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  dependency_graph_.RemoveNode(component);
34257663e753af15633e48c7b00eb7b5880168090bGreg Clayton}
35257663e753af15633e48c7b00eb7b5880168090bGreg Clayton
36257663e753af15633e48c7b00eb7b5880168090bGreg Claytonvoid BrowserContextDependencyManager::AddEdge(
37257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    BrowserContextKeyedBaseFactory* depended,
38257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    BrowserContextKeyedBaseFactory* dependee) {
39257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  dependency_graph_.AddEdge(depended, dependee);
40257663e753af15633e48c7b00eb7b5880168090bGreg Clayton}
41257663e753af15633e48c7b00eb7b5880168090bGreg Clayton
42178710cd4307f3d44dc76ebd70fc7daf7ebe17c5Greg Claytonvoid BrowserContextDependencyManager::RegisterProfilePrefsForServices(
43178710cd4307f3d44dc76ebd70fc7daf7ebe17c5Greg Clayton    const content::BrowserContext* context,
44257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    user_prefs::PrefRegistrySyncable* pref_registry) {
45257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  std::vector<DependencyNode*> construction_order;
46257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  if (!dependency_graph_.GetConstructionOrder(&construction_order)) {
47257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    NOTREACHED();
48257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  }
49257663e753af15633e48c7b00eb7b5880168090bGreg Clayton
50257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  for (std::vector<DependencyNode*>::const_iterator it =
51257663e753af15633e48c7b00eb7b5880168090bGreg Clayton           construction_order.begin();
52257663e753af15633e48c7b00eb7b5880168090bGreg Clayton       it != construction_order.end();
53257663e753af15633e48c7b00eb7b5880168090bGreg Clayton       ++it) {
54257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    BrowserContextKeyedBaseFactory* factory =
55257663e753af15633e48c7b00eb7b5880168090bGreg Clayton        static_cast<BrowserContextKeyedBaseFactory*>(*it);
56257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    factory->RegisterProfilePrefsIfNecessaryForContext(context, pref_registry);
57257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  }
58257663e753af15633e48c7b00eb7b5880168090bGreg Clayton}
59257663e753af15633e48c7b00eb7b5880168090bGreg Clayton
60257663e753af15633e48c7b00eb7b5880168090bGreg Claytonvoid BrowserContextDependencyManager::CreateBrowserContextServices(
61257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    content::BrowserContext* context) {
62257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  DoCreateBrowserContextServices(context, false);
6324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
64257663e753af15633e48c7b00eb7b5880168090bGreg Clayton
65257663e753af15633e48c7b00eb7b5880168090bGreg Claytonvoid BrowserContextDependencyManager::CreateBrowserContextServicesForTest(
66257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    content::BrowserContext* context) {
67257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  DoCreateBrowserContextServices(context, true);
68257663e753af15633e48c7b00eb7b5880168090bGreg Clayton}
6936da2aa6dc5ad9994b638ed09eb81c44cc05540bGreg Clayton
70257663e753af15633e48c7b00eb7b5880168090bGreg Claytonvoid BrowserContextDependencyManager::DoCreateBrowserContextServices(
71257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    content::BrowserContext* context,
72bc36a861b8e0b2f2dde34f27c9fa9629a357d598Greg Clayton    bool is_testing_context) {
73257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  TRACE_EVENT0(
74257663e753af15633e48c7b00eb7b5880168090bGreg Clayton      "browser",
75257663e753af15633e48c7b00eb7b5880168090bGreg Clayton      "BrowserContextDependencyManager::DoCreateBrowserContextServices")
76257663e753af15633e48c7b00eb7b5880168090bGreg Clayton#ifndef NDEBUG
77257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  MarkBrowserContextLiveForTesting(context);
78257663e753af15633e48c7b00eb7b5880168090bGreg Clayton#endif
79257663e753af15633e48c7b00eb7b5880168090bGreg Clayton
80257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  will_create_browser_context_services_callbacks_.Notify(context);
81257663e753af15633e48c7b00eb7b5880168090bGreg Clayton
82257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  std::vector<DependencyNode*> construction_order;
83257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  if (!dependency_graph_.GetConstructionOrder(&construction_order)) {
84257663e753af15633e48c7b00eb7b5880168090bGreg Clayton    NOTREACHED();
85257663e753af15633e48c7b00eb7b5880168090bGreg Clayton  }
86257663e753af15633e48c7b00eb7b5880168090bGreg Clayton
8724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#ifndef NDEBUG
8824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DumpBrowserContextDependencies(context);
89257663e753af15633e48c7b00eb7b5880168090bGreg Clayton#endif
90257663e753af15633e48c7b00eb7b5880168090bGreg Clayton
9124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  for (size_t i = 0; i < construction_order.size(); i++) {
9224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    BrowserContextKeyedBaseFactory* factory =
9324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        static_cast<BrowserContextKeyedBaseFactory*>(construction_order[i]);
9424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    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
104void 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
133scoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription>
134BrowserContextDependencyManager::
135RegisterWillCreateBrowserContextServicesCallbackForTesting(
136    const base::Callback<void(content::BrowserContext*)>& callback) {
137  return will_create_browser_context_services_callbacks_.Add(callback);
138}
139
140#ifndef NDEBUG
141void 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
152void BrowserContextDependencyManager::MarkBrowserContextLiveForTesting(
153    content::BrowserContext* context) {
154  dead_context_pointers_.erase(context);
155}
156#endif
157
158// static
159BrowserContextDependencyManager*
160BrowserContextDependencyManager::GetInstance() {
161  return Singleton<BrowserContextDependencyManager>::get();
162}
163
164BrowserContextDependencyManager::BrowserContextDependencyManager() {}
165
166BrowserContextDependencyManager::~BrowserContextDependencyManager() {}
167
168#ifndef NDEBUG
169namespace {
170
171std::string BrowserContextKeyedBaseFactoryGetNodeName(DependencyNode* node) {
172  return static_cast<BrowserContextKeyedBaseFactory*>(node)->name();
173}
174
175}  // namespace
176
177void 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