OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/profiles/profile_dependency_manager.h" | 5 #include "chrome/browser/profiles/profile_dependency_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <deque> | 8 #include <deque> |
9 #include <iterator> | 9 #include <iterator> |
10 | 10 |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 #ifndef NDEBUG | 124 #ifndef NDEBUG |
125 #include "base/command_line.h" | 125 #include "base/command_line.h" |
126 #include "base/file_util.h" | 126 #include "base/file_util.h" |
127 #include "chrome/common/chrome_switches.h" | 127 #include "chrome/common/chrome_switches.h" |
128 #endif | 128 #endif |
129 | 129 |
130 class Profile; | 130 class Profile; |
131 | 131 |
132 void ProfileDependencyManager::AddComponent( | 132 void ProfileDependencyManager::AddComponent( |
133 ProfileKeyedBaseFactory* component) { | 133 ProfileKeyedBaseFactory* component) { |
134 all_components_.push_back(component); | 134 dependency_graph_.AddNode(component); |
135 destruction_order_.clear(); | |
136 } | 135 } |
137 | 136 |
138 void ProfileDependencyManager::RemoveComponent( | 137 void ProfileDependencyManager::RemoveComponent( |
139 ProfileKeyedBaseFactory* component) { | 138 ProfileKeyedBaseFactory* component) { |
140 all_components_.erase(std::remove(all_components_.begin(), | 139 dependency_graph_.RemoveNode(component); |
141 all_components_.end(), | |
142 component), | |
143 all_components_.end()); | |
144 | |
145 // Remove all dependency edges that contain this component. | |
146 EdgeMap::iterator it = edges_.begin(); | |
147 while (it != edges_.end()) { | |
148 EdgeMap::iterator temp = it; | |
149 ++it; | |
150 | |
151 if (temp->first == component || temp->second == component) | |
152 edges_.erase(temp); | |
153 } | |
154 | |
155 destruction_order_.clear(); | |
156 } | 140 } |
157 | 141 |
158 void ProfileDependencyManager::AddEdge(ProfileKeyedBaseFactory* depended, | 142 void ProfileDependencyManager::AddEdge(ProfileKeyedBaseFactory* depended, |
159 ProfileKeyedBaseFactory* dependee) { | 143 ProfileKeyedBaseFactory* dependee) { |
160 edges_.insert(std::make_pair(depended, dependee)); | 144 dependency_graph_.AddEdge(depended, dependee); |
161 destruction_order_.clear(); | |
162 } | 145 } |
163 | 146 |
164 void ProfileDependencyManager::CreateProfileServices(Profile* profile, | 147 void ProfileDependencyManager::CreateProfileServices(Profile* profile, |
165 bool is_testing_profile) { | 148 bool is_testing_profile) { |
166 #ifndef NDEBUG | 149 #ifndef NDEBUG |
167 // Unmark |profile| as dead. This exists because of unit tests, which will | 150 // Unmark |profile| as dead. This exists because of unit tests, which will |
168 // often have similar stack structures. 0xWhatever might be created, go out | 151 // often have similar stack structures. 0xWhatever might be created, go out |
169 // of scope, and then a new Profile object might be created at 0xWhatever. | 152 // of scope, and then a new Profile object might be created at 0xWhatever. |
170 dead_profile_pointers_.erase(profile); | 153 dead_profile_pointers_.erase(profile); |
171 #endif | 154 #endif |
172 | 155 |
173 AssertFactoriesBuilt(); | 156 AssertFactoriesBuilt(); |
174 | 157 |
175 if (destruction_order_.empty()) | 158 std::vector<DependencyNode*> construction_order; |
176 BuildDestructionOrder(profile); | 159 if (!dependency_graph_.GetConstructionOrder(&construction_order)) { |
| 160 NOTREACHED(); |
| 161 } |
177 | 162 |
178 // Iterate in reverse destruction order for creation. | 163 #ifndef NDEBUG |
179 for (std::vector<ProfileKeyedBaseFactory*>::reverse_iterator rit = | 164 DumpProfileDependencies(profile); |
180 destruction_order_.rbegin(); rit != destruction_order_.rend(); | 165 #endif |
181 ++rit) { | 166 |
| 167 for (size_t i = 0; i < construction_order.size(); i++) { |
| 168 ProfileKeyedBaseFactory* factory = |
| 169 static_cast<ProfileKeyedBaseFactory*>(construction_order[i]); |
| 170 |
182 if (!profile->IsOffTheRecord()) { | 171 if (!profile->IsOffTheRecord()) { |
183 // We only register preferences on normal profiles because the incognito | 172 // We only register preferences on normal profiles because the incognito |
184 // profile shares the pref service with the normal one. | 173 // profile shares the pref service with the normal one. |
185 (*rit)->RegisterUserPrefsOnProfile(profile); | 174 factory->RegisterUserPrefsOnProfile(profile); |
186 } | 175 } |
187 | 176 |
188 if (is_testing_profile && (*rit)->ServiceIsNULLWhileTesting()) { | 177 if (is_testing_profile && factory->ServiceIsNULLWhileTesting()) { |
189 (*rit)->SetEmptyTestingFactory(profile); | 178 factory->SetEmptyTestingFactory(profile); |
190 } else if ((*rit)->ServiceIsCreatedWithProfile()) { | 179 } else if (factory->ServiceIsCreatedWithProfile()) { |
191 // Create the service. | 180 // Create the service. |
192 (*rit)->CreateServiceNow(profile); | 181 factory->CreateServiceNow(profile); |
193 } | 182 } |
194 } | 183 } |
195 } | 184 } |
196 | 185 |
197 void ProfileDependencyManager::DestroyProfileServices(Profile* profile) { | 186 void ProfileDependencyManager::DestroyProfileServices(Profile* profile) { |
198 if (destruction_order_.empty()) | 187 std::vector<DependencyNode*> destruction_order; |
199 BuildDestructionOrder(profile); | 188 if (!dependency_graph_.GetDestructionOrder(&destruction_order)) { |
200 | 189 NOTREACHED(); |
201 for (std::vector<ProfileKeyedBaseFactory*>::const_iterator it = | |
202 destruction_order_.begin(); it != destruction_order_.end(); ++it) { | |
203 (*it)->ProfileShutdown(profile); | |
204 } | 190 } |
205 | 191 |
206 #ifndef NDEBUG | 192 #ifndef NDEBUG |
| 193 DumpProfileDependencies(profile); |
| 194 #endif |
| 195 |
| 196 for (size_t i = 0; i < destruction_order.size(); i++) { |
| 197 ProfileKeyedBaseFactory* factory = |
| 198 static_cast<ProfileKeyedBaseFactory*>(destruction_order[i]); |
| 199 factory->ProfileShutdown(profile); |
| 200 } |
| 201 |
| 202 #ifndef NDEBUG |
207 // The profile is now dead to the rest of the program. | 203 // The profile is now dead to the rest of the program. |
208 dead_profile_pointers_.insert(profile); | 204 dead_profile_pointers_.insert(profile); |
209 #endif | 205 #endif |
210 | 206 |
211 for (std::vector<ProfileKeyedBaseFactory*>::const_iterator it = | 207 for (size_t i = 0; i < destruction_order.size(); i++) { |
212 destruction_order_.begin(); it != destruction_order_.end(); ++it) { | 208 ProfileKeyedBaseFactory* factory = |
213 (*it)->ProfileDestroyed(profile); | 209 static_cast<ProfileKeyedBaseFactory*>(destruction_order[i]); |
| 210 factory->ProfileDestroyed(profile); |
214 } | 211 } |
215 } | 212 } |
216 | 213 |
217 #ifndef NDEBUG | 214 #ifndef NDEBUG |
218 void ProfileDependencyManager::AssertProfileWasntDestroyed(Profile* profile) { | 215 void ProfileDependencyManager::AssertProfileWasntDestroyed(Profile* profile) { |
219 if (dead_profile_pointers_.find(profile) != dead_profile_pointers_.end()) { | 216 if (dead_profile_pointers_.find(profile) != dead_profile_pointers_.end()) { |
220 NOTREACHED() << "Attempted to access a Profile that was ShutDown(). This " | 217 NOTREACHED() << "Attempted to access a Profile that was ShutDown(). This " |
221 << "is most likely a heap smasher in progress. After " | 218 << "is most likely a heap smasher in progress. After " |
222 << "ProfileKeyedService::Shutdown() completes, your service " | 219 << "ProfileKeyedService::Shutdown() completes, your service " |
223 << "MUST NOT refer to depended Profile services again."; | 220 << "MUST NOT refer to depended Profile services again."; |
224 } | 221 } |
225 } | 222 } |
226 #endif | 223 #endif |
227 | 224 |
228 // static | 225 // static |
229 ProfileDependencyManager* ProfileDependencyManager::GetInstance() { | 226 ProfileDependencyManager* ProfileDependencyManager::GetInstance() { |
230 return Singleton<ProfileDependencyManager>::get(); | 227 return Singleton<ProfileDependencyManager>::get(); |
231 } | 228 } |
232 | 229 |
| 230 namespace { |
| 231 |
| 232 std::string ProfileKeyedBaseFactoryGetNodeName(DependencyNode* node) { |
| 233 return static_cast<ProfileKeyedBaseFactory*>(node)->name(); |
| 234 } |
| 235 |
| 236 } // namespace |
| 237 |
233 ProfileDependencyManager::ProfileDependencyManager() | 238 ProfileDependencyManager::ProfileDependencyManager() |
234 : built_factories_(false) { | 239 : built_factories_(false), |
| 240 dependency_graph_(base::Bind(&ProfileKeyedBaseFactoryGetNodeName)) { |
235 } | 241 } |
236 | 242 |
237 ProfileDependencyManager::~ProfileDependencyManager() {} | 243 ProfileDependencyManager::~ProfileDependencyManager() {} |
238 | 244 |
239 // This method gets the instance of each ServiceFactory. We do this so that | 245 // This method gets the instance of each ServiceFactory. We do this so that |
240 // each ServiceFactory initializes itself and registers its dependencies with | 246 // each ServiceFactory initializes itself and registers its dependencies with |
241 // the global PreferenceDependencyManager. We need to have a complete | 247 // the global PreferenceDependencyManager. We need to have a complete |
242 // dependency graph when we create a profile so we can dispatch the profile | 248 // dependency graph when we create a profile so we can dispatch the profile |
243 // creation message to the services that want to create their services at | 249 // creation message to the services that want to create their services at |
244 // profile creation time. | 250 // profile creation time. |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 ThemeServiceFactory::GetInstance(); | 385 ThemeServiceFactory::GetInstance(); |
380 #endif | 386 #endif |
381 TokenCacheServiceFactory::GetInstance(); | 387 TokenCacheServiceFactory::GetInstance(); |
382 TokenServiceFactory::GetInstance(); | 388 TokenServiceFactory::GetInstance(); |
383 UserStyleSheetWatcherFactory::GetInstance(); | 389 UserStyleSheetWatcherFactory::GetInstance(); |
384 WebDataServiceFactory::GetInstance(); | 390 WebDataServiceFactory::GetInstance(); |
385 | 391 |
386 built_factories_ = true; | 392 built_factories_ = true; |
387 } | 393 } |
388 | 394 |
389 void ProfileDependencyManager::BuildDestructionOrder(Profile* profile) { | 395 #ifndef NDEBUG |
390 #if !defined(NDEBUG) | 396 void ProfileDependencyManager::DumpProfileDependencies(Profile* profile) { |
391 // Whenever we try to build a destruction ordering, we should also dump a | 397 // Whenever we try to build a destruction ordering, we should also dump a |
392 // dependency graph to "/path/to/profile/profile-dependencies.dot". | 398 // dependency graph to "/path/to/profile/profile-dependencies.dot". |
393 if (CommandLine::ForCurrentProcess()->HasSwitch( | 399 if (CommandLine::ForCurrentProcess()->HasSwitch( |
394 switches::kDumpProfileDependencyGraph)) { | 400 switches::kDumpProfileDependencyGraph)) { |
395 base::FilePath dot_file = | 401 base::FilePath dot_file = |
396 profile->GetPath().AppendASCII("profile-dependencies.dot"); | 402 profile->GetPath().AppendASCII("profile-dependencies.dot"); |
397 std::string contents = DumpGraphvizDependency(); | 403 std::string contents = dependency_graph_.DumpAsGraphviz("Profile"); |
398 file_util::WriteFile(dot_file, contents.c_str(), contents.size()); | 404 file_util::WriteFile(dot_file, contents.c_str(), contents.size()); |
399 } | 405 } |
| 406 } |
400 #endif | 407 #endif |
401 | |
402 // Step 1: Build a set of nodes with no incoming edges. | |
403 std::deque<ProfileKeyedBaseFactory*> queue; | |
404 std::copy(all_components_.begin(), | |
405 all_components_.end(), | |
406 std::back_inserter(queue)); | |
407 | |
408 std::deque<ProfileKeyedBaseFactory*>::iterator queue_end = queue.end(); | |
409 for (EdgeMap::const_iterator it = edges_.begin(); | |
410 it != edges_.end(); ++it) { | |
411 queue_end = std::remove(queue.begin(), queue_end, it->second); | |
412 } | |
413 queue.erase(queue_end, queue.end()); | |
414 | |
415 // Step 2: Do the Kahn topological sort. | |
416 std::vector<ProfileKeyedBaseFactory*> output; | |
417 EdgeMap edges(edges_); | |
418 while (!queue.empty()) { | |
419 ProfileKeyedBaseFactory* node = queue.front(); | |
420 queue.pop_front(); | |
421 output.push_back(node); | |
422 | |
423 std::pair<EdgeMap::iterator, EdgeMap::iterator> range = | |
424 edges.equal_range(node); | |
425 EdgeMap::iterator it = range.first; | |
426 while (it != range.second) { | |
427 ProfileKeyedBaseFactory* dest = it->second; | |
428 EdgeMap::iterator temp = it; | |
429 it++; | |
430 edges.erase(temp); | |
431 | |
432 bool has_incoming_edges = false; | |
433 for (EdgeMap::iterator jt = edges.begin(); jt != edges.end(); ++jt) { | |
434 if (jt->second == dest) { | |
435 has_incoming_edges = true; | |
436 break; | |
437 } | |
438 } | |
439 | |
440 if (!has_incoming_edges) | |
441 queue.push_back(dest); | |
442 } | |
443 } | |
444 | |
445 if (edges.size()) { | |
446 NOTREACHED() << "Dependency graph has a cycle. We are doomed."; | |
447 } | |
448 | |
449 std::reverse(output.begin(), output.end()); | |
450 destruction_order_ = output; | |
451 } | |
452 | |
453 #if !defined(NDEBUG) | |
454 | |
455 std::string ProfileDependencyManager::DumpGraphvizDependency() { | |
456 std::string result("digraph {\n"); | |
457 | |
458 // Make a copy of all components. | |
459 std::deque<ProfileKeyedBaseFactory*> components; | |
460 std::copy(all_components_.begin(), | |
461 all_components_.end(), | |
462 std::back_inserter(components)); | |
463 | |
464 // State all dependencies and remove |second| so we don't generate an | |
465 // implicit dependency on the Profile hard coded node. | |
466 std::deque<ProfileKeyedBaseFactory*>::iterator components_end = | |
467 components.end(); | |
468 result.append(" /* Dependencies */\n"); | |
469 for (EdgeMap::const_iterator it = edges_.begin(); it != edges_.end(); ++it) { | |
470 result.append(" "); | |
471 result.append(it->second->name()); | |
472 result.append(" -> "); | |
473 result.append(it->first->name()); | |
474 result.append(";\n"); | |
475 | |
476 components_end = std::remove(components.begin(), components_end, | |
477 it->second); | |
478 } | |
479 components.erase(components_end, components.end()); | |
480 | |
481 // Every node that doesn't depend on anything else will implicitly depend on | |
482 // the Profile. | |
483 result.append("\n /* Toplevel attachments */\n"); | |
484 for (std::deque<ProfileKeyedBaseFactory*>::const_iterator it = | |
485 components.begin(); it != components.end(); ++it) { | |
486 result.append(" "); | |
487 result.append((*it)->name()); | |
488 result.append(" -> Profile;\n"); | |
489 } | |
490 | |
491 result.append("\n /* Toplevel profile */\n"); | |
492 result.append(" Profile [shape=box];\n"); | |
493 | |
494 result.append("}\n"); | |
495 return result; | |
496 } | |
497 | |
498 #endif | |
OLD | NEW |