| 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 |
| 229 namespace { |
| 230 |
| 231 std::string ProfileKeyedBaseFactoryGetNodeName(DependencyNode* node) { |
| 232 return static_cast<ProfileKeyedBaseFactory*>(node)->name(); |
| 233 } |
| 234 |
| 235 } // namespace |
| 236 |
| 232 ProfileDependencyManager::ProfileDependencyManager() | 237 ProfileDependencyManager::ProfileDependencyManager() |
| 233 : built_factories_(false) { | 238 : built_factories_(false), |
| 239 dependency_graph_(base::Bind(&ProfileKeyedBaseFactoryGetNodeName)) { |
| 234 } | 240 } |
| 235 | 241 |
| 236 ProfileDependencyManager::~ProfileDependencyManager() {} | 242 ProfileDependencyManager::~ProfileDependencyManager() {} |
| 237 | 243 |
| 238 // This method gets the instance of each ServiceFactory. We do this so that | 244 // This method gets the instance of each ServiceFactory. We do this so that |
| 239 // each ServiceFactory initializes itself and registers its dependencies with | 245 // each ServiceFactory initializes itself and registers its dependencies with |
| 240 // the global PreferenceDependencyManager. We need to have a complete | 246 // the global PreferenceDependencyManager. We need to have a complete |
| 241 // dependency graph when we create a profile so we can dispatch the profile | 247 // 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 | 248 // creation message to the services that want to create their services at |
| 243 // profile creation time. | 249 // profile creation time. |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 ThemeServiceFactory::GetInstance(); | 383 ThemeServiceFactory::GetInstance(); |
| 378 #endif | 384 #endif |
| 379 TokenCacheServiceFactory::GetInstance(); | 385 TokenCacheServiceFactory::GetInstance(); |
| 380 TokenServiceFactory::GetInstance(); | 386 TokenServiceFactory::GetInstance(); |
| 381 UserStyleSheetWatcherFactory::GetInstance(); | 387 UserStyleSheetWatcherFactory::GetInstance(); |
| 382 WebDataServiceFactory::GetInstance(); | 388 WebDataServiceFactory::GetInstance(); |
| 383 | 389 |
| 384 built_factories_ = true; | 390 built_factories_ = true; |
| 385 } | 391 } |
| 386 | 392 |
| 387 void ProfileDependencyManager::BuildDestructionOrder(Profile* profile) { | 393 #ifndef NDEBUG |
| 388 #if !defined(NDEBUG) | 394 void ProfileDependencyManager::DumpProfileDependencies(Profile* profile) { |
| 389 // Whenever we try to build a destruction ordering, we should also dump a | 395 // Whenever we try to build a destruction ordering, we should also dump a |
| 390 // dependency graph to "/path/to/profile/profile-dependencies.dot". | 396 // dependency graph to "/path/to/profile/profile-dependencies.dot". |
| 391 if (CommandLine::ForCurrentProcess()->HasSwitch( | 397 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 392 switches::kDumpProfileDependencyGraph)) { | 398 switches::kDumpProfileDependencyGraph)) { |
| 393 base::FilePath dot_file = | 399 base::FilePath dot_file = |
| 394 profile->GetPath().AppendASCII("profile-dependencies.dot"); | 400 profile->GetPath().AppendASCII("profile-dependencies.dot"); |
| 395 std::string contents = DumpGraphvizDependency(); | 401 std::string contents = dependency_graph_.DumpAsGraphviz("Profile"); |
| 396 file_util::WriteFile(dot_file, contents.c_str(), contents.size()); | 402 file_util::WriteFile(dot_file, contents.c_str(), contents.size()); |
| 397 } | 403 } |
| 404 } |
| 398 #endif | 405 #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 } | |
| 450 | |
| 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 |