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.
5 #include "components/keyed_service/core/dependency_manager.h"
8 #include "base/logging.h"
9 #include "base/supports_user_data.h"
10 #include "components/keyed_service/core/keyed_service_base_factory.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
17 DependencyManager::DependencyManager() {
20 DependencyManager::~DependencyManager() {
23 void DependencyManager::AddComponent(KeyedServiceBaseFactory
* component
) {
24 dependency_graph_
.AddNode(component
);
27 void DependencyManager::RemoveComponent(KeyedServiceBaseFactory
* component
) {
28 dependency_graph_
.RemoveNode(component
);
31 void DependencyManager::AddEdge(KeyedServiceBaseFactory
* depended
,
32 KeyedServiceBaseFactory
* dependee
) {
33 dependency_graph_
.AddEdge(depended
, dependee
);
36 void DependencyManager::RegisterPrefsForServices(
37 base::SupportsUserData
* context
,
38 user_prefs::PrefRegistrySyncable
* pref_registry
) {
39 std::vector
<DependencyNode
*> construction_order
;
40 if (!dependency_graph_
.GetConstructionOrder(&construction_order
)) {
44 for (const auto& dependency_node
: construction_order
) {
45 KeyedServiceBaseFactory
* factory
=
46 static_cast<KeyedServiceBaseFactory
*>(dependency_node
);
47 base::SupportsUserData
* typed_context
= factory
->GetTypedContext(context
);
48 factory
->RegisterPrefsIfNecessaryForContext(typed_context
, pref_registry
);
52 void DependencyManager::CreateContextServices(base::SupportsUserData
* context
,
53 bool is_testing_context
) {
55 MarkContextLiveForTesting(context
);
58 std::vector
<DependencyNode
*> construction_order
;
59 if (!dependency_graph_
.GetConstructionOrder(&construction_order
)) {
64 DumpContextDependencies(context
);
67 for (const auto& dependency_node
: construction_order
) {
68 KeyedServiceBaseFactory
* factory
=
69 static_cast<KeyedServiceBaseFactory
*>(dependency_node
);
70 base::SupportsUserData
* typed_context
= factory
->GetTypedContext(context
);
71 if (is_testing_context
&& factory
->ServiceIsNULLWhileTesting() &&
72 !factory
->HasTestingFactory(typed_context
)) {
73 factory
->SetEmptyTestingFactory(typed_context
);
74 } else if (factory
->ServiceIsCreatedWithContext()) {
75 factory
->CreateServiceNow(typed_context
);
80 void DependencyManager::DestroyContextServices(
81 base::SupportsUserData
* context
) {
82 std::vector
<DependencyNode
*> destruction_order
;
83 if (!dependency_graph_
.GetDestructionOrder(&destruction_order
)) {
88 DumpContextDependencies(context
);
91 for (const auto& dependency_node
: destruction_order
) {
92 KeyedServiceBaseFactory
* factory
=
93 static_cast<KeyedServiceBaseFactory
*>(dependency_node
);
94 base::SupportsUserData
* typed_context
= factory
->GetTypedContext(context
);
95 factory
->ContextShutdown(typed_context
);
99 // The context is now dead to the rest of the program.
100 dead_context_pointers_
.insert(context
);
103 for (const auto& dependency_node
: destruction_order
) {
104 KeyedServiceBaseFactory
* factory
=
105 static_cast<KeyedServiceBaseFactory
*>(dependency_node
);
106 base::SupportsUserData
* typed_context
= factory
->GetTypedContext(context
);
107 factory
->ContextDestroyed(typed_context
);
112 void DependencyManager::AssertContextWasntDestroyed(
113 base::SupportsUserData
* context
) {
114 if (dead_context_pointers_
.find(context
) != dead_context_pointers_
.end()) {
115 NOTREACHED() << "Attempted to access a context that was ShutDown(). "
116 << "This is most likely a heap smasher in progress. After "
117 << "KeyedService::Shutdown() completes, your service MUST "
118 << "NOT refer to depended services again.";
122 void DependencyManager::MarkContextLiveForTesting(
123 base::SupportsUserData
* context
) {
124 dead_context_pointers_
.erase(context
);
129 std::string
KeyedServiceBaseFactoryGetNodeName(DependencyNode
* node
) {
130 return static_cast<KeyedServiceBaseFactory
*>(node
)->name();
135 void DependencyManager::DumpDependenciesAsGraphviz(
136 const std::string
& top_level_name
,
137 const base::FilePath
& dot_file
) const {
138 DCHECK(!dot_file
.empty());
139 std::string contents
= dependency_graph_
.DumpAsGraphviz(
140 top_level_name
, base::Bind(&KeyedServiceBaseFactoryGetNodeName
));
141 base::WriteFile(dot_file
, contents
.c_str(), contents
.size());