blob: 4e590660ec035e892e795cf2d2449ae1cee1e241 [file] [log] [blame]
// Copyright (c) 2009 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 <set>
#include "chrome/browser/profile_manager.h"
#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/net/url_request_context_getter.h"
#include "chrome/browser/pref_service.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "net/http/http_transaction_factory.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_job_tracker.h"
// static
void ProfileManager::ShutdownSessionServices() {
ProfileManager* pm = g_browser_process->profile_manager();
for (ProfileManager::const_iterator i = pm->begin(); i != pm->end(); ++i)
(*i)->ShutdownSessionService();
}
// static
Profile* ProfileManager::GetLoginWizardProfile() {
FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
ProfileManager* profile_manager = g_browser_process->profile_manager();
return profile_manager->GetDefaultProfile(
user_data_dir)->GetOffTheRecordProfile();
}
ProfileManager::ProfileManager() : logged_in_(false) {
SystemMonitor::Get()->AddObserver(this);
#if defined(OS_CHROMEOS)
registrar_.Add(
this,
NotificationType::LOGIN_USER_CHANGED,
NotificationService::AllSources());
#endif
}
ProfileManager::~ProfileManager() {
SystemMonitor* system_monitor = SystemMonitor::Get();
if (system_monitor)
system_monitor->RemoveObserver(this);
// Destroy all profiles that we're keeping track of.
for (const_iterator i(begin()); i != end(); ++i)
delete *i;
profiles_.clear();
// Get rid of available profile list
for (AvailableProfileVector::const_iterator i(available_profiles_.begin());
i != available_profiles_.end(); ++i)
delete *i;
available_profiles_.clear();
}
FilePath ProfileManager::GetDefaultProfileDir(
const FilePath& user_data_dir) {
FilePath default_profile_dir(user_data_dir);
default_profile_dir = default_profile_dir.Append(
FilePath::FromWStringHack(chrome::kNotSignedInProfile));
return default_profile_dir;
}
FilePath ProfileManager::GetProfilePrefsPath(
const FilePath &profile_dir) {
FilePath default_prefs_path(profile_dir);
default_prefs_path = default_prefs_path.Append(chrome::kPreferencesFilename);
return default_prefs_path;
}
Profile* ProfileManager::GetDefaultProfile(const FilePath& user_data_dir) {
FilePath default_profile_dir(user_data_dir);
std::wstring profile = chrome::kNotSignedInProfile;
#if defined(OS_CHROMEOS)
// If the user has logged in, pick up the new profile.
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
// TODO(davemoore) Delete this once chromium os has started using
// "--login-profile" instead of "--profile".
if (logged_in_ && command_line.HasSwitch(switches::kProfile)) {
profile = command_line.GetSwitchValue(switches::kProfile);
}
if (logged_in_ && command_line.HasSwitch(switches::kLoginProfile)) {
profile = command_line.GetSwitchValue(switches::kLoginProfile);
}
#endif
default_profile_dir = default_profile_dir.Append(
FilePath::FromWStringHack(profile));
return GetProfile(default_profile_dir);
}
Profile* ProfileManager::GetProfile(const FilePath& profile_dir) {
// If the profile is already loaded (e.g., chrome.exe launched twice), just
// return it.
Profile* profile = GetProfileByPath(profile_dir);
if (NULL != profile)
return profile;
if (!ProfileManager::IsProfile(profile_dir)) {
// If the profile directory doesn't exist, create it.
profile = ProfileManager::CreateProfile(profile_dir);
if (!profile)
return NULL;
bool result = AddProfile(profile);
DCHECK(result);
} else {
// The profile already exists on disk, just load it.
profile = AddProfileByPath(profile_dir);
if (!profile)
return NULL;
}
DCHECK(profile);
return profile;
}
Profile* ProfileManager::AddProfileByPath(const FilePath& path) {
Profile* profile = GetProfileByPath(path);
if (profile)
return profile;
profile = Profile::CreateProfile(path);
if (AddProfile(profile)) {
return profile;
} else {
return NULL;
}
}
bool ProfileManager::AddProfile(Profile* profile) {
DCHECK(profile);
// Make sure that we're not loading a profile with the same ID as a profile
// that's already loaded.
if (GetProfileByPath(profile->GetPath())) {
NOTREACHED() << "Attempted to add profile with the same path (" <<
profile->GetPath().value() <<
") as an already-loaded profile.";
return false;
}
profiles_.insert(profiles_.end(), profile);
profile->InitExtensions();
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (!command_line.HasSwitch(switches::kDisableWebResources))
profile->InitWebResources();
return true;
}
Profile* ProfileManager::GetProfileByPath(const FilePath& path) const {
for (const_iterator i(begin()); i != end(); ++i) {
if ((*i)->GetPath() == path)
return *i;
}
return NULL;
}
void ProfileManager::OnSuspend() {
DCHECK(CalledOnValidThread());
for (const_iterator i(begin()); i != end(); ++i) {
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableFunction(&ProfileManager::SuspendProfile, *i));
}
}
void ProfileManager::OnResume() {
DCHECK(CalledOnValidThread());
for (const_iterator i(begin()); i != end(); ++i) {
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableFunction(&ProfileManager::ResumeProfile, *i));
}
}
void ProfileManager::Observe(
NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
#if defined(OS_CHROMEOS)
if (type == NotificationType::LOGIN_USER_CHANGED) {
logged_in_ = true;
}
#endif
}
void ProfileManager::SuspendProfile(Profile* profile) {
DCHECK(profile);
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
for (URLRequestJobTracker::JobIterator i = g_url_request_job_tracker.begin();
i != g_url_request_job_tracker.end(); ++i)
(*i)->Kill();
profile->GetRequestContext()->GetURLRequestContext()->
http_transaction_factory()->Suspend(true);
}
void ProfileManager::ResumeProfile(Profile* profile) {
DCHECK(profile);
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
profile->GetRequestContext()->GetURLRequestContext()->
http_transaction_factory()->Suspend(false);
}
// static
bool ProfileManager::IsProfile(const FilePath& path) {
FilePath prefs_path = GetProfilePrefsPath(path);
FilePath history_path = path;
history_path = history_path.Append(chrome::kHistoryFilename);
return file_util::PathExists(prefs_path) &&
file_util::PathExists(history_path);
}
// static
Profile* ProfileManager::CreateProfile(const FilePath& path) {
if (IsProfile(path)) {
DCHECK(false) << "Attempted to create a profile with the path:\n"
<< path.value() << "\n but that path already contains a profile";
}
if (!file_util::PathExists(path)) {
// TODO(tc): http://b/1094718 Bad things happen if we can't write to the
// profile directory. We should eventually be able to run in this
// situation.
if (!file_util::CreateDirectory(path))
return NULL;
}
return Profile::CreateProfile(path);
}