summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authoraltimofeev@chromium.org <altimofeev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-13 11:27:06 +0000
committeraltimofeev@chromium.org <altimofeev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-13 11:27:06 +0000
commit334c59d927639aaae464f76b082a893b9fdf6987 (patch)
treef3e0a7ef15974751cbbbb32e2d075dc27088179f /chrome/browser
parentc813df0195b2c96d2265ad767d4848dd13818211 (diff)
downloadchromium_src-334c59d927639aaae464f76b082a893b9fdf6987.zip
chromium_src-334c59d927639aaae464f76b082a893b9fdf6987.tar.gz
chromium_src-334c59d927639aaae464f76b082a893b9fdf6987.tar.bz2
This CL implements alternative asynchronous methods for profile and preferences loading.
BUG=chromium-os:11104 TEST=UserProfileGotten (see "/tmp/login-times-sent") time doesn't increase, while UI jankness decreases. Review URL: http://codereview.chromium.org/6716025 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81394 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/app_controller_mac.mm14
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc6
-rw-r--r--chrome/browser/browser_main.cc18
-rw-r--r--chrome/browser/browser_process_impl.cc5
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller.cc41
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller.h11
-rw-r--r--chrome/browser/chromeos/login/login_performer.cc48
-rw-r--r--chrome/browser/chromeos/login/login_performer.h9
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc107
-rw-r--r--chrome/browser/chromeos/login/login_utils.h23
-rw-r--r--chrome/browser/chromeos/login/mock_authenticator.h20
-rw-r--r--chrome/browser/chromeos/login/screen_locker.cc1
-rw-r--r--chrome/browser/chromeos/login/wizard_controller.cc1
-rw-r--r--chrome/browser/content_settings/content_settings_pref_provider_unittest.cc2
-rw-r--r--chrome/browser/debugger/extension_ports_remote_service.cc13
-rw-r--r--chrome/browser/extensions/extension_event_router_forwarder.cc9
-rw-r--r--chrome/browser/extensions/extension_event_router_forwarder_unittest.cc4
-rw-r--r--chrome/browser/memory_purger.cc13
-rw-r--r--chrome/browser/prefs/pref_service.cc74
-rw-r--r--chrome/browser/prefs/pref_service.h26
-rw-r--r--chrome/browser/prefs/pref_service_mock_builder.cc3
-rw-r--r--chrome/browser/profiles/profile.h10
-rw-r--r--chrome/browser/profiles/profile_impl.cc134
-rw-r--r--chrome/browser/profiles/profile_impl.h15
-rw-r--r--chrome/browser/profiles/profile_manager.cc209
-rw-r--r--chrome/browser/profiles/profile_manager.h98
-rw-r--r--chrome/browser/profiles/profile_manager_unittest.cc140
-rw-r--r--chrome/browser/task_manager/task_manager.cc11
-rw-r--r--chrome/browser/task_manager/task_manager_resource_providers.cc16
29 files changed, 691 insertions, 390 deletions
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 6934219..3be6c92 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -599,18 +599,17 @@ void RecordLastRunAppBundlePath() {
if (!profile_manager)
return YES;
- ProfileManager::const_iterator it = profile_manager->begin();
- for (; it != profile_manager->end(); ++it) {
- Profile* profile = *it;
- DownloadManager* download_manager = profile->GetDownloadManager();
+ std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i) {
+ DownloadManager* download_manager = profiles[i]->GetDownloadManager();
if (download_manager && download_manager->in_progress_count() > 0) {
int downloadCount = download_manager->in_progress_count();
if ([self userWillWaitForInProgressDownloads:downloadCount]) {
// Create a new browser window (if necessary) and navigate to the
// downloads page if the user chooses to wait.
- Browser* browser = BrowserList::FindBrowserWithProfile(profile);
+ Browser* browser = BrowserList::FindBrowserWithProfile(profiles[i]);
if (!browser) {
- browser = Browser::Create(profile);
+ browser = Browser::Create(profiles[i]);
browser->window()->Show();
}
DCHECK(browser);
@@ -984,9 +983,8 @@ void RecordLastRunAppBundlePath() {
}
- (Profile*)defaultProfile {
- // TODO(jrg): Find a better way to get the "default" profile.
if (g_browser_process->profile_manager())
- return *g_browser_process->profile_manager()->begin();
+ return g_browser_process->profile_manager()->GetDefaultProfile();
return NULL;
}
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index a2d9055..2a344d7 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -2563,10 +2563,10 @@ void TestingAutomationProvider::GetBrowserInfo(
// item per extension process.
ListValue* extension_processes = new ListValue;
ProfileManager* profile_manager = g_browser_process->profile_manager();
- for (ProfileManager::const_iterator it = profile_manager->begin();
- it != profile_manager->end(); ++it) {
+ std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i) {
ExtensionProcessManager* process_manager =
- (*it)->GetExtensionProcessManager();
+ profiles[i]->GetExtensionProcessManager();
if (!process_manager)
continue;
ExtensionProcessManager::const_iterator jt;
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index 746ae30..6c5a59b 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -955,7 +955,8 @@ void InitializeToolkit(const MainFunctionParams& parameters) {
// Class is used to login using passed username and password.
// The instance will be deleted upon success or failure.
-class StubLogin : public chromeos::LoginStatusConsumer {
+class StubLogin : public chromeos::LoginStatusConsumer,
+ public chromeos::LoginUtils::Delegate {
public:
explicit StubLogin(std::string username, std::string password) {
authenticator_ = chromeos::LoginUtils::Get()->CreateAuthenticator(this);
@@ -976,10 +977,17 @@ class StubLogin : public chromeos::LoginStatusConsumer {
const std::string& password,
const GaiaAuthConsumer::ClientLoginResult& credentials,
bool pending_requests) {
- chromeos::LoginUtils::Get()->CompleteLogin(username,
- password,
- credentials,
- pending_requests);
+ // Will call OnProfilePrepared in the end.
+ chromeos::LoginUtils::Get()->PrepareProfile(username,
+ password,
+ credentials,
+ pending_requests,
+ this);
+ }
+
+ // LoginUtils::Delegate implementation:
+ virtual void OnProfilePrepared(Profile* profile) {
+ chromeos::LoginUtils::DoBrowserLaunch(profile);
delete this;
}
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index c521e11..b14403e 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -324,8 +324,9 @@ void BrowserProcessImpl::EndSession() {
// Mark all the profiles as clean.
ProfileManager* pm = profile_manager();
- for (ProfileManager::const_iterator i = pm->begin(); i != pm->end(); ++i)
- (*i)->MarkAsCleanShutdown();
+ std::vector<Profile*> profiles(pm->GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i)
+ profiles[i]->MarkAsCleanShutdown();
// Tell the metrics service it was cleanly shutdown.
MetricsService* metrics = g_browser_process->metrics_service();
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index dcba46b..d080e73 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -16,7 +16,6 @@
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/login_display_host.h"
-#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/views_login_display.h"
#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
@@ -321,6 +320,14 @@ void ExistingUserController::OnLoginSuccess(
const std::string& password,
const GaiaAuthConsumer::ClientLoginResult& credentials,
bool pending_requests) {
+ bool known_user = UserManager::Get()->IsKnownUser(username);
+ bool login_only =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kLoginScreen) == WizardController::kLoginScreenName;
+ ready_for_browser_launch_ = known_user || login_only;
+
+ two_factor_credentials_ = credentials.two_factor;
+
// LoginPerformer instance will delete itself once online auth result is OK.
// In case of failure it'll bring up ScreenLock and ask for
// correct password/display error message.
@@ -329,12 +336,19 @@ void ExistingUserController::OnLoginSuccess(
login_performer_->set_delegate(NULL);
LoginPerformer* performer = login_performer_.release();
performer = NULL;
- bool known_user = UserManager::Get()->IsKnownUser(username);
- bool login_only =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kLoginScreen) == WizardController::kLoginScreenName;
+
+ // Will call OnProfilePrepared() in the end.
+ LoginUtils::Get()->PrepareProfile(username,
+ password,
+ credentials,
+ pending_requests,
+ this);
+
+}
+
+void ExistingUserController::OnProfilePrepared(Profile* profile) {
// TODO(nkostylev): May add login UI implementation callback call.
- if (!known_user && !login_only) {
+ if (!ready_for_browser_launch_) {
#if defined(OFFICIAL_BUILD)
CommandLine::ForCurrentProcess()->AppendArg(kGetStartedURL);
#endif // OFFICIAL_BUILD
@@ -345,29 +359,18 @@ void ExistingUserController::OnLoginSuccess(
CommandLine::ForCurrentProcess()->AppendArg(initial_start_page_);
}
- if (credentials.two_factor) {
+ if (two_factor_credentials_) {
// If we have a two factor error and and this is a new user,
// load the personal settings page.
// TODO(stevenjb): direct the user to a lightweight sync login page.
CommandLine::ForCurrentProcess()->AppendArg(kSettingsSyncLoginURL);
}
- // For new user login don't launch browser until we pass image screen.
- LoginUtils::Get()->EnableBrowserLaunch(false);
- LoginUtils::Get()->CompleteLogin(username,
- password,
- credentials,
- pending_requests);
-
ActivateWizard(WizardController::IsDeviceRegistered() ?
WizardController::kUserImageScreenName :
WizardController::kRegistrationScreenName);
} else {
- LoginUtils::Get()->CompleteLogin(username,
- password,
- credentials,
- pending_requests);
-
+ LoginUtils::DoBrowserLaunch(profile);
// Delay deletion as we're on the stack.
host_->OnSessionStart();
}
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index d7a02d6..aff1bfc 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -16,6 +16,7 @@
#include "chrome/browser/chromeos/login/captcha_view.h"
#include "chrome/browser/chromeos/login/login_display.h"
#include "chrome/browser/chromeos/login/login_performer.h"
+#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/ownership_status_checker.h"
#include "chrome/browser/chromeos/login/password_changed_view.h"
#include "chrome/browser/chromeos/login/user_manager.h"
@@ -41,6 +42,7 @@ class UserCrosSettingsProvider;
class ExistingUserController : public LoginDisplay::Delegate,
public NotificationObserver,
public LoginPerformer::Delegate,
+ public LoginUtils::Delegate,
public CaptchaView::Delegate,
public PasswordChangedView::Delegate {
public:
@@ -91,6 +93,9 @@ class ExistingUserController : public LoginDisplay::Delegate,
const GaiaAuthConsumer::ClientLoginResult& credentials);
virtual void WhiteListCheckFailed(const std::string& email);
+ // LoginUtils::Delegate implementation:
+ virtual void OnProfilePrepared(Profile* profile);
+
// CaptchaView::Delegate:
virtual void OnCaptchaEntered(const std::string& captcha);
@@ -159,6 +164,12 @@ class ExistingUserController : public LoginDisplay::Delegate,
// Factory of callbacks.
ScopedRunnableMethodFactory<ExistingUserController> method_factory_;
+ // Whether everything is ready to launch the browser.
+ bool ready_for_browser_launch_;
+
+ // Whether two factor credentials were used.
+ bool two_factor_credentials_;
+
// Used to verify ownership before starting enterprise enrollment.
scoped_ptr<OwnershipStatusChecker> ownership_checker_;
diff --git a/chrome/browser/chromeos/login/login_performer.cc b/chrome/browser/chromeos/login/login_performer.cc
index 4aad0fa..8d333e6 100644
--- a/chrome/browser/chromeos/login/login_performer.cc
+++ b/chrome/browser/chromeos/login/login_performer.cc
@@ -135,31 +135,39 @@ void LoginPerformer::OnLoginSuccess(
pending_requests);
return;
} else {
+ // Online login has succeeded.
DCHECK(!pending_requests)
<< "Pending request w/o delegate_ should not happen!";
- // Online login has succeeded.
- Profile* profile =
- g_browser_process->profile_manager()->GetDefaultProfile();
- LoginUtils::Get()->FetchCookies(profile, credentials);
- LoginUtils::Get()->FetchTokens(profile, credentials);
-
- // Don't unlock screen if it was locked while we're waiting
- // for initial online auth.
- if (ScreenLocker::default_screen_locker() &&
- !initial_online_auth_pending_) {
- DVLOG(1) << "Online login OK - unlocking screen.";
- RequestScreenUnlock();
- // Do not delete itself just yet, wait for unlock.
- // See ResolveScreenUnlocked().
- return;
- }
- initial_online_auth_pending_ = false;
- // There's nothing else that's holding LP from deleting itself -
- // no ScreenLock, no pending requests.
- MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+ // It is not guaranted, that profile creation has been finished yet. So use
+ // async version here.
+ credentials_ = credentials;
+ ProfileManager::CreateDefaultProfileAsync(this);
}
}
+void LoginPerformer::OnProfileCreated(Profile* profile) {
+ CHECK(profile);
+
+ LoginUtils::Get()->FetchCookies(profile, credentials_);
+ LoginUtils::Get()->FetchTokens(profile, credentials_);
+ credentials_ = GaiaAuthConsumer::ClientLoginResult();
+
+ // Don't unlock screen if it was locked while we're waiting
+ // for initial online auth.
+ if (ScreenLocker::default_screen_locker() &&
+ !initial_online_auth_pending_) {
+ DVLOG(1) << "Online login OK - unlocking screen.";
+ RequestScreenUnlock();
+ // Do not delete itself just yet, wait for unlock.
+ // See ResolveScreenUnlocked().
+ return;
+ }
+ initial_online_auth_pending_ = false;
+ // There's nothing else that's holding LP from deleting itself -
+ // no ScreenLock, no pending requests.
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
void LoginPerformer::OnOffTheRecordLoginSuccess() {
UserMetrics::RecordAction(
UserMetricsAction("Login_GuestLoginSuccess"));
diff --git a/chrome/browser/chromeos/login/login_performer.h b/chrome/browser/chromeos/login/login_performer.h
index ff3c829..fb847c7 100644
--- a/chrome/browser/chromeos/login/login_performer.h
+++ b/chrome/browser/chromeos/login/login_performer.h
@@ -14,6 +14,7 @@
#include "chrome/browser/chromeos/login/authenticator.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/signed_settings_helper.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h"
@@ -52,7 +53,8 @@ namespace chromeos {
// 2. Pending online auth request.
class LoginPerformer : public LoginStatusConsumer,
public SignedSettingsHelper::Callback,
- public NotificationObserver {
+ public NotificationObserver,
+ public ProfileManager::Observer {
public:
// Delegate class to get notifications from the LoginPerformer.
class Delegate : public LoginStatusConsumer {
@@ -117,6 +119,9 @@ class LoginPerformer : public LoginStatusConsumer,
void set_delegate(Delegate* delegate) { delegate_ = delegate; }
private:
+ // ProfeleManager::Observer implementation:
+ void OnProfileCreated(Profile* profile);
+
// Requests screen lock and subscribes to screen lock notifications.
void RequestScreenLock();
@@ -183,6 +188,8 @@ class LoginPerformer : public LoginStatusConsumer,
// is locked during that stage. No need to resolve screen lock action then.
bool initial_online_auth_pending_;
+ GaiaAuthConsumer::ClientLoginResult credentials_;
+
ScopedRunnableMethodFactory<LoginPerformer> method_factory_;
DISALLOW_COPY_AND_ASSIGN(LoginPerformer);
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index f71a5a5..5045ba9 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -103,20 +103,19 @@ class ResetDefaultProxyConfigServiceTask : public Task {
} // namespace
-class LoginUtilsImpl : public LoginUtils {
+class LoginUtilsImpl : public LoginUtils,
+ public ProfileManager::Observer {
public:
LoginUtilsImpl()
- : browser_launch_enabled_(true),
- background_view_(NULL) {
+ : background_view_(NULL) {
}
- // Invoked after the user has successfully logged in. This launches a browser
- // and does other bookkeeping after logging in.
- virtual void CompleteLogin(
+ virtual void PrepareProfile(
const std::string& username,
const std::string& password,
const GaiaAuthConsumer::ClientLoginResult& credentials,
- bool pending_requests);
+ bool pending_requests,
+ LoginUtils::Delegate* delegate);
// Invoked after the tmpfs is successfully mounted.
// Launches a browser in the incognito mode.
@@ -130,13 +129,6 @@ class LoginUtilsImpl : public LoginUtils {
// Authenticator and must delete it when done.
virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer);
- // Used to postpone browser launch via DoBrowserLaunch() if some post
- // login screen is to be shown.
- virtual void EnableBrowserLaunch(bool enable);
-
- // Returns if browser launch enabled now or not.
- virtual bool IsBrowserLaunchEnabled() const;
-
// Warms the url used by authentication.
virtual void PrewarmAuthentication();
@@ -157,6 +149,9 @@ class LoginUtilsImpl : public LoginUtils {
// Gets the current background view.
virtual chromeos::BackgroundView* GetBackgroundView();
+ // ProfileManager::Observer implementation:
+ virtual void OnProfileCreated(Profile* profile);
+
protected:
virtual std::string GetOffTheRecordCommandLine(
const GURL& start_url,
@@ -167,12 +162,17 @@ class LoginUtilsImpl : public LoginUtils {
// Check user's profile for kApplicationLocale setting.
void RespectLocalePreference(Profile* pref);
- // Indicates if DoBrowserLaunch will actually launch the browser or not.
- bool browser_launch_enabled_;
-
// The current background view.
chromeos::BackgroundView* background_view_;
+ std::string username_;
+ std::string password_;
+ GaiaAuthConsumer::ClientLoginResult credentials_;
+ bool pending_requests_;
+
+ // Delegate to be fired when the profile will be prepared.
+ LoginUtils::Delegate* delegate_;
+
DISALLOW_COPY_AND_ASSIGN(LoginUtilsImpl);
};
@@ -204,11 +204,12 @@ class LoginUtilsWrapper {
DISALLOW_COPY_AND_ASSIGN(LoginUtilsWrapper);
};
-void LoginUtilsImpl::CompleteLogin(
+void LoginUtilsImpl::PrepareProfile(
const std::string& username,
const std::string& password,
const GaiaAuthConsumer::ClientLoginResult& credentials,
- bool pending_requests) {
+ bool pending_requests,
+ LoginUtils::Delegate* delegate) {
BootTimesLoader* btl = BootTimesLoader::Get();
VLOG(1) << "Completing login for " << username;
@@ -219,30 +220,31 @@ void LoginUtilsImpl::CompleteLogin(
btl->AddLoginTimeMarker("StartedSession", false);
}
- bool first_login = !UserManager::Get()->IsKnownUser(username);
UserManager::Get()->UserLoggedIn(username);
btl->AddLoginTimeMarker("UserLoggedIn", false);
- // Now get the new profile.
- FilePath user_data_dir;
- PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
- ProfileManager* profile_manager = g_browser_process->profile_manager();
-
// Switch log file as soon as possible.
logging::RedirectChromeLogging(*(CommandLine::ForCurrentProcess()));
btl->AddLoginTimeMarker("LoggingRedirected", false);
- Profile* profile = NULL;
- {
- // Loading user profile causes us to do blocking IO on UI thread.
- // Temporarily allow it until we fix http://crosbug.com/11104
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- // The default profile will have been changed because the ProfileManager
- // will process the notification that the UserManager sends out.
- profile = profile_manager->GetDefaultProfile(user_data_dir);
- }
+ username_ = username;
+ password_ = password;
+ credentials_ = credentials;
+ pending_requests_ = pending_requests;
+ delegate_ = delegate;
+
+ // The default profile will have been changed because the ProfileManager
+ // will process the notification that the UserManager sends out.
+ ProfileManager::CreateDefaultProfileAsync(this);
+}
+
+void LoginUtilsImpl::OnProfileCreated(Profile* profile) {
+ CHECK(profile);
+
+ BootTimesLoader* btl = BootTimesLoader::Get();
btl->AddLoginTimeMarker("UserProfileGotten", false);
+ bool first_login = !UserManager::Get()->IsKnownUser(username_);
// Change the proxy configuration service of the default request context to
// use the preference configuration from the logged-in profile. This ensures
// that requests done through the default context use the proxy configuration
@@ -266,11 +268,11 @@ void LoginUtilsImpl::CompleteLogin(
proxy_config_service));
// Since we're doing parallel authentication, only new user sign in
- // would perform online auth before calling CompleteLogin.
+ // would perform online auth before calling PrepareProfile.
// For existing users there's usually a pending online auth request.
// Cookies will be fetched after it's is succeeded.
- if (!pending_requests) {
- FetchCookies(profile, credentials);
+ if (!pending_requests_) {
+ FetchCookies(profile, credentials_);
}
// Init extension event routers; this normally happens in browser_main
@@ -290,16 +292,16 @@ void LoginUtilsImpl::CompleteLogin(
// For existing users there's usually a pending online auth request.
// Tokens will be fetched after it's is succeeded.
- if (!pending_requests) {
- FetchTokens(profile, credentials);
+ if (!pending_requests_) {
+ FetchTokens(profile, credentials_);
}
btl->AddLoginTimeMarker("TokensGotten", false);
// Set the CrOS user by getting this constructor run with the
// user's email on first retrieval.
- profile->GetProfileSyncService(username)->SetPassphrase(password,
- false,
- true);
+ profile->GetProfileSyncService(username_)->SetPassphrase(password_,
+ false,
+ true);
btl->AddLoginTimeMarker("SyncStarted", false);
// Own TPM device if, for any reason, it has not been done in EULA
@@ -330,13 +332,19 @@ void LoginUtilsImpl::CompleteLogin(
// done yet to pull down policies from the domain admin. We'll take this
// out when we get that done properly.
// TODO(xiyuan): Remove this once enterprise feature is ready.
- if (EndsWith(username, "@google.com", true)) {
+ if (EndsWith(username_, "@google.com", true)) {
PrefService* pref_service = profile->GetPrefs();
pref_service->SetBoolean(prefs::kEnableScreenLock, true);
}
profile->OnLogin();
- DoBrowserLaunch(profile);
+
+ delegate_->OnProfilePrepared(profile);
+
+ // TODO(altimofeev): Need to sanitize memory used to store password.
+ password_ = "";
+ username_ = "";
+ credentials_ = GaiaAuthConsumer::ClientLoginResult();
}
void LoginUtilsImpl::FetchCookies(
@@ -515,14 +523,6 @@ Authenticator* LoginUtilsImpl::CreateAuthenticator(
return new GoogleAuthenticator(consumer);
}
-void LoginUtilsImpl::EnableBrowserLaunch(bool enable) {
- browser_launch_enabled_ = enable;
-}
-
-bool LoginUtilsImpl::IsBrowserLaunchEnabled() const {
- return browser_launch_enabled_;
-}
-
// We use a special class for this so that it can be safely leaked if we
// never connect. At shutdown the order is not well defined, and it's possible
// for the infrastructure needed to unregister might be unstable and crash.
@@ -580,9 +580,6 @@ void LoginUtils::Set(LoginUtils* mock) {
void LoginUtils::DoBrowserLaunch(Profile* profile) {
BootTimesLoader::Get()->AddLoginTimeMarker("BrowserLaunched", false);
- // Browser launch was disabled due to some post login screen.
- if (!LoginUtils::Get()->IsBrowserLaunchEnabled())
- return;
// Update command line in case loose values were added.
CommandLine::ForCurrentProcess()->InitFromArgv(
diff --git a/chrome/browser/chromeos/login/login_utils.h b/chrome/browser/chromeos/login/login_utils.h
index 05a1a6c..d0eaeb7 100644
--- a/chrome/browser/chromeos/login/login_utils.h
+++ b/chrome/browser/chromeos/login/login_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -27,6 +27,12 @@ class LoginStatusConsumer;
class LoginUtils {
public:
+ class Delegate {
+ public:
+ // Called after profile is loaded and prepared for the session.
+ virtual void OnProfilePrepared(Profile* profile) = 0;
+ };
+
// Get LoginUtils singleton object. If it was not set before, new default
// instance will be created.
static LoginUtils* Get();
@@ -40,14 +46,14 @@ class LoginUtils {
virtual ~LoginUtils() {}
- // Invoked after the user has successfully logged in. This launches a browser
- // and does other bookkeeping after logging in.
+ // Loads and prepares profile for the session. Fires |delegate| in the end.
// If |pending_requests| is true, there's a pending online auth request.
- virtual void CompleteLogin(
+ virtual void PrepareProfile(
const std::string& username,
const std::string& password,
const GaiaAuthConsumer::ClientLoginResult& credentials,
- bool pending_requests) = 0;
+ bool pending_requests,
+ Delegate* delegate) = 0;
// Invoked after the tmpfs is successfully mounted.
// Asks session manager to restart Chrome in Browse Without Sign In mode.
@@ -62,13 +68,6 @@ class LoginUtils {
// Authenticator and must delete it when done.
virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer) = 0;
- // Used to postpone browser launch via DoBrowserLaunch() if some post
- // login screen is to be shown.
- virtual void EnableBrowserLaunch(bool enable) = 0;
-
- // Returns if browser launch enabled now or not.
- virtual bool IsBrowserLaunchEnabled() const = 0;
-
// Prewarms the authentication network connection.
virtual void PrewarmAuthentication() = 0;
diff --git a/chrome/browser/chromeos/login/mock_authenticator.h b/chrome/browser/chromeos/login/mock_authenticator.h
index 4816442..73c5352 100644
--- a/chrome/browser/chromeos/login/mock_authenticator.h
+++ b/chrome/browser/chromeos/login/mock_authenticator.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -111,12 +111,15 @@ class MockLoginUtils : public LoginUtils {
return false;
}
- virtual void CompleteLogin(const std::string& username,
- const std::string& password,
- const GaiaAuthConsumer::ClientLoginResult& res,
- bool pending_requests) {
+ virtual void PrepareProfile(const std::string& username,
+ const std::string& password,
+ const GaiaAuthConsumer::ClientLoginResult& res,
+ bool pending_requests,
+ Delegate* delegate) {
EXPECT_EQ(expected_username_, username);
EXPECT_EQ(expected_password_, password);
+ // Profile hasn't been loaded.
+ delegate->OnProfilePrepared(NULL);
}
virtual void CompleteOffTheRecordLogin(const GURL& start_url) {
@@ -130,13 +133,6 @@ class MockLoginUtils : public LoginUtils {
consumer, expected_username_, expected_password_);
}
- virtual void EnableBrowserLaunch(bool enable) {
- }
-
- virtual bool IsBrowserLaunchEnabled() const {
- return true;
- }
-
virtual void PrewarmAuthentication() {
}
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
index 09d7675..0d74e11 100644
--- a/chrome/browser/chromeos/login/screen_locker.cc
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -36,6 +36,7 @@
#include "chrome/browser/chromeos/view_ids.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index d28a56c..02111db 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -550,7 +550,6 @@ void WizardController::OnUserImageSelected() {
// Host will mark itself (and all controllers/windows) for deletion.
host_->OnSessionStart();
// Launch browser after controller is deleted and its windows are closed.
- chromeos::LoginUtils::Get()->EnableBrowserLaunch(true);
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
index 6f9827d..105cb96 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
@@ -36,7 +36,7 @@ class ContentSettingsPrefService : public PrefService {
: PrefService(
managed_platform_prefs, managed_cloud_prefs, extension_prefs,
command_line_prefs, user_prefs, recommended_platform_prefs,
- recommended_cloud_prefs, default_store) {}
+ recommended_cloud_prefs, default_store, NULL) {}
virtual ~ContentSettingsPrefService() {}
};
}
diff --git a/chrome/browser/debugger/extension_ports_remote_service.cc b/chrome/browser/debugger/extension_ports_remote_service.cc
index b769ca0..9db706c 100644
--- a/chrome/browser/debugger/extension_ports_remote_service.cc
+++ b/chrome/browser/debugger/extension_ports_remote_service.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -121,12 +121,11 @@ ExtensionPortsRemoteService::ExtensionPortsRemoteService(
LOG(WARNING) << "No profile manager for ExtensionPortsRemoteService";
return;
}
- for (ProfileManager::ProfileVector::const_iterator it
- = profile_manager->begin();
- it != profile_manager->end();
- ++it) {
- if (!(*it)->IsOffTheRecord()) {
- service_ = (*it)->GetExtensionMessageService();
+
+ std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i) {
+ if (!profiles[i]->IsOffTheRecord()) {
+ service_ = profiles[i]->GetExtensionMessageService();
break;
}
}
diff --git a/chrome/browser/extensions/extension_event_router_forwarder.cc b/chrome/browser/extensions/extension_event_router_forwarder.cc
index 5147453..969c61d 100644
--- a/chrome/browser/extensions/extension_event_router_forwarder.cc
+++ b/chrome/browser/extensions/extension_event_router_forwarder.cc
@@ -80,11 +80,11 @@ void ExtensionEventRouterForwarder::HandleEvent(
profile, extension_id, event_name, event_args,
use_profile_to_restrict_events ? profile : NULL, event_url);
} else {
- ProfileManager::iterator i;
- for (i = profile_manager->begin(); i != profile_manager->end(); ++i) {
+ std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i) {
CallExtensionEventRouter(
- *i, extension_id, event_name, event_args,
- use_profile_to_restrict_events ? (*i) : NULL, event_url);
+ profiles[i], extension_id, event_name, event_args,
+ use_profile_to_restrict_events ? profiles[i] : NULL, event_url);
}
}
}
@@ -112,4 +112,3 @@ void ExtensionEventRouterForwarder::CallExtensionEventRouter(
event_name, event_args, restrict_to_profile, event_url);
}
}
-
diff --git a/chrome/browser/extensions/extension_event_router_forwarder_unittest.cc b/chrome/browser/extensions/extension_event_router_forwarder_unittest.cc
index ac4405e..7d82ea5 100644
--- a/chrome/browser/extensions/extension_event_router_forwarder_unittest.cc
+++ b/chrome/browser/extensions/extension_event_router_forwarder_unittest.cc
@@ -52,8 +52,8 @@ class ExtensionEventRouterForwarderTest : public TestingBrowserProcessTest {
profile1_ = new TestingProfile();
profile2_ = new TestingProfile();
- browser_process->profile_manager()->RegisterProfile(profile1_);
- browser_process->profile_manager()->RegisterProfile(profile2_);
+ browser_process->profile_manager()->RegisterProfile(profile1_, true);
+ browser_process->profile_manager()->RegisterProfile(profile2_, true);
}
TestingProfile* CreateIncognitoProfile(TestingProfile* base) {
diff --git a/chrome/browser/memory_purger.cc b/chrome/browser/memory_purger.cc
index 78d009d..80a884e 100644
--- a/chrome/browser/memory_purger.cc
+++ b/chrome/browser/memory_purger.cc
@@ -98,11 +98,10 @@ void MemoryPurger::PurgeBrowser() {
new PurgeMemoryIOHelper(g_browser_process->resource_dispatcher_host()->
safe_browsing_service()));
ProfileManager* profile_manager = g_browser_process->profile_manager();
- for (ProfileManager::iterator i(profile_manager->begin());
- i != profile_manager->end(); ++i) {
- Profile* profile = *i;
+ std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i) {
purge_memory_io_helper->AddRequestContextGetter(
- make_scoped_refptr(profile->GetRequestContext()));
+ make_scoped_refptr(profiles[i]->GetRequestContext()));
// NOTE: Some objects below may be duplicates across profiles. We could
// conceivably put all these in sets and then iterate over the sets.
@@ -111,20 +110,20 @@ void MemoryPurger::PurgeBrowser() {
// Spinning up the history service is expensive, so we avoid doing it if it
// hasn't been done already.
HistoryService* history_service =
- profile->GetHistoryServiceWithoutCreating();
+ profiles[i]->GetHistoryServiceWithoutCreating();
if (history_service)
history_service->UnloadBackend();
// Unload all web databases (freeing memory used to cache sqlite).
WebDataService* web_data_service =
- profile->GetWebDataServiceWithoutCreating();
+ profiles[i]->GetWebDataServiceWithoutCreating();
if (web_data_service)
web_data_service->UnloadDatabase();
// Ask all WebKitContexts to purge memory (freeing memory used to cache
// the LocalStorage sqlite DB). WebKitContext creation is basically free so
// we don't bother with a "...WithoutCreating()" function.
- profile->GetWebKitContext()->PurgeMemory();
+ profiles[i]->GetWebKitContext()->PurgeMemory();
}
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
diff --git a/chrome/browser/prefs/pref_service.cc b/chrome/browser/prefs/pref_service.cc
index 0a2f381..e960eb4 100644
--- a/chrome/browser/prefs/pref_service.cc
+++ b/chrome/browser/prefs/pref_service.cc
@@ -25,7 +25,6 @@
#include "chrome/browser/prefs/overlay_persistent_pref_store.h"
#include "chrome/browser/prefs/pref_notifier_impl.h"
#include "chrome/browser/prefs/pref_value_store.h"
-#include "chrome/common/json_pref_store.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_service.h"
#include "grit/chromium_strings.h"
@@ -88,6 +87,15 @@ void NotifyReadError(PrefService* pref, int message_id) {
PrefService* PrefService::CreatePrefService(const FilePath& pref_filename,
PrefStore* extension_prefs,
Profile* profile) {
+ return CreatePrefServiceAsync(pref_filename, extension_prefs, profile, NULL);
+}
+
+// static
+PrefService* PrefService::CreatePrefServiceAsync(
+ const FilePath& pref_filename,
+ PrefStore* extension_prefs,
+ Profile* profile,
+ PrefService::Delegate* delegate) {
using policy::ConfigurationPolicyPrefStore;
#if defined(OS_LINUX)
@@ -121,7 +129,7 @@ PrefService* PrefService::CreatePrefService(const FilePath& pref_filename,
return new PrefService(managed_platform, managed_cloud, extension_prefs,
command_line, user, recommended_platform,
- recommended_cloud, default_pref_store);
+ recommended_cloud, default_pref_store, delegate);
}
PrefService* PrefService::CreateIncognitoPrefService(
@@ -136,9 +144,11 @@ PrefService::PrefService(PrefStore* managed_platform_prefs,
PersistentPrefStore* user_prefs,
PrefStore* recommended_platform_prefs,
PrefStore* recommended_cloud_prefs,
- DefaultPrefStore* default_store)
+ DefaultPrefStore* default_store,
+ PrefService::Delegate* delegate)
: user_pref_store_(user_prefs),
- default_store_(default_store) {
+ default_store_(default_store),
+ delegate_(delegate) {
pref_notifier_.reset(new PrefNotifierImpl(this));
pref_value_store_.reset(
new PrefValueStore(managed_platform_prefs,
@@ -157,7 +167,8 @@ PrefService::PrefService(const PrefService& original,
PrefStore* incognito_extension_prefs)
: user_pref_store_(
new OverlayPersistentPrefStore(original.user_pref_store_.get())),
- default_store_(original.default_store_.get()){
+ default_store_(original.default_store_.get()),
+ delegate_(NULL) {
pref_notifier_.reset(new PrefNotifierImpl(this));
pref_value_store_.reset(original.pref_value_store_->CloneAndSpecialize(
NULL, // managed_platform_prefs
@@ -183,27 +194,48 @@ PrefService::~PrefService() {
default_store_ = NULL;
}
-void PrefService::InitFromStorage() {
- const PersistentPrefStore::PrefReadError error =
- user_pref_store_->ReadPrefs();
- if (error == PersistentPrefStore::PREF_READ_ERROR_NONE)
+void PrefService::OnPrefsRead(PersistentPrefStore::PrefReadError error,
+ bool no_dir) {
+ if (no_dir) {
+ // Bad news. When profile is created, the process that creates the directory
+ // is explicitly started. So if directory is missing it probably means that
+ // Chromium hasn't sufficient privileges.
+ CHECK(delegate_);
+ delegate_->OnPrefsLoaded(this, false);
return;
+ }
+
+ if (error != PersistentPrefStore::PREF_READ_ERROR_NONE) {
+ // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for
+ // an example problem that this can cause.
+ // Do some diagnosis and try to avoid losing data.
+ int message_id = 0;
+ if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE) {
+ message_id = IDS_PREFERENCES_CORRUPT_ERROR;
+ } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) {
+ message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
+ }
- // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for
- // an example problem that this can cause.
- // Do some diagnosis and try to avoid losing data.
- int message_id = 0;
- if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE) {
- message_id = IDS_PREFERENCES_CORRUPT_ERROR;
- } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) {
- message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
+ if (message_id) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(&NotifyReadError, this, message_id));
+ }
+ UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error, 20);
}
- if (message_id) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- NewRunnableFunction(&NotifyReadError, this, message_id));
+ if (delegate_)
+ delegate_->OnPrefsLoaded(this, true);
+}
+
+void PrefService::InitFromStorage() {
+ if (!delegate_) {
+ const PersistentPrefStore::PrefReadError error =
+ user_pref_store_->ReadPrefs();
+ OnPrefsRead(error, false);
+ } else {
+ // todo(altimofeev): move this method to PersistentPrefStore interface.
+ (static_cast<JsonPrefStore*>(user_pref_store_.get()))->ReadPrefs(this);
}
- UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error, 20);
}
bool PrefService::ReloadPersistentPrefs() {
diff --git a/chrome/browser/prefs/pref_service.h b/chrome/browser/prefs/pref_service.h
index 690b8c2..59e4b51 100644
--- a/chrome/browser/prefs/pref_service.h
+++ b/chrome/browser/prefs/pref_service.h
@@ -15,6 +15,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "base/values.h"
+#include "chrome/common/json_pref_store.h"
class DefaultPrefStore;
class FilePath;
@@ -32,7 +33,8 @@ class PrefMemberBase;
class ScopedUserPrefUpdateBase;
};
-class PrefService : public base::NonThreadSafe {
+class PrefService : public base::NonThreadSafe,
+ public JsonPrefStore::Delegate {
public:
// A helper class to store all the information associated with a preference.
class Preference {
@@ -111,6 +113,15 @@ class PrefService : public base::NonThreadSafe {
DISALLOW_COPY_AND_ASSIGN(Preference);
};
+ class Delegate {
+ public:
+ virtual void OnPrefsLoaded(PrefService* prefs, bool success) = 0;
+ };
+
+ // JsonPrefStore::Delegate implementaion.
+ virtual void OnPrefsRead(PersistentPrefStore::PrefReadError error,
+ bool no_dir);
+
// Factory method that creates a new instance of a PrefService with the
// applicable PrefStores. The |pref_filename| points to the user preference
// file. The |profile| is the one to which these preferences apply; it may be
@@ -122,6 +133,12 @@ class PrefService : public base::NonThreadSafe {
PrefStore* extension_pref_store,
Profile* profile);
+ // Same as above, but with async initialization.
+ static PrefService* CreatePrefServiceAsync(const FilePath& pref_filename,
+ PrefStore* extension_pref_store,
+ Profile* profile,
+ Delegate* delegate);
+
// Creates an incognito copy of the pref service that shares most pref stores
// but uses a fresh non-persistent overlay for the user pref store and an
// individual extension pref store (to cache the effective extension prefs for
@@ -238,7 +255,8 @@ class PrefService : public base::NonThreadSafe {
PersistentPrefStore* user_prefs,
PrefStore* recommended_platform_prefs,
PrefStore* recommended_cloud_prefs,
- DefaultPrefStore* default_store);
+ DefaultPrefStore* default_store,
+ Delegate* delegate);
// The PrefNotifier handles registering and notifying preference observers.
// It is created and owned by this PrefService. Subclasses may access it for
@@ -320,6 +338,10 @@ class PrefService : public base::NonThreadSafe {
// of registered preferences are.
mutable PreferenceSet prefs_;
+ // Holds delegator to be called after initialization, if async version
+ // is used.
+ Delegate* delegate_;
+
DISALLOW_COPY_AND_ASSIGN(PrefService);
};
diff --git a/chrome/browser/prefs/pref_service_mock_builder.cc b/chrome/browser/prefs/pref_service_mock_builder.cc
index 14012d1..1de0403 100644
--- a/chrome/browser/prefs/pref_service_mock_builder.cc
+++ b/chrome/browser/prefs/pref_service_mock_builder.cc
@@ -113,7 +113,8 @@ PrefService* PrefServiceMockBuilder::Create() {
user_prefs_.get(),
recommended_platform_prefs_.get(),
recommended_cloud_prefs_.get(),
- new DefaultPrefStore());
+ new DefaultPrefStore(),
+ NULL);
managed_platform_prefs_ = NULL;
managed_cloud_prefs_ = NULL;
extension_prefs_ = NULL;
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 1054aad..d63413f 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -130,6 +130,12 @@ class Profile {
IMPLICIT_ACCESS
};
+ class Delegate {
+ public:
+ // Called when creation of the profile is finished.
+ virtual void OnProfileCreated(Profile* profile, bool success) = 0;
+ };
+
// Key used to bind profile to the widget with which it is associated.
static const char* kProfileKey;
@@ -146,6 +152,10 @@ class Profile {
// Create a new profile given a path.
static Profile* CreateProfile(const FilePath& path);
+ // Same as above, but uses async initialization.
+ static Profile* CreateProfileAsync(const FilePath& path,
+ Delegate* delegate);
+
// Returns the request context for the "default" profile. This may be called
// from any thread. This CAN return NULL if a first request context has not
// yet been created. If necessary, listen on the UI thread for
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 66a28b1..844642a 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -231,7 +231,27 @@ void ProfileSizeTask::Run() {
// static
Profile* Profile::CreateProfile(const FilePath& path) {
- return new ProfileImpl(path);
+ 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 new ProfileImpl(path, NULL);
+}
+
+// static
+Profile* Profile::CreateProfileAsync(const FilePath&path,
+ Profile::Delegate* delegate) {
+ DCHECK(delegate);
+ // This is safe while all file opeartions are done on the FILE thread.
+ BrowserThread::PostTask(BrowserThread::FILE,
+ FROM_HERE,
+ NewRunnableFunction(&file_util::CreateDirectory,
+ path));
+ // Async version.
+ return new ProfileImpl(path, delegate);
}
// static
@@ -241,7 +261,8 @@ void ProfileImpl::RegisterUserPrefs(PrefService* prefs) {
DefaultApps::RegisterUserPrefs(prefs);
}
-ProfileImpl::ProfileImpl(const FilePath& path)
+ProfileImpl::ProfileImpl(const FilePath& path,
+ Profile::Delegate* delegate)
: path_(path),
visited_link_event_listener_(new VisitedLinkEventListener()),
extension_devtools_manager_(NULL),
@@ -259,13 +280,31 @@ ProfileImpl::ProfileImpl(const FilePath& path)
#if defined(OS_WIN)
checked_instant_promo_(false),
#endif
- shutdown_session_service_(false) {
+ shutdown_session_service_(false),
+ delegate_(delegate) {
DCHECK(!path.empty()) << "Using an empty path will attempt to write " <<
"profile files to the root directory!";
create_session_service_timer_.Start(
TimeDelta::FromMilliseconds(kCreateSessionServiceDelayMS), this,
&ProfileImpl::EnsureSessionServiceCreated);
+ if (delegate_) {
+ prefs_.reset(PrefService::CreatePrefServiceAsync(
+ GetPrefFilePath(),
+ new ExtensionPrefStore(GetExtensionPrefValueMap(), false),
+ GetOriginalProfile(),
+ this)); // Ask to notify us in the end.
+ } else {
+ // Load prefs synchronously.
+ prefs_.reset(PrefService::CreatePrefService(
+ GetPrefFilePath(),
+ new ExtensionPrefStore(GetExtensionPrefValueMap(), false),
+ GetOriginalProfile()));
+ OnPrefsLoaded(prefs_.get(), true);
+ }
+}
+
+void ProfileImpl::DoFinalInit() {
PrefService* prefs = GetPrefs();
pref_change_registrar_.Init(prefs);
pref_change_registrar_.Add(prefs::kSpellCheckDictionary, this);
@@ -277,7 +316,16 @@ ProfileImpl::ProfileImpl(const FilePath& path)
// the cache directory depends on the profile directory, which isn't available
// to PathService.
chrome::GetUserCacheDirectory(path_, &base_cache_path_);
- file_util::CreateDirectory(base_cache_path_);
+ if (!delegate_) {
+ file_util::CreateDirectory(base_cache_path_);
+ } else {
+ // Async profile loading is used, so call this on the FILE thread instead.
+ // It is safe since all other file operations should also be done there.
+ BrowserThread::PostTask(BrowserThread::FILE,
+ FROM_HERE,
+ NewRunnableFunction(&file_util::CreateDirectory,
+ base_cache_path_));
+ }
#if !defined(OS_CHROMEOS)
// Listen for bookmark model load, to bootstrap the sync service.
@@ -344,6 +392,10 @@ ProfileImpl::ProfileImpl(const FilePath& path)
// Initialize the ProfilePolicyConnector after |io_data_| since it requires
// the URLRequestContextGetter to be initialized.
GetPolicyConnector()->Initialize();
+
+ // Creation has been finished.
+ if (delegate_)
+ delegate_->OnProfileCreated(this, true);
}
void ProfileImpl::InitExtensions() {
@@ -742,44 +794,50 @@ net::TransportSecurityState*
return transport_security_state_.get();
}
-PrefService* ProfileImpl::GetPrefs() {
- if (!prefs_.get()) {
- prefs_.reset(PrefService::CreatePrefService(
- GetPrefFilePath(),
- new ExtensionPrefStore(GetExtensionPrefValueMap(), false),
- GetOriginalProfile()));
+void ProfileImpl::OnPrefsLoaded(PrefService* prefs, bool success) {
+ DCHECK(prefs == prefs_.get());
- // The Profile class and ProfileManager class may read some prefs so
- // register known prefs as soon as possible.
- Profile::RegisterUserPrefs(prefs_.get());
- browser::RegisterUserPrefs(prefs_.get());
- // TODO(mirandac): remove migration code after 6 months (crbug.com/69995).
- if (g_browser_process->local_state()) {
- browser::MigrateBrowserPrefs(prefs_.get(),
- g_browser_process->local_state());
- }
+ if (!success) {
+ DCHECK(delegate_);
+ delegate_->OnProfileCreated(this, false);
+ return;
+ }
- // The last session exited cleanly if there is no pref for
- // kSessionExitedCleanly or the value for kSessionExitedCleanly is true.
- last_session_exited_cleanly_ =
- prefs_->GetBoolean(prefs::kSessionExitedCleanly);
- // Mark the session as open.
- prefs_->SetBoolean(prefs::kSessionExitedCleanly, false);
- // Make sure we save to disk that the session has opened.
- prefs_->ScheduleSavePersistentPrefs();
-
- // Ensure that preferences set by extensions are restored in the profile
- // as early as possible. The constructor takes care of that.
- extension_prefs_.reset(new ExtensionPrefs(
- prefs_.get(),
- GetPath().AppendASCII(ExtensionService::kInstallDirectoryName),
- GetExtensionPrefValueMap()));
-
- DCHECK(!net_pref_observer_.get());
- net_pref_observer_.reset(
- new NetPrefObserver(prefs_.get(), GetPrerenderManager()));
+ // The Profile class and ProfileManager class may read some prefs so
+ // register known prefs as soon as possible.
+ Profile::RegisterUserPrefs(prefs_.get());
+ browser::RegisterUserPrefs(prefs_.get());
+ // TODO(mirandac): remove migration code after 6 months (crbug.com/69995).
+ if (g_browser_process->local_state()) {
+ browser::MigrateBrowserPrefs(prefs_.get(),
+ g_browser_process->local_state());
}
+ // The last session exited cleanly if there is no pref for
+ // kSessionExitedCleanly or the value for kSessionExitedCleanly is true.
+ last_session_exited_cleanly_ =
+ prefs_->GetBoolean(prefs::kSessionExitedCleanly);
+ // Mark the session as open.
+ prefs_->SetBoolean(prefs::kSessionExitedCleanly, false);
+ // Make sure we save to disk that the session has opened.
+ prefs_->ScheduleSavePersistentPrefs();
+
+ // Ensure that preferences set by extensions are restored in the profile
+ // as early as possible. The constructor takes care of that.
+ extension_prefs_.reset(new ExtensionPrefs(
+ prefs_.get(),
+ GetPath().AppendASCII(ExtensionService::kInstallDirectoryName),
+ GetExtensionPrefValueMap()));
+
+ DCHECK(!net_pref_observer_.get());
+ net_pref_observer_.reset(
+ new NetPrefObserver(prefs_.get(), GetPrerenderManager()));
+
+ DoFinalInit();
+}
+
+PrefService* ProfileImpl::GetPrefs() {
+ DCHECK(prefs_.get()); // Should explicitly be initialized.
return prefs_.get();
}
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 7e7095f..617e3bb 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -37,7 +37,8 @@ class NetPrefObserver;
// The default profile implementation.
class ProfileImpl : public Profile,
public SpellCheckHostObserver,
- public NotificationObserver {
+ public NotificationObserver,
+ public PrefService::Delegate {
public:
virtual ~ProfileImpl();
@@ -156,7 +157,15 @@ class ProfileImpl : public Profile,
private:
friend class Profile;
- explicit ProfileImpl(const FilePath& path);
+ ProfileImpl(const FilePath& path,
+ Profile::Delegate* delegate);
+
+ // Does final initialization. Should be called after prefs were loaded.
+ void DoFinalInit();
+
+ // PrefService::Delegate implementation. Does final prefs initialization and
+ // calls Init().
+ void OnPrefsLoaded(PrefService* prefs, bool success);
void CreateWebDataService();
FilePath GetPrefFilePath();
@@ -309,6 +318,8 @@ class ProfileImpl : public Profile,
scoped_ptr<ChromeURLDataManager> chrome_url_data_manager_;
+ Profile::Delegate* delegate_;
+
DISALLOW_COPY_AND_ASSIGN(ProfileImpl);
};
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index b893b25..0f0576a 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -68,8 +68,9 @@ void ProfileManager::ShutdownSessionServices() {
ProfileManager* pm = g_browser_process->profile_manager();
if (!pm) // Is NULL when running unit tests.
return;
- for (ProfileManager::const_iterator i = pm->begin(); i != pm->end(); ++i)
- (*i)->ShutdownSessionService();
+ std::vector<Profile*> profiles(pm->GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i)
+ profiles[i]->ShutdownSessionService();
}
// static
@@ -94,11 +95,6 @@ ProfileManager::~ProfileManager() {
ui::SystemMonitor* system_monitor = ui::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();
}
FilePath ProfileManager::GetDefaultProfileDir(
@@ -155,10 +151,10 @@ Profile* ProfileManager::GetDefaultProfile(const FilePath& user_data_dir) {
if (!command_line.HasSwitch(switches::kTestType) ||
command_line.HasSwitch(switches::kLoginProfile)) {
// Don't init extensions for this profile
- profile = GetProfile(default_profile_dir, false);
+ profile = GetProfile(default_profile_dir);
profile = profile->GetOffTheRecordProfile();
} else {
- profile = GetProfile(default_profile_dir, true);
+ profile = GetProfile(default_profile_dir);
}
return profile;
}
@@ -166,63 +162,102 @@ Profile* ProfileManager::GetDefaultProfile(const FilePath& user_data_dir) {
return GetProfile(default_profile_dir);
}
-Profile* ProfileManager::GetProfile(const FilePath& profile_dir) {
- return GetProfile(profile_dir, true);
-}
-
Profile* ProfileManager::GetProfileWithId(ProfileId profile_id) {
DCHECK_NE(Profile::kInvalidProfileId, profile_id);
- for (iterator i = begin(); i != end(); ++i) {
- if ((*i)->GetRuntimeId() == profile_id)
- return *i;
- if ((*i)->HasOffTheRecordProfile() &&
- (*i)->GetOffTheRecordProfile()->GetRuntimeId() == profile_id) {
- return (*i)->GetOffTheRecordProfile();
+ for (ProfilesInfoMap::iterator iter = profiles_info_.begin();
+ iter != profiles_info_.end(); ++iter) {
+ if (iter->second->created) {
+ Profile* candidate = iter->second->profile.get();
+ if (candidate->GetRuntimeId() == profile_id)
+ return candidate;
+ if (candidate->HasOffTheRecordProfile()) {
+ candidate = candidate->GetOffTheRecordProfile();
+ if (candidate->GetRuntimeId() == profile_id)
+ return candidate;
+ }
}
}
return NULL;
}
bool ProfileManager::IsValidProfile(Profile* profile) {
- for (iterator i = begin(); i != end(); ++i) {
- if (*i == profile)
- return true;
- if ((*i)->HasOffTheRecordProfile() &&
- (*i)->GetOffTheRecordProfile() == profile) {
- return true;
+ for (ProfilesInfoMap::iterator iter = profiles_info_.begin();
+ iter != profiles_info_.end(); ++iter) {
+ if (iter->second->created) {
+ Profile* candidate = iter->second->profile.get();
+ if (candidate == profile ||
+ (candidate->HasOffTheRecordProfile() &&
+ candidate->GetOffTheRecordProfile() == profile)) {
+ return true;
+ }
}
}
return false;
}
-Profile* ProfileManager::GetProfile(
- const FilePath& profile_dir, bool init_extensions) {
+std::vector<Profile*> ProfileManager::GetLoadedProfiles() const {
+ std::vector<Profile*> profiles;
+ for (ProfilesInfoMap::const_iterator iter = profiles_info_.begin();
+ iter != profiles_info_.end(); ++iter) {
+ if (iter->second->created)
+ profiles.push_back(iter->second->profile.get());
+ }
+ return profiles;
+}
+
+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);
- } else {
- // The profile already exists on disk, just load it.
- profile = Profile::CreateProfile(profile_dir);
- }
+ profile = Profile::CreateProfile(profile_dir);
DCHECK(profile);
if (profile) {
- bool result = AddProfile(profile, init_extensions);
+ bool result = AddProfile(profile);
DCHECK(result);
}
return profile;
}
-void ProfileManager::RegisterProfile(Profile* profile) {
- profiles_.insert(profiles_.end(), profile);
+void ProfileManager::CreateProfileAsync(const FilePath& user_data_dir,
+ Observer* observer) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ProfilesInfoMap::iterator iter = profiles_info_.find(user_data_dir);
+ if (iter != profiles_info_.end()) {
+ ProfileInfo* info = iter->second.get();
+ if (info->created) {
+ // Profile has already been created. Call observer immediately.
+ observer->OnProfileCreated(info->profile.get());
+ } else {
+ // Profile is being created. Add observer to list.
+ info->observers.push_back(observer);
+ }
+ } else {
+ // Initiate asynchronous creation process.
+ ProfileInfo* info =
+ RegisterProfile(Profile::CreateProfileAsync(user_data_dir, this),
+ false);
+ info->observers.push_back(observer);
+ }
+}
+
+// static
+void ProfileManager::CreateDefaultProfileAsync(Observer* observer) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+
+ FilePath default_profile_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &default_profile_dir);
+ default_profile_dir = default_profile_dir.Append(
+ profile_manager->GetCurrentProfileDir());
+
+ profile_manager->CreateProfileAsync(default_profile_dir,
+ observer);
}
-bool ProfileManager::AddProfile(Profile* profile, bool init_extensions) {
+bool ProfileManager::AddProfile(Profile* profile) {
DCHECK(profile);
// Make sure that we're not loading a profile with the same ID as a profile
@@ -234,22 +269,22 @@ bool ProfileManager::AddProfile(Profile* profile, bool init_extensions) {
return false;
}
- profiles_.insert(profiles_.end(), profile);
- if (init_extensions)
- profile->InitExtensions();
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (!command_line.HasSwitch(switches::kDisableWebResources))
- profile->InitPromoResources();
+ RegisterProfile(profile, true);
+ DoFinalInit(profile);
return true;
}
-Profile* ProfileManager::GetProfileByPath(const FilePath& path) const {
- for (const_iterator i(begin()); i != end(); ++i) {
- if ((*i)->GetPath() == path)
- return *i;
- }
+ProfileManager::ProfileInfo* ProfileManager::RegisterProfile(Profile* profile,
+ bool created) {
+ ProfileInfo* info = new ProfileInfo(profile, created);
+ ProfilesInfoMap::iterator new_elem =
+ (profiles_info_.insert(std::make_pair(profile->GetPath(), info))).first;
+ return info;
+}
- return NULL;
+Profile* ProfileManager::GetProfileByPath(const FilePath& path) const {
+ ProfilesInfoMap::const_iterator iter = profiles_info_.find(path);
+ return (iter == profiles_info_.end()) ? NULL : iter->second->profile.get();
}
void ProfileManager::OnSuspend() {
@@ -261,13 +296,14 @@ void ProfileManager::OnSuspend() {
DCHECK(posted);
scoped_refptr<net::URLRequestContextGetter> request_context;
- for (const_iterator i(begin()); i != end(); ++i) {
- request_context = (*i)->GetRequestContext();
+ std::vector<Profile*> profiles(GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i) {
+ request_context = profiles[i]->GetRequestContext();
posted = BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableFunction(&SuspendRequestContext, request_context));
DCHECK(posted);
- request_context = (*i)->GetRequestContextForMedia();
+ request_context = profiles[i]->GetRequestContextForMedia();
posted = BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableFunction(&SuspendRequestContext, request_context));
@@ -279,13 +315,14 @@ void ProfileManager::OnResume() {
DCHECK(CalledOnValidThread());
scoped_refptr<net::URLRequestContextGetter> request_context;
- for (const_iterator i(begin()); i != end(); ++i) {
- request_context = (*i)->GetRequestContext();
+ std::vector<Profile*> profiles(GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i) {
+ request_context = profiles[i]->GetRequestContext();
bool posted = BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableFunction(&ResumeRequestContext, request_context));
DCHECK(posted);
- request_context = (*i)->GetRequestContextForMedia();
+ request_context = profiles[i]->GetRequestContextForMedia();
posted = BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableFunction(&ResumeRequestContext, request_context));
@@ -315,30 +352,50 @@ void ProfileManager::Observe(
#endif
}
-// static
-bool ProfileManager::IsProfile(const FilePath& path) {
- FilePath prefs_path = GetProfilePrefsPath(path);
- FilePath history_path = path;
- history_path = history_path.Append(chrome::kHistoryFilename);
+void ProfileManager::DoFinalInit(Profile* profile) {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ bool init_extensions = true;
+#if defined(OS_CHROMEOS)
+ if (!logged_in_ &&
+ (!command_line.HasSwitch(switches::kTestType) ||
+ command_line.HasSwitch(switches::kLoginProfile))) {
+ init_extensions = false;
+ }
+#endif
+ if (init_extensions)
+ profile->InitExtensions();
- return file_util::PathExists(prefs_path) &&
- file_util::PathExists(history_path);
+ if (!command_line.HasSwitch(switches::kDisableWebResources))
+ profile->InitPromoResources();
}
-// 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";
- }
+void ProfileManager::OnProfileCreated(Profile* profile, bool success) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- 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;
+ ProfilesInfoMap::iterator iter = profiles_info_.find(profile->GetPath());
+ DCHECK(iter != profiles_info_.end());
+ ProfileInfo* info = iter->second.get();
+
+ std::vector<Observer*> observers;
+ info->observers.swap(observers);
+
+ if (success) {
+ DoFinalInit(profile);
+ info->created = true;
+#if defined(OS_CHROMEOS)
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (!logged_in_ &&
+ (!command_line.HasSwitch(switches::kTestType) ||
+ command_line.HasSwitch(switches::kLoginProfile))) {
+ profile = profile->GetOffTheRecordProfile();
+ }
+#endif
+ } else {
+ profile = NULL;
+ profiles_info_.erase(iter);
}
- return Profile::CreateProfile(path);
+ for (size_t i = 0; i < observers.size(); ++i) {
+ observers[i]->OnProfileCreated(profile);
+ }
}
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
index c90834f..eeca447 100644
--- a/chrome/browser/profiles/profile_manager.h
+++ b/chrome/browser/profiles/profile_manager.h
@@ -11,6 +11,10 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/hash_tables.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/threading/non_thread_safe.h"
#include "chrome/browser/profiles/profile.h"
@@ -22,8 +26,16 @@ class FilePath;
class ProfileManager : public base::NonThreadSafe,
public ui::SystemMonitor::PowerObserver,
- public NotificationObserver {
+ public NotificationObserver,
+ public Profile::Delegate {
public:
+ class Observer {
+ public:
+ // This method is called when profile is ready. If profile creation has been
+ // failed, method is called with |profile| equals to NULL.
+ virtual void OnProfileCreated(Profile* profile) = 0;
+ };
+
ProfileManager();
virtual ~ProfileManager();
@@ -44,6 +56,16 @@ class ProfileManager : public base::NonThreadSafe,
// otherwise it will create and manage it.
Profile* GetProfile(const FilePath& profile_dir);
+ // Explicit asynchronous creation of the profile. |observer| is called
+ // when profile is created. If profile has already been created, observer
+ // is called immediately. Should be called on the UI thread.
+ void CreateProfileAsync(const FilePath& user_data_dir,
+ Observer* observer);
+
+ // Initiates default profile creation. If default profile has already been
+ // created, observer is called immediately. Should be called on the UI thread.
+ static void CreateDefaultProfileAsync(Observer* observer);
+
// Returns the profile with the given |profile_id| or NULL if no such profile
// exists.
Profile* GetProfileWithId(ProfileId profile_id);
@@ -52,28 +74,13 @@ class ProfileManager : public base::NonThreadSafe,
// profile.
bool IsValidProfile(Profile* profile);
- // Returns a profile for a specific profile directory within the user data
- // dir with the option of controlling whether extensions are initialized
- // or not. This will return an existing profile it had already been created,
- // otherwise it will create and manage it.
- // Note that if the profile has already been created, extensions may have
- // been initialized. If this matters to you, you should call GetProfileByPath
- // first to see if the profile already exists.
- Profile* GetProfile(const FilePath& profile_dir, bool init_extensions);
-
// Returns the directory where the currently active profile is
// stored, relative to the user data directory currently in use..
FilePath GetCurrentProfileDir();
- // These allow iteration through the current list of profiles.
- typedef std::vector<Profile*> ProfileVector;
- typedef ProfileVector::iterator iterator;
- typedef ProfileVector::const_iterator const_iterator;
-
- iterator begin() { return profiles_.begin(); }
- const_iterator begin() const { return profiles_.begin(); }
- iterator end() { return profiles_.end(); }
- const_iterator end() const { return profiles_.end(); }
+ // Returns created profiles. Note, profiles order is NOT guaranteed to be
+ // related with the creation order.
+ std::vector<Profile*> GetLoadedProfiles() const;
// PowerObserver notifications
virtual void OnSuspend();
@@ -93,35 +100,48 @@ class ProfileManager : public base::NonThreadSafe,
// Returns the path to the preferences file given the user profile directory.
static FilePath GetProfilePrefsPath(const FilePath& profile_dir);
- // Tries to determine whether the given path represents a profile
- // directory, and returns true if it thinks it does.
- static bool IsProfile(const FilePath& path);
-
// If a profile with the given path is currently managed by this object,
// return a pointer to the corresponding Profile object;
// otherwise return NULL.
Profile* GetProfileByPath(const FilePath& path) const;
- // Creates a new profile at the specified path.
- // This method should always return a valid Profile (i.e., should never
- // return NULL).
- static Profile* CreateProfile(const FilePath& path);
+ // Profile::Delegate implementation:
+ virtual void OnProfileCreated(Profile* profile, bool success);
+
+ protected:
+ // Does final initial actions.
+ virtual void DoFinalInit(Profile* profile);
private:
friend class ExtensionEventRouterForwarderTest;
- // Helper method for unit tests to inject |profile| into the ProfileManager.
- void RegisterProfile(Profile* profile);
+ // This struct contains information about profiles which are being loaded or
+ // were loaded.
+ struct ProfileInfo {
+ ProfileInfo(Profile* profile, bool created)
+ : profile(profile), created(created) {
+ }
+
+ scoped_ptr<Profile> profile;
+ // Whether profile has been fully loaded (created and initialized).
+ bool created;
+ // List of observers which should be notified when profile initialization is
+ // done. Note, when profile is fully loaded this vector will be empty.
+ std::vector<Observer*> observers;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProfileInfo);
+ };
// Adds a pre-existing Profile object to the set managed by this
// ProfileManager. This ProfileManager takes ownership of the Profile.
// The Profile should not already be managed by this ProfileManager.
// Returns true if the profile was added, false otherwise.
- bool AddProfile(Profile* profile, bool init_extensions);
+ bool AddProfile(Profile* profile);
- // We keep a simple vector of profiles rather than something fancier
- // because we expect there to be a small number of profiles active.
- ProfileVector profiles_;
+ // Registers profile with given info. Returns pointer to created ProfileInfo
+ // entry.
+ ProfileInfo* RegisterProfile(Profile* profile, bool created);
NotificationRegistrar registrar_;
@@ -130,7 +150,19 @@ class ProfileManager : public base::NonThreadSafe,
// default.
bool logged_in_;
+ // Maps profile path to ProfileInfo (if profile has been created). Use
+ // RegisterProfile() to add into this map.
+ typedef std::map<FilePath, linked_ptr<ProfileInfo> > ProfilesInfoMap;
+ ProfilesInfoMap profiles_info_;
+
DISALLOW_COPY_AND_ASSIGN(ProfileManager);
};
+// Same as the ProfileManager, but doesn't initialize some services of the
+// profile. This one is useful in unittests.
+class ProfileManagerWithoutInit : public ProfileManager {
+ protected:
+ virtual void DoFinalInit(Profile*) {}
+};
+
#endif // CHROME_BROWSER_PROFILES_PROFILE_MANAGER_H_
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index eeea273..7080055 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -18,14 +18,23 @@
#include "chrome/test/testing_pref_service.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/system_monitor/system_monitor.h"
+namespace {
+// This global variable is used to check that value returned to different
+// observers is the same.
+Profile* g_created_profile;
+
+} // namespace
+
class ProfileManagerTest : public testing::Test {
protected:
ProfileManagerTest()
: ui_thread_(BrowserThread::UI, &message_loop_),
- file_thread_(BrowserThread::FILE, &message_loop_) {
+ file_thread_(BrowserThread::FILE, &message_loop_),
+ profile_manager_(new ProfileManagerWithoutInit) {
}
virtual void SetUp() {
@@ -40,11 +49,18 @@ class ProfileManagerTest : public testing::Test {
}
virtual void TearDown() {
+ profile_manager_.reset();
+
TestingBrowserProcess* testing_browser_process =
static_cast<TestingBrowserProcess*>(g_browser_process);
testing_browser_process->SetPrefService(NULL);
}
+ class MockObserver : public ProfileManager::Observer {
+ public:
+ MOCK_METHOD1(OnProfileCreated, void(Profile* profile));
+ };
+
// The path to temporary directory used to contain the test operations.
ScopedTempDir temp_dir_;
@@ -52,40 +68,30 @@ class ProfileManagerTest : public testing::Test {
BrowserThread ui_thread_;
BrowserThread file_thread_;
+ ui::SystemMonitor system_monitor_dummy_;
+
+ // Also will test profile deletion.
+ scoped_ptr<ProfileManager> profile_manager_;
+
TestingPrefService test_local_state_;
};
-TEST_F(ProfileManagerTest, CreateProfile) {
- FilePath source_path;
- PathService::Get(chrome::DIR_TEST_DATA, &source_path);
- source_path = source_path.Append(FILE_PATH_LITERAL("profiles"));
- source_path = source_path.Append(FILE_PATH_LITERAL("sample"));
-
+TEST_F(ProfileManagerTest, GetProfile) {
FilePath dest_path = temp_dir_.path();
dest_path = dest_path.Append(FILE_PATH_LITERAL("New Profile"));
- scoped_ptr<Profile> profile;
+ Profile* profile;
// Successfully create a profile.
- profile.reset(ProfileManager::CreateProfile(dest_path));
- ASSERT_TRUE(profile.get());
-
- profile.reset();
+ profile = profile_manager_->GetProfile(dest_path);
+ EXPECT_TRUE(profile);
-#ifdef NDEBUG
- // In Release mode, we always try to always return a profile. In debug,
- // these cases would trigger DCHECKs.
-
- // The profile already exists when we call CreateProfile. Just load it.
- profile.reset(ProfileManager::CreateProfile(dest_path));
- ASSERT_TRUE(profile.get());
-#endif
+ // The profile already exists when we call GetProfile. Just load it.
+ EXPECT_EQ(profile, profile_manager_->GetProfile(dest_path));
}
TEST_F(ProfileManagerTest, DefaultProfileDir) {
CommandLine *cl = CommandLine::ForCurrentProcess();
- ui::SystemMonitor dummy;
- ProfileManager profile_manager;
std::string profile_dir("my_user");
cl->AppendSwitch(switches::kTestType);
@@ -93,15 +99,13 @@ TEST_F(ProfileManagerTest, DefaultProfileDir) {
FilePath expected_default =
FilePath().AppendASCII(chrome::kNotSignedInProfile);
EXPECT_EQ(expected_default.value(),
- profile_manager.GetCurrentProfileDir().value());
+ profile_manager_->GetCurrentProfileDir().value());
}
#if defined(OS_CHROMEOS)
// This functionality only exists on Chrome OS.
TEST_F(ProfileManagerTest, LoggedInProfileDir) {
CommandLine *cl = CommandLine::ForCurrentProcess();
- ui::SystemMonitor dummy;
- ProfileManager profile_manager;
std::string profile_dir("my_user");
cl->AppendSwitchASCII(switches::kLoginProfile, profile_dir);
@@ -110,41 +114,36 @@ TEST_F(ProfileManagerTest, LoggedInProfileDir) {
FilePath expected_default =
FilePath().AppendASCII(chrome::kNotSignedInProfile);
EXPECT_EQ(expected_default.value(),
- profile_manager.GetCurrentProfileDir().value());
+ profile_manager_->GetCurrentProfileDir().value());
- profile_manager.Observe(NotificationType::LOGIN_USER_CHANGED,
- NotificationService::AllSources(),
- NotificationService::NoDetails());
+ profile_manager_->Observe(NotificationType::LOGIN_USER_CHANGED,
+ NotificationService::AllSources(),
+ NotificationService::NoDetails());
FilePath expected_logged_in(profile_dir);
EXPECT_EQ(expected_logged_in.value(),
- profile_manager.GetCurrentProfileDir().value());
+ profile_manager_->GetCurrentProfileDir().value());
VLOG(1) << temp_dir_.path().Append(
- profile_manager.GetCurrentProfileDir()).value();
+ profile_manager_->GetCurrentProfileDir()).value();
}
#endif
TEST_F(ProfileManagerTest, CreateAndUseTwoProfiles) {
- FilePath source_path;
- PathService::Get(chrome::DIR_TEST_DATA, &source_path);
- source_path = source_path.Append(FILE_PATH_LITERAL("profiles"));
- source_path = source_path.Append(FILE_PATH_LITERAL("sample"));
-
FilePath dest_path1 = temp_dir_.path();
dest_path1 = dest_path1.Append(FILE_PATH_LITERAL("New Profile 1"));
FilePath dest_path2 = temp_dir_.path();
dest_path2 = dest_path2.Append(FILE_PATH_LITERAL("New Profile 2"));
- scoped_ptr<Profile> profile1;
- scoped_ptr<Profile> profile2;
+ Profile* profile1;
+ Profile* profile2;
// Successfully create the profiles.
- profile1.reset(ProfileManager::CreateProfile(dest_path1));
- ASSERT_TRUE(profile1.get());
+ profile1 = profile_manager_->GetProfile(dest_path1);
+ ASSERT_TRUE(profile1);
- profile2.reset(ProfileManager::CreateProfile(dest_path2));
- ASSERT_TRUE(profile2.get());
+ profile2 = profile_manager_->GetProfile(dest_path2);
+ ASSERT_TRUE(profile2);
// Force lazy-init of some profile services to simulate use.
EXPECT_TRUE(profile1->GetHistoryService(Profile::EXPLICIT_ACCESS));
@@ -155,9 +154,62 @@ TEST_F(ProfileManagerTest, CreateAndUseTwoProfiles) {
// Make sure any pending tasks run before we destroy the profiles.
message_loop_.RunAllPending();
- profile1.reset();
- profile2.reset();
+ profile_manager_.reset();
// Make sure history cleans up correctly.
message_loop_.RunAllPending();
}
+
+// Tests asynchronous profile creation mechanism.
+TEST_F(ProfileManagerTest, CreateProfileAsync) {
+ FilePath dest_path =
+ temp_dir_.path().Append(FILE_PATH_LITERAL("New Profile"));
+
+ MockObserver mock_observer;
+ EXPECT_CALL(mock_observer, OnProfileCreated(testing::NotNull())).Times(1);
+
+ profile_manager_->CreateProfileAsync(dest_path, &mock_observer);
+
+ message_loop_.RunAllPending();
+}
+
+MATCHER(SameNotNull, "The same non-NULL value for all cals.") {
+ if (!g_created_profile)
+ g_created_profile = arg;
+ return g_created_profile == arg;
+}
+
+TEST_F(ProfileManagerTest, CreateProfileAsyncMultipleRequests) {
+ FilePath dest_path =
+ temp_dir_.path().Append(FILE_PATH_LITERAL("New Profile"));
+
+ g_created_profile = NULL;
+
+ MockObserver mock_observer1;
+ EXPECT_CALL(mock_observer1, OnProfileCreated(SameNotNull())).Times(1);
+ MockObserver mock_observer2;
+ EXPECT_CALL(mock_observer2, OnProfileCreated(SameNotNull())).Times(1);
+ MockObserver mock_observer3;
+ EXPECT_CALL(mock_observer3, OnProfileCreated(SameNotNull())).Times(1);
+
+ profile_manager_->CreateProfileAsync(dest_path, &mock_observer1);
+ profile_manager_->CreateProfileAsync(dest_path, &mock_observer2);
+ profile_manager_->CreateProfileAsync(dest_path, &mock_observer3);
+
+ message_loop_.RunAllPending();
+}
+
+TEST_F(ProfileManagerTest, CreateProfilesAsync) {
+ FilePath dest_path1 =
+ temp_dir_.path().Append(FILE_PATH_LITERAL("New Profile 1"));
+ FilePath dest_path2 =
+ temp_dir_.path().Append(FILE_PATH_LITERAL("New Profile 2"));
+
+ MockObserver mock_observer;
+ EXPECT_CALL(mock_observer, OnProfileCreated(testing::NotNull())).Times(2);
+
+ profile_manager_->CreateProfileAsync(dest_path1, &mock_observer);
+ profile_manager_->CreateProfileAsync(dest_path2, &mock_observer);
+
+ message_loop_.RunAllPending();
+}
diff --git a/chrome/browser/task_manager/task_manager.cc b/chrome/browser/task_manager/task_manager.cc
index 7f8a5d3..746c07a 100644
--- a/chrome/browser/task_manager/task_manager.cc
+++ b/chrome/browser/task_manager/task_manager.cc
@@ -979,12 +979,13 @@ void TaskManager::OpenAboutMemory() {
if (!browser) {
// On OS X, the task manager can be open without any open browser windows.
- if (!g_browser_process ||
- !g_browser_process->profile_manager() ||
- g_browser_process->profile_manager()->begin() ==
- g_browser_process->profile_manager()->end())
+ if (!g_browser_process || !g_browser_process->profile_manager())
return;
- browser = Browser::Create(*g_browser_process->profile_manager()->begin());
+ Profile* profile =
+ g_browser_process->profile_manager()->GetDefaultProfile();
+ if (!profile)
+ return;
+ browser = Browser::Create(profile);
browser->OpenURL(GURL(chrome::kAboutMemoryURL), GURL(), NEW_FOREGROUND_TAB,
PageTransition::LINK);
browser->window()->Show();
diff --git a/chrome/browser/task_manager/task_manager_resource_providers.cc b/chrome/browser/task_manager/task_manager_resource_providers.cc
index c4dfbf8..05d17b8 100644
--- a/chrome/browser/task_manager/task_manager_resource_providers.cc
+++ b/chrome/browser/task_manager/task_manager_resource_providers.cc
@@ -681,11 +681,11 @@ void TaskManagerBackgroundContentsResourceProvider::StartUpdating() {
// Add all the existing BackgroundContents from every profile.
ProfileManager* profile_manager = g_browser_process->profile_manager();
- for (ProfileManager::const_iterator it = profile_manager->begin();
- it != profile_manager->end(); ++it) {
+ std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i) {
BackgroundContentsService* background_contents_service =
- (*it)->GetBackgroundContentsService();
- ExtensionService* extensions_service = (*it)->GetExtensionService();
+ profiles[i]->GetBackgroundContentsService();
+ ExtensionService* extensions_service = profiles[i]->GetExtensionService();
std::vector<BackgroundContents*> contents =
background_contents_service->GetBackgroundContents();
for (std::vector<BackgroundContents*>::iterator iterator = contents.begin();
@@ -1207,10 +1207,10 @@ void TaskManagerExtensionProcessResourceProvider::StartUpdating() {
// Add all the existing ExtensionHosts.
ProfileManager* profile_manager = g_browser_process->profile_manager();
- for (ProfileManager::const_iterator it = profile_manager->begin();
- it != profile_manager->end(); ++it) {
+ std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
+ for (size_t i = 0; i < profiles.size(); ++i) {
ExtensionProcessManager* process_manager =
- (*it)->GetExtensionProcessManager();
+ profiles[i]->GetExtensionProcessManager();
if (process_manager) {
ExtensionProcessManager::const_iterator jt;
for (jt = process_manager->begin(); jt != process_manager->end(); ++jt)
@@ -1221,7 +1221,7 @@ void TaskManagerExtensionProcessResourceProvider::StartUpdating() {
// extensions.
if (BrowserList::IsOffTheRecordSessionActive()) {
ExtensionProcessManager* process_manager =
- (*it)->GetOffTheRecordProfile()->GetExtensionProcessManager();
+ profiles[i]->GetOffTheRecordProfile()->GetExtensionProcessManager();
if (process_manager) {
ExtensionProcessManager::const_iterator jt;
for (jt = process_manager->begin(); jt != process_manager->end(); ++jt)