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