With this implementation, logging on to sync logs you in to the multiprofile system (if --multi-profiles flag is on).

A drop-down menu then appears, from which you can create a new profile; this will open a browser window from which you can sync to a different Google account.

When the browser is shut down, the active profile is saved. This profile will be used when the browser is reopened.

Many things need to be added -- there's no duplicate checking, no way to delete a profile, and no color scheme -- etc.  This is just the most basic multi-profile functionality.

BUG=60105
TEST=existing tests; full suite to come.
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=83261
Review URL: http://codereview.chromium.org/6881054

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@83284 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index a4fd01e..ef17b57 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -806,8 +806,10 @@
 // should not continue.
 Profile* CreateProfile(const MainFunctionParams& parameters,
                        const FilePath& user_data_dir) {
-  Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile(
-      user_data_dir);
+  const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+  Profile* profile = browser_command_line.HasSwitch(switches::kMultiProfiles) ?
+      g_browser_process->profile_manager()->GetLastUsedProfile(user_data_dir) :
+      g_browser_process->profile_manager()->GetDefaultProfile(user_data_dir);
   if (profile)
     return profile;
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 2dd4dcb..2df2b2e4 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -38,6 +38,7 @@
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/printing/print_job_manager.h"
 #include "chrome/browser/profiles/profile_impl.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/renderer_host/web_cache_manager.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/search_engines/template_url_model.h"
@@ -109,6 +110,7 @@
   NotificationUIManager::RegisterPrefs(local_state);
   PrefProxyConfigService::RegisterPrefs(local_state);
   policy::CloudPolicySubsystem::RegisterPrefs(local_state);
+  ProfileManager::RegisterPrefs(local_state);
 #if defined(OS_CHROMEOS)
   chromeos::AudioMixerAlsa::RegisterPrefs(local_state);
   chromeos::UserManager::RegisterPrefs(local_state);
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 0b0f2e1e..e7ff3f376 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -210,6 +210,11 @@
     return reinterpret_cast<ProfileId>(this);
   }
 
+  virtual std::string GetProfileName() {
+    // Incognito profile should not return the profile name.
+    return std::string();
+  }
+
   virtual FilePath GetPath() { return profile_->GetPath(); }
 
   virtual bool IsOffTheRecord() {
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index bbc6658..a3b2a6e9 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -165,6 +165,10 @@
   // NOTIFY_DEFAULT_REQUEST_CONTEXT_AVAILABLE.
   static net::URLRequestContextGetter* GetDefaultRequestContext();
 
+  // Returns the name associated with this profile. This name is displayed in
+  // the browser frame.
+  virtual std::string GetProfileName() = 0;
+
   // Returns a unique Id that can be used to identify this profile at runtime.
   // This Id is not persistent and will not survive a restart of the browser.
   virtual ProfileId GetRuntimeId() = 0;
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 92e7630..8cd12c6 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -246,7 +246,7 @@
 Profile* Profile::CreateProfileAsync(const FilePath&path,
                                      Profile::Delegate* delegate) {
   DCHECK(delegate);
-  // This is safe while all file opeartions are done on the FILE thread.
+  // This is safe while all file operations are done on the FILE thread.
   BrowserThread::PostTask(BrowserThread::FILE,
                           FROM_HERE,
                           NewRunnableFunction(&file_util::CreateDirectory,
@@ -311,6 +311,7 @@
   pref_change_registrar_.Add(prefs::kEnableSpellCheck, this);
   pref_change_registrar_.Add(prefs::kEnableAutoSpellCorrect, this);
   pref_change_registrar_.Add(prefs::kClearSiteDataOnExit, this);
+  pref_change_registrar_.Add(prefs::kGoogleServicesUsername, this);
 
   // It would be nice to use PathService for fetching this directory, but
   // the cache directory depends on the profile directory, which isn't available
@@ -661,6 +662,10 @@
   MarkAsCleanShutdown();
 }
 
+std::string ProfileImpl::GetProfileName() {
+  return GetPrefs()->GetString(prefs::kGoogleServicesUsername);
+}
+
 ProfileId ProfileImpl::GetRuntimeId() {
   return reinterpret_cast<ProfileId>(this);
 }
@@ -1346,6 +1351,9 @@
         appcache_service_->SetClearLocalStateOnExit(
             clear_local_state_on_exit_);
       }
+    } else if (*pref_name_in == prefs::kGoogleServicesUsername) {
+      ProfileManager* profile_manager = g_browser_process->profile_manager();
+      profile_manager->RegisterProfileName(this);
     }
   } else if (NotificationType::BOOKMARK_MODEL_LOADED == type) {
     GetProfileSyncService();  // Causes lazy-load if sync is enabled.
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 0119610..00e30fe 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -44,6 +44,7 @@
   static void RegisterUserPrefs(PrefService* prefs);
 
   // Profile implementation.
+  virtual std::string GetProfileName();
   virtual ProfileId GetRuntimeId();
   virtual FilePath GetPath();
   virtual bool IsOffTheRecord();
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 94af544..7011e8e 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -7,16 +7,22 @@
 #include "chrome/browser/profiles/profile_manager.h"
 
 #include "base/command_line.h"
+#include "base/file_path.h"
 #include "base/file_util.h"
 #include "base/path_service.h"
+#include "base/string_number_conversions.h"
 #include "base/string_util.h"
+#include "base/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/ui/browser_window.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/pref_names.h"
 #include "content/browser/browser_thread.h"
 #include "content/common/notification_service.h"
 #include "content/common/notification_type.h"
@@ -63,6 +69,23 @@
 
 }  // namespace
 
+// The NewProfileLauncher class is created when to wait for a multi-profile
+// to be created asynchronously. Upon completion of profile creation, the
+// NPL takes care of launching a new browser window and signing the user
+// in to their Google account.
+class NewProfileLauncher : public ProfileManager::Observer {
+ public:
+  virtual void OnProfileCreated(Profile* profile) {
+    Browser::NewWindowWithProfile(profile);
+    ProfileSyncService* service = profile->GetProfileSyncService();
+    DCHECK(service);
+    service->ShowLoginDialog(NULL);
+    ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_PROFILE_MENU);
+  }
+
+  virtual bool DeleteAfterCreation() OVERRIDE { return true; }
+};
+
 // static
 void ProfileManager::ShutdownSessionServices() {
   ProfileManager* pm = g_browser_process->profile_manager();
@@ -83,6 +106,7 @@
 
 ProfileManager::ProfileManager() : logged_in_(false) {
   ui::SystemMonitor::Get()->AddObserver(this);
+  BrowserList::AddObserver(this);
 #if defined(OS_CHROMEOS)
   registrar_.Add(
       this,
@@ -95,6 +119,7 @@
   ui::SystemMonitor* system_monitor = ui::SystemMonitor::Get();
   if (system_monitor)
     system_monitor->RemoveObserver(this);
+  BrowserList::RemoveObserver(this);
 }
 
 FilePath ProfileManager::GetDefaultProfileDir(
@@ -130,11 +155,38 @@
     return relative_profile_dir;
   }
 #endif
+  // TODO(mirandac): should not automatically be default profile.
   relative_profile_dir =
       relative_profile_dir.AppendASCII(chrome::kNotSignedInProfile);
   return relative_profile_dir;
 }
 
+Profile* ProfileManager::GetLastUsedProfile(const FilePath& user_data_dir) {
+  FilePath last_used_profile_dir(user_data_dir);
+  std::string last_profile_used;
+  PrefService* local_state = g_browser_process->local_state();
+  DCHECK(local_state);
+
+  if (local_state->HasPrefPath(prefs::kProfileLastUsed))
+    last_profile_used = local_state->GetString(prefs::kProfileLastUsed);
+  last_used_profile_dir = last_profile_used.empty() ?
+      last_used_profile_dir.AppendASCII(chrome::kNotSignedInProfile) :
+      last_used_profile_dir.AppendASCII(last_profile_used);
+  return GetProfile(last_used_profile_dir);
+}
+
+void ProfileManager::RegisterProfileName(Profile* profile) {
+  std::string profile_name = profile->GetProfileName();
+  std::string dir_base = profile->GetPath().BaseName().MaybeAsASCII();
+  DictionaryPrefUpdate update(g_browser_process->local_state(),
+                              prefs::kProfileDirectoryMap);
+  DictionaryValue* path_map = update.Get();
+  // We don't check for duplicates because we should be able to overwrite
+  // path->name mappings here, if the user syncs a local account to a
+  // different Google account.
+  path_map->SetString(dir_base, profile_name);
+}
+
 Profile* ProfileManager::GetDefaultProfile(const FilePath& user_data_dir) {
   FilePath default_profile_dir(user_data_dir);
   default_profile_dir = default_profile_dir.Append(GetCurrentProfileDir());
@@ -250,6 +302,7 @@
 
   FilePath default_profile_dir;
   PathService::Get(chrome::DIR_USER_DATA, &default_profile_dir);
+  // TODO(mirandac): current directory will not always be default in the future
   default_profile_dir = default_profile_dir.Append(
       profile_manager->GetCurrentProfileDir());
 
@@ -352,6 +405,18 @@
 #endif
 }
 
+void ProfileManager::OnBrowserAdded(const Browser* browser) {}
+
+void ProfileManager::OnBrowserRemoved(const Browser* browser) {}
+
+void ProfileManager::OnBrowserSetLastActive(const Browser* browser) {
+  Profile* last_active = browser->GetProfile();
+  PrefService* local_state = g_browser_process->local_state();
+  DCHECK(local_state);
+  local_state->SetString(prefs::kProfileLastUsed,
+      last_active->GetPath().BaseName().MaybeAsASCII());
+}
+
 void ProfileManager::DoFinalInit(Profile* profile) {
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
   bool init_extensions = true;
@@ -394,7 +459,46 @@
     profiles_info_.erase(iter);
   }
 
+  std::vector<Observer*> observers_to_delete;
+
   for (size_t i = 0; i < observers.size(); ++i) {
     observers[i]->OnProfileCreated(profile);
+    if (observers[i]->DeleteAfterCreation())
+      observers_to_delete.push_back(observers[i]);
   }
+
+  observers_to_delete.clear();
+}
+
+// static
+void ProfileManager::CreateMultiProfileAsync() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  // Create the next profile in the next available directory slot.
+  PrefService* local_state = g_browser_process->local_state();
+  DCHECK(local_state);
+
+  int next_directory = local_state->GetInteger(prefs::kProfilesNumCreated);
+  std::string profile_name = chrome::kMultiProfileDirPrefix;
+  profile_name.append(base::IntToString(next_directory));
+  FilePath new_path;
+  PathService::Get(chrome::DIR_USER_DATA, &new_path);
+#if defined(OS_WIN)
+  new_path = new_path.Append(ASCIIToUTF16(profile_name));
+#else
+  new_path = new_path.Append(profile_name);
+#endif
+  local_state->SetInteger(prefs::kProfilesNumCreated, ++next_directory);
+
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  // The launcher is deleted by the manager when profile creation is finished.
+  NewProfileLauncher* launcher = new NewProfileLauncher();
+  profile_manager->CreateProfileAsync(new_path, launcher);
+}
+
+// static
+void ProfileManager::RegisterPrefs(PrefService* prefs) {
+  prefs->RegisterStringPref(prefs::kProfileLastUsed, "");
+  prefs->RegisterDictionaryPref(prefs::kProfileDirectoryMap);
+  prefs->RegisterIntegerPref(prefs::kProfilesNumCreated, 1);
 }
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
index 9af8f2b5..98190b11 100644
--- a/chrome/browser/profiles/profile_manager.h
+++ b/chrome/browser/profiles/profile_manager.h
@@ -8,6 +8,7 @@
 #define CHROME_BROWSER_PROFILES_PROFILE_MANAGER_H_
 #pragma once
 
+#include <list>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -18,22 +19,29 @@
 #include "base/message_loop.h"
 #include "base/threading/non_thread_safe.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "content/common/notification_observer.h"
 #include "content/common/notification_registrar.h"
 #include "ui/base/system_monitor/system_monitor.h"
 
 class FilePath;
+class NewProfileLauncher;
 
 class ProfileManager : public base::NonThreadSafe,
                        public ui::SystemMonitor::PowerObserver,
+                       public BrowserList::Observer,
                        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.
+    // This method is called when profile is ready. If profile creation has
+    // failed, method is called with |profile| equal to NULL.
     virtual void OnProfileCreated(Profile* profile) = 0;
+
+    // If true, delete the observer after the profile has been created. Default
+    // is false.
+    virtual bool DeleteAfterCreation() { return false; }
   };
 
   ProfileManager();
@@ -78,6 +86,13 @@
   // stored, relative to the user data directory currently in use..
   FilePath GetCurrentProfileDir();
 
+  // Get the Profile last used with this Chrome build. If no signed profile has
+  // been stored in Local State, hand back the Default profile.
+  Profile* GetLastUsedProfile(const FilePath& user_data_dir);
+
+  // Register the mapping of a directory to a profile name in Local State.
+  void RegisterProfileName(Profile* profile);
+
   // Returns created profiles. Note, profiles order is NOT guaranteed to be
   // related with the creation order.
   std::vector<Profile*> GetLoadedProfiles() const;
@@ -91,6 +106,11 @@
                        const NotificationSource& source,
                        const NotificationDetails& details);
 
+  // BrowserList::Observer implementation.
+  virtual void OnBrowserAdded(const Browser* browser);
+  virtual void OnBrowserRemoved(const Browser* browser);
+  virtual void OnBrowserSetLastActive(const Browser* browser);
+
   // ------------------ static utility functions -------------------
 
   // Returns the path to the default profile directory, based on the given
@@ -108,6 +128,20 @@
   // Profile::Delegate implementation:
   virtual void OnProfileCreated(Profile* profile, bool success);
 
+  // Add or remove a profile launcher to/from the list of launchers waiting for
+  // new profiles to be created from the multi-profile menu.
+  void AddProfileLauncher(NewProfileLauncher* profile_launcher);
+  void RemoveProfileLauncher(NewProfileLauncher* profile_launcher);
+
+  // Creates a new profile in the next available multiprofile directory.
+  // Directories are named "profile_1", "profile_2", etc., in sequence of
+  // creation. (Because directories can be removed, however, it may be the case
+  // that at some point the list of numbered profiles is not continuous.)
+  static void CreateMultiProfileAsync();
+
+  // Register multi-profile related preferences in Local State.
+  static void RegisterPrefs(PrefService* prefs);
+
  protected:
   // Does final initial actions.
   virtual void DoFinalInit(Profile* profile);
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index 4a4a4b8..97fffcf 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -8,12 +8,14 @@
 #include "base/memory/scoped_temp_dir.h"
 #include "base/message_loop.h"
 #include "base/path_service.h"
+#include "base/values.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/testing_browser_process_test.h"
 #include "chrome/test/testing_pref_service.h"
 #include "content/browser/browser_thread.h"
@@ -119,6 +121,29 @@
 
 #endif
 
+TEST_F(ProfileManagerTest, RegisterProfileName) {
+  // Create a test profile.
+  FilePath dest_path1 = temp_dir_.path();
+  std::string dir_base("New Profile 1");
+  dest_path1 = dest_path1.Append(FILE_PATH_LITERAL("New Profile 1"));
+  Profile* profile1;
+  profile1 = profile_manager_->GetProfile(dest_path1);
+  ASSERT_TRUE(profile1);
+
+  // Simulate registration of the profile name (normally triggered by the
+  // change of the kGoogleServicesUsername preference):
+  std::string testname("testname");
+  profile1->GetPrefs()->SetString(prefs::kGoogleServicesUsername, testname);
+  profile_manager_->RegisterProfileName(profile1);
+
+  // Profile name should be associated with the directory in Local State.
+  std::string stored_profile_name;
+  const DictionaryValue* path_map = static_cast<const DictionaryValue*>(
+      local_state_.Get()->GetUserPref(prefs::kProfileDirectoryMap));
+  path_map->GetString(dir_base, &stored_profile_name);
+  ASSERT_STREQ(testname.c_str(), stored_profile_name.c_str());
+}
+
 TEST_F(ProfileManagerTest, CreateAndUseTwoProfiles) {
   FilePath dest_path1 = temp_dir_.path();
   dest_path1 = dest_path1.Append(FILE_PATH_LITERAL("New Profile 1"));
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index 7b0d9056..05aa410b 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -112,6 +112,7 @@
     START_FROM_WRENCH = 2,   // Sync was started from the Wrench menu.
     START_FROM_OPTIONS = 3,  // Sync was started from Wrench->Options.
     START_FROM_BOOKMARK_MANAGER = 4,  // Sync was started from Bookmark manager.
+    START_FROM_PROFILE_MENU = 5,  // Sync was started from multiprofile menu.
 
     // Events regarding cancellation of the signon process of sync.
     CANCEL_FROM_SIGNON_WITHOUT_AUTH = 10,   // Cancelled before submitting
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 20bea8e..9075cc0 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -752,6 +752,16 @@
   browser->window()->Show();
 }
 
+// static
+void Browser::NewWindowWithProfile(Profile* profile) {
+  UserMetrics::RecordAction(UserMetricsAction("NewWindow"));
+  SessionService* session_service =
+      profile->GetOriginalProfile()->GetSessionService();
+  if (!session_service ||
+      !session_service->RestoreIfNecessary(std::vector<GURL>())) {
+    Browser::OpenEmptyWindow(profile->GetOriginalProfile());
+  }
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // Browser, State Storage and Retrieval for UI:
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 5155909..6288a2e0a 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -292,6 +292,12 @@
   // extensions which may run with no windows open.
   static void OpenExtensionsWindow(Profile* profile);
 
+  // Opens a new window with the given profile. This starts the session_service
+  // for the new profile as well; it is the static equivalent of the instance
+  // method Browser::NewWindow(), used for the creation of a Window from the
+  // multi-profile dropdown menu.
+  static void NewWindowWithProfile(Profile* profile);
+
   // State Storage and Retrieval for UI ///////////////////////////////////////
 
   // Save and restore the window position.
diff --git a/chrome/browser/ui/views/profile_menu_model.cc b/chrome/browser/ui/views/profile_menu_model.cc
index da2021a..8c29c3a9 100644
--- a/chrome/browser/ui/views/profile_menu_model.cc
+++ b/chrome/browser/ui/views/profile_menu_model.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/profile_menu_model.h"
 
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/sync/profile_sync_service.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/accelerator.h"
@@ -14,7 +16,7 @@
 
 ProfileMenuModel::ProfileMenuModel()
     : ALLOW_THIS_IN_INITIALIZER_LIST(ui::SimpleMenuModel(this)) {
-  AddItem(0, l10n_util::GetStringUTF16(
+  AddItem(COMMAND_CREATE_NEW_PROFILE, l10n_util::GetStringUTF16(
       IDS_PROFILES_CREATE_NEW_PROFILE_OPTION));
   menu_.reset(new views::Menu2(this));
 }
@@ -31,7 +33,7 @@
 }
 
 bool ProfileMenuModel::IsCommandIdEnabled(int command_id) const {
-  return false;
+  return true;
 }
 
 bool ProfileMenuModel::GetAcceleratorForCommandId(int command_id,
@@ -40,7 +42,14 @@
 }
 
 void ProfileMenuModel::ExecuteCommand(int command_id) {
-  NOTIMPLEMENTED();
+  switch (command_id) {
+    case COMMAND_CREATE_NEW_PROFILE:
+      ProfileManager::CreateMultiProfileAsync();
+      break;
+    default:
+      NOTIMPLEMENTED();
+      break;
+  }
 }
 
 }  // namespace views
diff --git a/chrome/browser/ui/views/profile_menu_model.h b/chrome/browser/ui/views/profile_menu_model.h
index 9f2bc74..7ee2203 100644
--- a/chrome/browser/ui/views/profile_menu_model.h
+++ b/chrome/browser/ui/views/profile_menu_model.h
@@ -38,6 +38,10 @@
   virtual void ExecuteCommand(int command_id);
 
  private:
+  enum {
+    COMMAND_CREATE_NEW_PROFILE,
+  };
+
   scoped_ptr<views::Menu2> menu_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileMenuModel);
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 465a1efe6..6cd9514 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -70,6 +70,7 @@
 const wchar_t kCrashReportLog[] = L"Reported Crashes.txt";
 const wchar_t kTestingInterfaceDLL[] = L"testing_interface.dll";
 const char    kNotSignedInProfile[] = "Default";
+const char    kMultiProfileDirPrefix[] = "profile_";
 const wchar_t kBrowserResourcesDll[] = L"chrome.dll";
 const FilePath::CharType kExtensionFileExtension[] = FPL(".crx");
 const FilePath::CharType kExtensionKeyFileExtension[] = FPL(".pem");
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index 4cc992db..e6d8fbe 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -31,6 +31,7 @@
 extern const wchar_t kCrashReportLog[];
 extern const wchar_t kTestingInterfaceDLL[];
 extern const char    kNotSignedInProfile[];
+extern const char    kMultiProfileDirPrefix[];
 extern const char    kStatsFilename[];
 extern const wchar_t kBrowserResourcesDll[];
 extern const wchar_t kNaClAppName[];
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index f1869af2..4c4fbcc8 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -704,6 +704,16 @@
 // *************** LOCAL STATE ***************
 // These are attached to the machine/installation
 
+// Directory of the last profile used.
+const char kProfileLastUsed[] = "profile.last_used";
+
+// Maps profile data directories to login names.
+const char kProfileDirectoryMap[] = "profile.directory_map";
+
+// Total number of profiles created for this Chrome build. Used to tag profile
+// directories.
+const char kProfilesNumCreated[] = "profile.profiles_created";
+
 // Prefs for SSLConfigServicePref.
 const char kCertRevocationCheckingEnabled[] = "ssl.rev_checking.enabled";
 const char kSSL3Enabled[] = "ssl.ssl3.enabled";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 53da7bb..b1f62e3 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -258,6 +258,10 @@
 extern const char kMetricsInitialLogs[];
 extern const char kMetricsOngoingLogs[];
 
+extern const char kProfileLastUsed[];
+extern const char kProfileDirectoryMap[];
+extern const char kProfilesNumCreated[];
+
 extern const char kProfileMetrics[];
 extern const char kProfilePrefix[];
 
diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc
index 560c603..dbfa6c40 100644
--- a/chrome/test/testing_profile.cc
+++ b/chrome/test/testing_profile.cc
@@ -379,6 +379,10 @@
   return testing_prefs_;
 }
 
+std::string TestingProfile::GetProfileName() {
+  return std::string("testing_profile");
+}
+
 ProfileId TestingProfile::GetRuntimeId() {
     return reinterpret_cast<ProfileId>(this);
   }
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 1543b35..c82e5e3 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -134,6 +134,7 @@
 
   TestingPrefService* GetTestingPrefService();
 
+  virtual std::string GetProfileName();
   virtual ProfileId GetRuntimeId();
 
   virtual FilePath GetPath();