browser_context_dependency_manager.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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.
22const char kDumpBrowserContextDependencyGraphFlag[] =
23    "dump-browser-context-graph";
24#endif  // NDEBUG
25
26void BrowserContextDependencyManager::AddComponent(
27    BrowserContextKeyedBaseFactory* component) {
28  dependency_graph_.AddNode(component);
29}
30
31void BrowserContextDependencyManager::RemoveComponent(
32    BrowserContextKeyedBaseFactory* component) {
33  dependency_graph_.RemoveNode(component);
34}
35
36void BrowserContextDependencyManager::AddEdge(
37    BrowserContextKeyedBaseFactory* depended,
38    BrowserContextKeyedBaseFactory* dependee) {
39  dependency_graph_.AddEdge(depended, dependee);
40}
41
42void 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
60void BrowserContextDependencyManager::CreateBrowserContextServices(
61    content::BrowserContext* context) {
62  DoCreateBrowserContextServices(context, false);
63}
64
65void BrowserContextDependencyManager::CreateBrowserContextServicesForTest(
66    content::BrowserContext* context) {
67  DoCreateBrowserContextServices(context, true);
68}
69
70void 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->SetEmptyTestingFactory(context);
96    } else if (factory->ServiceIsCreatedWithBrowserContext()) {
97      // Create the service.
98      factory->CreateServiceNow(context);
99    }
100  }
101}
102
103void BrowserContextDependencyManager::DestroyBrowserContextServices(
104    content::BrowserContext* context) {
105  std::vector<DependencyNode*> destruction_order;
106  if (!dependency_graph_.GetDestructionOrder(&destruction_order)) {
107    NOTREACHED();
108  }
109
110#ifndef NDEBUG
111  DumpBrowserContextDependencies(context);
112#endif
113
114  for (size_t i = 0; i < destruction_order.size(); i++) {
115    BrowserContextKeyedBaseFactory* factory =
116        static_cast<BrowserContextKeyedBaseFactory*>(destruction_order[i]);
117    factory->BrowserContextShutdown(context);
118  }
119
120#ifndef NDEBUG
121  // The context is now dead to the rest of the program.
122  dead_context_pointers_.insert(context);
123#endif
124
125  for (size_t i = 0; i < destruction_order.size(); i++) {
126    BrowserContextKeyedBaseFactory* factory =
127        static_cast<BrowserContextKeyedBaseFactory*>(destruction_order[i]);
128    factory->BrowserContextDestroyed(context);
129  }
130}
131
132scoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription>
133BrowserContextDependencyManager::
134RegisterWillCreateBrowserContextServicesCallbackForTesting(
135    const base::Callback<void(content::BrowserContext*)>& callback) {
136  return will_create_browser_context_services_callbacks_.Add(callback);
137}
138
139#ifndef NDEBUG
140void BrowserContextDependencyManager::AssertBrowserContextWasntDestroyed(
141    content::BrowserContext* context) {
142  if (dead_context_pointers_.find(context) != dead_context_pointers_.end()) {
143    NOTREACHED() << "Attempted to access a BrowserContext that was ShutDown(). "
144                 << "This is most likely a heap smasher in progress. After "
145                 << "KeyedService::Shutdown() completes, your "
146                 << "service MUST NOT refer to depended BrowserContext "
147                 << "services again.";
148  }
149}
150
151void BrowserContextDependencyManager::MarkBrowserContextLiveForTesting(
152    content::BrowserContext* context) {
153  dead_context_pointers_.erase(context);
154}
155#endif
156
157// static
158BrowserContextDependencyManager*
159BrowserContextDependencyManager::GetInstance() {
160  return Singleton<BrowserContextDependencyManager>::get();
161}
162
163BrowserContextDependencyManager::BrowserContextDependencyManager() {}
164
165BrowserContextDependencyManager::~BrowserContextDependencyManager() {}
166
167#ifndef NDEBUG
168namespace {
169
170std::string BrowserContextKeyedBaseFactoryGetNodeName(DependencyNode* node) {
171  return static_cast<BrowserContextKeyedBaseFactory*>(node)->name();
172}
173
174}  // namespace
175
176void BrowserContextDependencyManager::DumpBrowserContextDependencies(
177    content::BrowserContext* context) {
178  // Whenever we try to build a destruction ordering, we should also dump a
179  // dependency graph to "/path/to/context/context-dependencies.dot".
180  if (CommandLine::ForCurrentProcess()->HasSwitch(
181          kDumpBrowserContextDependencyGraphFlag)) {
182    base::FilePath dot_file =
183        context->GetPath().AppendASCII("browser-context-dependencies.dot");
184    std::string contents = dependency_graph_.DumpAsGraphviz(
185        "BrowserContext",
186        base::Bind(&BrowserContextKeyedBaseFactoryGetNodeName));
187    base::WriteFile(dot_file, contents.c_str(), contents.size());
188  }
189}
190#endif  // NDEBUG
191