| 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<void*> 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<void*> 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(void* 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 |