OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/user_data_manager.h" |
| 6 |
| 7 #include <windows.h> |
| 8 #include <string> |
| 9 |
| 10 #include "base/command_line.h" |
| 11 #include "base/file_util.h" |
| 12 #include "base/logging.h" |
| 13 #include "base/message_loop.h" |
| 14 #include "base/path_service.h" |
| 15 #include "base/process_util.h" |
| 16 #include "base/string_util.h" |
| 17 #include "chrome/browser/chrome_thread.h" |
| 18 #include "chrome/common/chrome_constants.h" |
| 19 #include "chrome/common/chrome_paths.h" |
| 20 #include "chrome/common/chrome_switches.h" |
| 21 #include "chrome/common/l10n_util.h" |
| 22 #include "chrome/installer/util/browser_distribution.h" |
| 23 #include "chrome/installer/util/shell_util.h" |
| 24 |
| 25 #include "chromium_strings.h" |
| 26 |
| 27 namespace { |
| 28 |
| 29 // Helper to start chrome for a given profile index. The helper takes care of |
| 30 // enumerating profiles on the file thread and then it launches Chrome for the |
| 31 // appropriate profile on the original thread. |
| 32 // An instance of this class should always be created on the heap, and it will |
| 33 // delete itself when the launch is done. |
| 34 class LaunchChromeForProfileIndexHelper : GetProfilesHelper::Delegate { |
| 35 public: |
| 36 // Creates an instance with the given data manager and to launch chrome for |
| 37 // the profile with the given index. |
| 38 LaunchChromeForProfileIndexHelper(const UserDataManager* manager, int index); |
| 39 virtual ~LaunchChromeForProfileIndexHelper(); |
| 40 |
| 41 // Starts the asynchronous launch. |
| 42 void StartLaunch(); |
| 43 |
| 44 // GetProfilesHelper::Delegate method. |
| 45 void OnGetProfilesDone(const std::vector<std::wstring>& profiles); |
| 46 |
| 47 private: |
| 48 int index_; |
| 49 const UserDataManager* manager_; |
| 50 scoped_refptr<GetProfilesHelper> profiles_helper_; |
| 51 |
| 52 DISALLOW_COPY_AND_ASSIGN(LaunchChromeForProfileIndexHelper); |
| 53 }; |
| 54 |
| 55 } // namespace |
| 56 |
| 57 LaunchChromeForProfileIndexHelper::LaunchChromeForProfileIndexHelper( |
| 58 const UserDataManager* manager, |
| 59 int index) |
| 60 : manager_(manager), |
| 61 index_(index), |
| 62 profiles_helper_(new GetProfilesHelper(this)) { |
| 63 DCHECK(manager); |
| 64 } |
| 65 |
| 66 LaunchChromeForProfileIndexHelper::~LaunchChromeForProfileIndexHelper() { |
| 67 profiles_helper_->OnDelegateDeleted(); |
| 68 } |
| 69 |
| 70 void LaunchChromeForProfileIndexHelper::StartLaunch() { |
| 71 profiles_helper_->GetProfiles(NULL); |
| 72 } |
| 73 |
| 74 void LaunchChromeForProfileIndexHelper::OnGetProfilesDone( |
| 75 const std::vector<std::wstring>& profiles) { |
| 76 if (index_ >= 0 && index_ < static_cast<int>(profiles.size())) |
| 77 manager_->LaunchChromeForProfile(profiles[index_]); |
| 78 |
| 79 // We are done, delete ourselves. |
| 80 delete this; |
| 81 } |
| 82 |
| 83 // Separator used in folder names between the prefix and the profile name. |
| 84 // For e.g. a folder for the profile "Joe" would be named "User Data-Joe". |
| 85 static const wchar_t kProfileFolderSeparator[] = L"-"; |
| 86 |
| 87 // static |
| 88 UserDataManager* UserDataManager::instance_ = NULL; |
| 89 |
| 90 // static |
| 91 void UserDataManager::Create() { |
| 92 DCHECK(!instance_); |
| 93 std::wstring user_data; |
| 94 PathService::Get(chrome::DIR_USER_DATA, &user_data); |
| 95 instance_ = new UserDataManager(user_data); |
| 96 } |
| 97 |
| 98 // static |
| 99 UserDataManager* UserDataManager::Get() { |
| 100 DCHECK(instance_); |
| 101 return instance_; |
| 102 } |
| 103 |
| 104 UserDataManager::UserDataManager(const std::wstring& user_data_root) |
| 105 : user_data_root_(user_data_root) { |
| 106 // Determine current profile name, current folder name and whether the current |
| 107 // profile is the default. |
| 108 current_folder_name_ = file_util::GetFilenameFromPath(user_data_root); |
| 109 is_current_profile_default_ = |
| 110 (current_folder_name_ == chrome::kUserDataDirname); |
| 111 bool success = GetProfileNameFromFolderName(current_folder_name_, |
| 112 ¤t_profile_name_); |
| 113 DCHECK(success); |
| 114 file_util::UpOneDirectory(&user_data_root_); |
| 115 } |
| 116 |
| 117 UserDataManager::~UserDataManager() { |
| 118 } |
| 119 |
| 120 // static |
| 121 bool UserDataManager::GetProfileNameFromFolderName( |
| 122 const std::wstring& folder_name, |
| 123 std::wstring* profile_name) { |
| 124 // The folder name should start with a specific prefix for it to be a valid |
| 125 // profile folder. |
| 126 if (folder_name.find(chrome::kUserDataDirname) != 0) |
| 127 return false; |
| 128 |
| 129 // Seems like we cannot use arraysize macro for externally defined constants. |
| 130 // Is there a way? |
| 131 unsigned int prefix_length = wcslen(chrome::kUserDataDirname); |
| 132 // Subtract 1 from the size of the array for trailing null character. |
| 133 unsigned int separator_length = arraysize(kProfileFolderSeparator) - 1; |
| 134 |
| 135 // It's safe to use profile_name variable for intermediate values since we |
| 136 // will always return true now. |
| 137 *profile_name = folder_name.substr(prefix_length); |
| 138 // Remove leading separator if present. |
| 139 if (profile_name->find_first_of(kProfileFolderSeparator) == 0) |
| 140 *profile_name = profile_name->substr(separator_length); |
| 141 |
| 142 if (profile_name->empty()) |
| 143 *profile_name = chrome::kNotSignedInProfile; |
| 144 |
| 145 return true; |
| 146 } |
| 147 |
| 148 // static |
| 149 std::wstring UserDataManager::GetFolderNameFromProfileName( |
| 150 const std::wstring& profile_name) { |
| 151 std::wstring folder_name = chrome::kUserDataDirname; |
| 152 if (profile_name != chrome::kNotSignedInProfile) { |
| 153 folder_name += kProfileFolderSeparator; |
| 154 folder_name += profile_name; |
| 155 } |
| 156 return folder_name; |
| 157 } |
| 158 |
| 159 std::wstring UserDataManager::GetUserDataFolderForProfile( |
| 160 const std::wstring& profile_name) const { |
| 161 std::wstring folder_name = GetFolderNameFromProfileName(profile_name); |
| 162 std::wstring folder_path(user_data_root_); |
| 163 file_util::AppendToPath(&folder_path, folder_name); |
| 164 return folder_path; |
| 165 } |
| 166 |
| 167 std::wstring UserDataManager::GetCommandForProfile( |
| 168 const std::wstring& profile_name) const { |
| 169 std::wstring user_data_dir = GetUserDataFolderForProfile(profile_name); |
| 170 std::wstring command; |
| 171 PathService::Get(base::FILE_EXE, &command); |
| 172 CommandLine::AppendSwitchWithValue(&command, |
| 173 switches::kUserDataDir, |
| 174 user_data_dir); |
| 175 std::wstring local_state_path; |
| 176 PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path); |
| 177 CommandLine::AppendSwitchWithValue(&command, |
| 178 switches::kParentProfile, |
| 179 local_state_path); |
| 180 return command; |
| 181 } |
| 182 |
| 183 void UserDataManager::LaunchChromeForProfile( |
| 184 const std::wstring& profile_name) const { |
| 185 std::wstring command = GetCommandForProfile(profile_name); |
| 186 base::LaunchApp(command, false, false, NULL); |
| 187 } |
| 188 |
| 189 void UserDataManager::LaunchChromeForProfile(int index) const { |
| 190 // Helper deletes itself when done. |
| 191 LaunchChromeForProfileIndexHelper* helper = |
| 192 new LaunchChromeForProfileIndexHelper(this, index); |
| 193 helper->StartLaunch(); |
| 194 } |
| 195 |
| 196 void UserDataManager::GetProfiles(std::vector<std::wstring>* profiles) const { |
| 197 // This function should be called on the file thread. |
| 198 DCHECK(MessageLoop::current() == |
| 199 ChromeThread::GetMessageLoop(ChromeThread::FILE)); |
| 200 file_util::FileEnumerator file_enum(user_data_root_, |
| 201 false, |
| 202 file_util::FileEnumerator::DIRECTORIES); |
| 203 std::wstring folder_name; |
| 204 while (!(folder_name = file_enum.Next()).empty()) { |
| 205 folder_name = file_util::GetFilenameFromPath(folder_name); |
| 206 std::wstring profile_name; |
| 207 if (GetProfileNameFromFolderName(folder_name, &profile_name)) |
| 208 profiles->push_back(profile_name); |
| 209 } |
| 210 } |
| 211 |
| 212 bool UserDataManager::CreateDesktopShortcutForProfile( |
| 213 const std::wstring& profile_name) const { |
| 214 std::wstring exe_path; |
| 215 std::wstring shortcut_path; |
| 216 if (!PathService::Get(base::FILE_EXE, &exe_path) || |
| 217 !ShellUtil::GetDesktopPath(false, &shortcut_path)) |
| 218 return false; |
| 219 |
| 220 // Working directory. |
| 221 std::wstring exe_folder = file_util::GetDirectoryFromPath(exe_path); |
| 222 |
| 223 // Command and arguments. |
| 224 std::wstring cmd; |
| 225 cmd = StringPrintf(L"\"%ls\"", exe_path.c_str()); |
| 226 std::wstring user_data_dir = GetUserDataFolderForProfile(profile_name); |
| 227 std::wstring args = CommandLine::PrefixedSwitchStringWithValue( |
| 228 switches::kUserDataDir, |
| 229 user_data_dir); |
| 230 args = StringPrintf(L"\"%ls\"", args.c_str()); |
| 231 |
| 232 // Shortcut path. |
| 233 std::wstring shortcut_name = l10n_util::GetStringF( |
| 234 IDS_START_IN_PROFILE_SHORTCUT_NAME, |
| 235 profile_name); |
| 236 shortcut_name.append(L".lnk"); |
| 237 file_util::AppendToPath(&shortcut_path, shortcut_name); |
| 238 |
| 239 return file_util::CreateShortcutLink(cmd.c_str(), |
| 240 shortcut_path.c_str(), |
| 241 exe_folder.c_str(), |
| 242 args.c_str(), |
| 243 NULL, |
| 244 exe_path.c_str(), |
| 245 0); |
| 246 } |
| 247 |
| 248 GetProfilesHelper::GetProfilesHelper(Delegate* delegate) |
| 249 : delegate_(delegate) { |
| 250 } |
| 251 |
| 252 void GetProfilesHelper::GetProfiles(MessageLoop* target_loop) { |
| 253 // If the target loop is not NULL then use the target loop, or if it's NULL |
| 254 // then use the current message loop to post a task on it later when we are |
| 255 // done building a list of profiles. |
| 256 if (target_loop) { |
| 257 message_loop_ = target_loop; |
| 258 } else { |
| 259 message_loop_ = MessageLoop::current(); |
| 260 } |
| 261 DCHECK(message_loop_); |
| 262 MessageLoop* file_loop = ChromeThread::GetMessageLoop(ChromeThread::FILE); |
| 263 file_loop->PostTask( |
| 264 FROM_HERE, |
| 265 NewRunnableMethod(this, &GetProfilesHelper::GetProfilesFromManager)); |
| 266 } |
| 267 |
| 268 // Records that the delegate is closed. |
| 269 void GetProfilesHelper::OnDelegateDeleted() { |
| 270 delegate_ = NULL; |
| 271 } |
| 272 |
| 273 void GetProfilesHelper::GetProfilesFromManager() { |
| 274 // This function should be called on the file thread. |
| 275 DCHECK(MessageLoop::current() == |
| 276 ChromeThread::GetMessageLoop(ChromeThread::FILE)); |
| 277 |
| 278 // If the delegate is gone by now, no need to do any work. |
| 279 if (!delegate_) |
| 280 return; |
| 281 |
| 282 scoped_ptr<std::vector<std::wstring>> profiles(new std::vector<std::wstring>); |
| 283 UserDataManager::Get()->GetProfiles(profiles.get()); |
| 284 |
| 285 // Post a task on the original thread to call the delegate. |
| 286 message_loop_->PostTask( |
| 287 FROM_HERE, |
| 288 NewRunnableMethod(this, |
| 289 &GetProfilesHelper::InvokeDelegate, |
| 290 profiles.release())); |
| 291 } |
| 292 |
| 293 void GetProfilesHelper::InvokeDelegate(std::vector<std::wstring>* profiles) { |
| 294 scoped_ptr<std::vector<std::wstring>> udd_profiles(profiles); |
| 295 // If the delegate is gone by now, no need to do any work. |
| 296 if (delegate_) |
| 297 delegate_->OnGetProfilesDone(*udd_profiles.get()); |
| 298 } |
OLD | NEW |