blob: f32fc617baddc97209cc5e713cf55f89ddbba4f5 [file] [log] [blame]
// Copyright (c) 2012 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 <algorithm>
#include <deque>
#include <iterator>
#include "apps/app_restore_service_factory.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/background/background_contents_service_factory.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/content_settings/cookie_settings.h"
#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
#include "chrome/browser/download/download_service_factory.h"
#include "chrome/browser/extensions/activity_log.h"
#include "chrome/browser/extensions/api/bluetooth/bluetooth_api_factory.h"
#include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h"
#include "chrome/browser/extensions/api/commands/command_service.h"
#include "chrome/browser/extensions/api/cookies/cookies_api.h"
#include "chrome/browser/extensions/api/dial/dial_api_factory.h"
#include "chrome/browser/extensions/api/discovery/suggested_links_registry_factory.h"
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
#include "chrome/browser/extensions/api/file_handlers/file_handlers_api.h"
#include "chrome/browser/extensions/api/font_settings/font_settings_api.h"
#include "chrome/browser/extensions/api/history/history_api.h"
#include "chrome/browser/extensions/api/idle/idle_manager_factory.h"
#include "chrome/browser/extensions/api/input/input.h"
#include "chrome/browser/extensions/api/managed_mode/managed_mode_api.h"
#include "chrome/browser/extensions/api/management/management_api.h"
#include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h"
#include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
#include "chrome/browser/extensions/api/preference/preference_api.h"
#include "chrome/browser/extensions/api/processes/processes_api.h"
#include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h"
#include "chrome/browser/extensions/api/session_restore/session_restore_api.h"
#include "chrome/browser/extensions/api/tab_capture/tab_capture_registry_factory.h"
#include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
#include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
#include "chrome/browser/extensions/extension_system_factory.h"
#include "chrome/browser/extensions/manifest_url_parser.h"
#include "chrome/browser/extensions/web_accessible_resources_parser.h"
#include "chrome/browser/extensions/web_intents_parser.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/geolocation/chrome_geolocation_permission_context_factory.h"
#include "chrome/browser/google/google_url_tracker_factory.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/history/shortcuts_backend_factory.h"
#include "chrome/browser/intents/web_intents_registry_factory.h"
#include "chrome/browser/media_gallery/media_galleries_preferences_factory.h"
#include "chrome/browser/notifications/desktop_notification_service_factory.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/plugins/plugin_prefs_factory.h"
#include "chrome/browser/predictors/autocomplete_action_predictor_factory.h"
#include "chrome/browser/predictors/predictor_database_factory.h"
#include "chrome/browser/predictors/resource_prefetch_predictor_factory.h"
#include "chrome/browser/prerender/prerender_link_manager_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/gaia_info_update_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_fetcher_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 "chrome/browser/signin/about_signin_internals_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/signin/token_service_factory.h"
#include "chrome/browser/speech/chrome_speech_recognition_preferences.h"
#include "chrome/browser/speech/extension_api/tts_extension_api.h"
#include "chrome/browser/speech/speech_input_extension_manager.h"
#include "chrome/browser/spellchecker/spellcheck_factory.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/thumbnails/thumbnail_service_factory.h"
#include "chrome/browser/ui/find_bar/find_bar_state_factory.h"
#include "chrome/browser/ui/global_error/global_error_service_factory.h"
#include "chrome/browser/ui/tabs/pinned_tab_service_factory.h"
#include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h"
#include "chrome/browser/user_style_sheet_watcher_factory.h"
#include "chrome/browser/webdata/web_data_service_factory.h"
#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
#include "chrome/browser/captive_portal/captive_portal_service_factory.h"
#endif
#if defined(ENABLE_CONFIGURATION_POLICY)
#include "chrome/browser/policy/user_policy_signin_service_factory.h"
#endif
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/extensions/input_method_api.h"
#include "chrome/browser/chromeos/extensions/media_player_api.h"
#include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
#if defined(FILE_MANAGER_EXTENSION)
#include "chrome/browser/chromeos/extensions/file_browser_private_api_factory.h"
#endif
#endif
#if defined(USE_AURA)
#include "chrome/browser/ui/gesture_prefs_observer_factory_aura.h"
#endif
#ifndef NDEBUG
#include "base/command_line.h"
#include "base/file_util.h"
#include "chrome/common/chrome_switches.h"
#endif
class Profile;
void ProfileDependencyManager::AddComponent(
ProfileKeyedBaseFactory* component) {
all_components_.push_back(component);
destruction_order_.clear();
}
void ProfileDependencyManager::RemoveComponent(
ProfileKeyedBaseFactory* 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(ProfileKeyedBaseFactory* depended,
ProfileKeyedBaseFactory* 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(profile);
// Iterate in reverse destruction order for creation.
for (std::vector<ProfileKeyedBaseFactory*>::reverse_iterator rit =
destruction_order_.rbegin(); rit != destruction_order_.rend();
++rit) {
if (!profile->IsOffTheRecord()) {
// We only register preferences on normal profiles because the incognito
// profile shares the pref service with the normal one.
(*rit)->RegisterUserPrefsOnProfile(profile);
}
if (is_testing_profile && (*rit)->ServiceIsNULLWhileTesting()) {
(*rit)->SetEmptyTestingFactory(profile);
} else if ((*rit)->ServiceIsCreatedWithProfile()) {
// Create the service.
(*rit)->CreateServiceNow(profile);
}
}
}
void ProfileDependencyManager::DestroyProfileServices(Profile* profile) {
if (destruction_order_.empty())
BuildDestructionOrder(profile);
for (std::vector<ProfileKeyedBaseFactory*>::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<ProfileKeyedBaseFactory*>::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<ProfileDependencyManager>::get();
}
ProfileDependencyManager::ProfileDependencyManager()
: built_factories_(false) {
}
ProfileDependencyManager::~ProfileDependencyManager() {}
// This method gets the instance of each ServiceFactory. We do this so that
// each ServiceFactory initializes itself 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 ProfileDependencyManager::AssertFactoriesBuilt() {
if (built_factories_)
return;
AboutSigninInternalsFactory::GetInstance();
#if defined(ENABLE_BACKGROUND)
BackgroundContentsServiceFactory::GetInstance();
#endif
BookmarkModelFactory::GetInstance();
#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
captive_portal::CaptivePortalServiceFactory::GetInstance();
#endif
ChromeGeolocationPermissionContextFactory::GetInstance();
#if defined(ENABLE_PRINTING)
CloudPrintProxyServiceFactory::GetInstance();
#endif
CookieSettings::Factory::GetInstance();
#if defined(ENABLE_NOTIFICATIONS)
DesktopNotificationServiceFactory::GetInstance();
#endif
DownloadServiceFactory::GetInstance();
#if defined(ENABLE_EXTENSIONS)
apps::AppRestoreServiceFactory::GetInstance();
extensions::ActivityLogFactory::GetInstance();
extensions::BookmarksAPI::GetFactoryInstance();
extensions::BluetoothAPIFactory::GetInstance();
extensions::CommandService::GetFactoryInstance();
extensions::CookiesAPI::GetFactoryInstance();
extensions::DialAPIFactory::GetInstance();
extensions::ExtensionActionAPI::GetFactoryInstance();
extensions::ExtensionSystemFactory::GetInstance();
extensions::FileHandlersAPI::GetFactoryInstance();
extensions::FontSettingsAPI::GetFactoryInstance();
extensions::HistoryAPI::GetFactoryInstance();
extensions::IdleManagerFactory::GetInstance();
#if defined(TOOLKIT_VIEWS)
extensions::InputAPI::GetFactoryInstance();
#endif
#if defined(OS_CHROMEOS)
extensions::InputImeAPI::GetFactoryInstance();
extensions::InputMethodAPI::GetFactoryInstance();
#endif
extensions::ManagedModeAPI::GetFactoryInstance();
extensions::ManagementAPI::GetFactoryInstance();
extensions::ManifestURLParser::GetFactoryInstance();
extensions::MediaGalleriesPrivateAPI::GetFactoryInstance();
#if defined(OS_CHROMEOS)
extensions::MediaPlayerAPI::GetFactoryInstance();
#endif
extensions::OmniboxAPI::GetFactoryInstance();
extensions::PreferenceAPI::GetFactoryInstance();
extensions::ProcessesAPI::GetFactoryInstance();
extensions::PushMessagingAPI::GetFactoryInstance();
extensions::SessionRestoreAPI::GetFactoryInstance();
#if defined(ENABLE_INPUT_SPEECH)
extensions::SpeechInputAPI::GetFactoryInstance();
#endif
extensions::SuggestedLinksRegistryFactory::GetInstance();
extensions::TabCaptureRegistryFactory::GetInstance();
extensions::TabsWindowsAPI::GetFactoryInstance();
extensions::TtsAPI::GetFactoryInstance();
extensions::WebAccessibleResourcesParser::GetFactoryInstance();
extensions::WebIntentsParser::GetFactoryInstance();
extensions::WebNavigationAPI::GetFactoryInstance();
#endif
FaviconServiceFactory::GetInstance();
#if defined(OS_CHROMEOS) && defined(FILE_MANAGER_EXTENSION)
FileBrowserPrivateAPIFactory::GetInstance();
#endif
FindBarStateFactory::GetInstance();
GAIAInfoUpdateServiceFactory::GetInstance();
#if defined(USE_AURA)
GesturePrefsObserverFactoryAura::GetInstance();
#endif
GlobalErrorServiceFactory::GetInstance();
GoogleURLTrackerFactory::GetInstance();
HistoryServiceFactory::GetInstance();
MediaGalleriesPreferencesFactory::GetInstance();
NTPResourceCacheFactory::GetInstance();
PasswordStoreFactory::GetInstance();
PersonalDataManagerFactory::GetInstance();
#if !defined(OS_ANDROID)
PinnedTabServiceFactory::GetInstance();
#endif
#if defined(ENABLE_PLUGINS)
PluginPrefsFactory::GetInstance();
#endif
#if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS)
// Not used on chromeos because signin happens before the profile is loaded.
policy::UserPolicySigninServiceFactory::GetInstance();
#endif
predictors::AutocompleteActionPredictorFactory::GetInstance();
predictors::PredictorDatabaseFactory::GetInstance();
predictors::ResourcePrefetchPredictorFactory::GetInstance();
prerender::PrerenderManagerFactory::GetInstance();
prerender::PrerenderLinkManagerFactory::GetInstance();
ProfileSyncServiceFactory::GetInstance();
ProtocolHandlerRegistryFactory::GetInstance();
#if defined(ENABLE_SESSION_SERVICE)
SessionServiceFactory::GetInstance();
#endif
ShortcutsBackendFactory::GetInstance();
ThumbnailServiceFactory::GetInstance();
SigninManagerFactory::GetInstance();
#if defined(ENABLE_INPUT_SPEECH)
ChromeSpeechRecognitionPreferences::InitializeFactory();
#endif
SpellcheckServiceFactory::GetInstance();
TabRestoreServiceFactory::GetInstance();
TemplateURLFetcherFactory::GetInstance();
TemplateURLServiceFactory::GetInstance();
#if defined(ENABLE_THEMES)
ThemeServiceFactory::GetInstance();
#endif
TokenServiceFactory::GetInstance();
UserStyleSheetWatcherFactory::GetInstance();
WebDataServiceFactory::GetInstance();
#if defined(ENABLE_WEB_INTENTS)
WebIntentsRegistryFactory::GetInstance();
#endif
built_factories_ = true;
}
void ProfileDependencyManager::BuildDestructionOrder(Profile* profile) {
#if !defined(NDEBUG)
// Whenever we try to build a destruction ordering, we should also dump a
// dependency graph to "/path/to/profile/profile-dependencies.dot".
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDumpProfileDependencyGraph)) {
FilePath dot_file =
profile->GetPath().AppendASCII("profile-dependencies.dot");
std::string contents = DumpGraphvizDependency();
file_util::WriteFile(dot_file, contents.c_str(), contents.size());
}
#endif
// Step 1: Build a set of nodes with no incoming edges.
std::deque<ProfileKeyedBaseFactory*> queue;
std::copy(all_components_.begin(),
all_components_.end(),
std::back_inserter(queue));
std::deque<ProfileKeyedBaseFactory*>::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<ProfileKeyedBaseFactory*> output;
EdgeMap edges(edges_);
while (!queue.empty()) {
ProfileKeyedBaseFactory* node = queue.front();
queue.pop_front();
output.push_back(node);
std::pair<EdgeMap::iterator, EdgeMap::iterator> range =
edges.equal_range(node);
EdgeMap::iterator it = range.first;
while (it != range.second) {
ProfileKeyedBaseFactory* 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;
}
#if !defined(NDEBUG)
std::string ProfileDependencyManager::DumpGraphvizDependency() {
std::string result("digraph {\n");
// Make a copy of all components.
std::deque<ProfileKeyedBaseFactory*> components;
std::copy(all_components_.begin(),
all_components_.end(),
std::back_inserter(components));
// State all dependencies and remove |second| so we don't generate an
// implicit dependency on the Profile hard coded node.
std::deque<ProfileKeyedBaseFactory*>::iterator components_end =
components.end();
result.append(" /* Dependencies */\n");
for (EdgeMap::const_iterator it = edges_.begin(); it != edges_.end(); ++it) {
result.append(" ");
result.append(it->second->name());
result.append(" -> ");
result.append(it->first->name());
result.append(";\n");
components_end = std::remove(components.begin(), components_end,
it->second);
}
components.erase(components_end, components.end());
// Every node that doesn't depend on anything else will implicitly depend on
// the Profile.
result.append("\n /* Toplevel attachments */\n");
for (std::deque<ProfileKeyedBaseFactory*>::const_iterator it =
components.begin(); it != components.end(); ++it) {
result.append(" ");
result.append((*it)->name());
result.append(" -> Profile;\n");
}
result.append("\n /* Toplevel profile */\n");
result.append(" Profile [shape=box];\n");
result.append("}\n");
return result;
}
#endif