// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/profiles/profile_dependency_manager.h" #include #include #include #include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/background/background_contents_service_factory.h" #include "chrome/browser/extensions/speech_input/extension_speech_input_manager.h" #include "chrome/browser/plugin_prefs_factory.h" #include "chrome/browser/prerender/prerender_manager_factory.h" #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_keyed_service.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/sessions/session_service_factory.h" #include "chrome/browser/sessions/tab_restore_service_factory.h" #include "content/common/notification_service.h" class Profile; namespace { bool g_initialized = false; // This method gets the instance of each ServiceFactory. We do this so that // each ServiceFactory initializes iteslf and registers its dependencies with // the global PreferenceDependencyManager. We need to have a complete // dependency graph when we create a profile so we can dispatch the profile // creation message to the services that want to create their services at // profile creation time. // // TODO(erg): This needs to be something else. I don't think putting every // FooServiceFactory here will scale or is desireable long term. void AssertFactoriesBuilt() { if (!g_initialized) { BackgroundContentsServiceFactory::GetInstance(); CloudPrintProxyServiceFactory::GetInstance(); PersonalDataManagerFactory::GetInstance(); PluginPrefsFactory::GetInstance(); prerender::PrerenderManagerFactory::GetInstance(); SessionServiceFactory::GetInstance(); TabRestoreServiceFactory::GetInstance(); TemplateURLServiceFactory::GetInstance(); ExtensionSpeechInputManager::InitializeFactory(); g_initialized = true; } } } // namespace void ProfileDependencyManager::AddComponent( ProfileKeyedServiceFactory* component) { all_components_.push_back(component); destruction_order_.clear(); } void ProfileDependencyManager::RemoveComponent( ProfileKeyedServiceFactory* component) { all_components_.erase(std::remove(all_components_.begin(), all_components_.end(), component), all_components_.end()); // Remove all dependency edges that contain this component. EdgeMap::iterator it = edges_.begin(); while (it != edges_.end()) { EdgeMap::iterator temp = it; ++it; if (temp->first == component || temp->second == component) edges_.erase(temp); } destruction_order_.clear(); } void ProfileDependencyManager::AddEdge(ProfileKeyedServiceFactory* depended, ProfileKeyedServiceFactory* dependee) { edges_.insert(std::make_pair(depended, dependee)); destruction_order_.clear(); } void ProfileDependencyManager::CreateProfileServices(Profile* profile, bool is_testing_profile) { #ifndef NDEBUG // Unmark |profile| as dead. This exists because of unit tests, which will // often have similar stack structures. 0xWhatever might be created, go out // of scope, and then a new Profile object might be created at 0xWhatever. dead_profile_pointers_.erase(profile); #endif AssertFactoriesBuilt(); if (destruction_order_.empty()) BuildDestructionOrder(); // Iterate in reverse destruction order for creation. for (std::vector::reverse_iterator rit = destruction_order_.rbegin(); rit != destruction_order_.rend(); ++rit) { if (!profile->IsOffTheRecord() && !profile->AsTestingProfile()) { // We only register preferences on normal profiles because the incognito // profile shares the pref service with the normal one and the testing // profile will often just insert its own PrefService. (*rit)->RegisterUserPrefsOnProfile(profile); } if (is_testing_profile && (*rit)->ServiceIsNULLWhileTesting()) { (*rit)->SetTestingFactory(profile, NULL); } else if ((*rit)->ServiceIsCreatedWithProfile()) { // Create the service. (*rit)->GetServiceForProfile(profile, true); } } } void ProfileDependencyManager::DestroyProfileServices(Profile* profile) { if (destruction_order_.empty()) BuildDestructionOrder(); for (std::vector::const_iterator it = destruction_order_.begin(); it != destruction_order_.end(); ++it) { (*it)->ProfileShutdown(profile); } #ifndef NDEBUG // The profile is now dead to the rest of the program. dead_profile_pointers_.insert(profile); #endif for (std::vector::const_iterator it = destruction_order_.begin(); it != destruction_order_.end(); ++it) { (*it)->ProfileDestroyed(profile); } } #ifndef NDEBUG void ProfileDependencyManager::AssertProfileWasntDestroyed(Profile* profile) { if (dead_profile_pointers_.find(profile) != dead_profile_pointers_.end()) { NOTREACHED() << "Attempted to access a Profile that was ShutDown(). This " << "is most likely a heap smasher in progress. After " << "ProfileKeyedService::Shutdown() completes, your service " << "MUST NOT refer to depended Profile services again."; } } #endif // static ProfileDependencyManager* ProfileDependencyManager::GetInstance() { return Singleton::get(); } ProfileDependencyManager::ProfileDependencyManager() {} ProfileDependencyManager::~ProfileDependencyManager() {} void ProfileDependencyManager::BuildDestructionOrder() { // Step 1: Build a set of nodes with no incoming edges. std::deque queue; std::copy(all_components_.begin(), all_components_.end(), std::back_inserter(queue)); std::deque::iterator queue_end = queue.end(); for (EdgeMap::const_iterator it = edges_.begin(); it != edges_.end(); ++it) { queue_end = std::remove(queue.begin(), queue_end, it->second); } queue.erase(queue_end, queue.end()); // Step 2: Do the Kahn topological sort. std::vector output; EdgeMap edges(edges_); while (!queue.empty()) { ProfileKeyedServiceFactory* node = queue.front(); queue.pop_front(); output.push_back(node); std::pair range = edges.equal_range(node); EdgeMap::iterator it = range.first; while (it != range.second) { ProfileKeyedServiceFactory* dest = it->second; EdgeMap::iterator temp = it; it++; edges.erase(temp); bool has_incoming_edges = false; for (EdgeMap::iterator jt = edges.begin(); jt != edges.end(); ++jt) { if (jt->second == dest) { has_incoming_edges = true; break; } } if (!has_incoming_edges) queue.push_back(dest); } } if (edges.size()) { NOTREACHED() << "Dependency graph has a cycle. We are doomed."; } std::reverse(output.begin(), output.end()); destruction_order_ = output; }