user_manager.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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/chromeos/login/user_manager.h" 6 7#include "app/resource_bundle.h" 8#include "base/compiler_specific.h" 9#include "base/file_path.h" 10#include "base/file_util.h" 11#include "base/logging.h" 12#include "base/nss_util.h" 13#include "base/path_service.h" 14#include "base/string_util.h" 15#include "base/time.h" 16#include "base/utf_string_conversions.h" 17#include "base/values.h" 18#include "chrome/browser/browser_process.h" 19#include "chrome/browser/chrome_thread.h" 20#include "chrome/browser/chromeos/cros/cros_library.h" 21#include "chrome/browser/chromeos/cros/input_method_library.h" 22#include "chrome/browser/chromeos/login/ownership_service.h" 23#include "chrome/browser/chromeos/wm_ipc.h" 24#include "chrome/browser/prefs/pref_service.h" 25#include "chrome/common/chrome_paths.h" 26#include "chrome/common/notification_service.h" 27#include "chrome/common/notification_type.h" 28#include "gfx/codec/png_codec.h" 29#include "grit/theme_resources.h" 30 31namespace chromeos { 32 33namespace { 34 35// A vector pref of the users who have logged into the device. 36const char kLoggedInUsers[] = "LoggedInUsers"; 37// A dictionary that maps usernames to file paths to their images. 38const char kUserImages[] = "UserImages"; 39 40// Incognito user is represented by an empty string (since some code already 41// depends on that and it's hard to figure out what). 42const char kIncognitoUser[] = ""; 43 44// The one true UserManager. 45static UserManager* user_manager_ = NULL; 46 47// Stores path to the image in local state. Runs on UI thread. 48void save_path_to_local_state(const std::string& username, 49 const std::string& image_path) { 50 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 51 PrefService* local_state = g_browser_process->local_state(); 52 DictionaryValue* images = 53 local_state->GetMutableDictionary(kUserImages); 54 images->SetWithoutPathExpansion(username, new StringValue(image_path)); 55 LOG(INFO) << "Saving path to user image in Local State."; 56 local_state->SavePersistentPrefs(); 57} 58 59// Saves image to file with specified path. Runs on FILE thread. 60// Posts task for saving image path to local state on UI thread. 61void save_image_to_file(const SkBitmap& image, 62 const FilePath& image_path, 63 const std::string& username) { 64 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 65 std::vector<unsigned char> encoded_image; 66 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, true, &encoded_image)) { 67 LOG(ERROR) << "Failed to PNG encode the image."; 68 return; 69 } 70 71 if (file_util::WriteFile(image_path, 72 reinterpret_cast<char*>(&encoded_image[0]), 73 encoded_image.size()) == -1) { 74 LOG(ERROR) << "Failed to save image to file."; 75 return; 76 } 77 78 ChromeThread::PostTask( 79 ChromeThread::UI, 80 FROM_HERE, 81 NewRunnableFunction(&save_path_to_local_state, 82 username, image_path.value())); 83} 84 85// Checks current user's ownership on file thread. 86void CheckOwnership() { 87 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); 88 89 UserManager::Get()->set_current_user_is_owner( 90 OwnershipService::GetSharedInstance()->CurrentUserIsOwner()); 91} 92 93} // namespace 94 95UserManager::User::User() { 96 image_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed( 97 IDR_LOGIN_DEFAULT_USER); 98} 99 100std::string UserManager::User::GetDisplayName() const { 101 size_t i = email_.find('@'); 102 if (i == 0 || i == std::string::npos) { 103 return email_; 104 } 105 return email_.substr(0, i); 106} 107 108// static 109UserManager* UserManager::Get() { 110 if (!user_manager_) 111 user_manager_ = new UserManager(); 112 return user_manager_; 113} 114 115// static 116void UserManager::RegisterPrefs(PrefService* local_state) { 117 local_state->RegisterListPref(kLoggedInUsers); 118 local_state->RegisterDictionaryPref(kUserImages); 119} 120 121std::vector<UserManager::User> UserManager::GetUsers() const { 122 std::vector<User> users; 123 if (!g_browser_process) 124 return users; 125 126 PrefService* local_state = g_browser_process->local_state(); 127 const ListValue* prefs_users = local_state->GetList(kLoggedInUsers); 128 const DictionaryValue* prefs_images = 129 local_state->GetDictionary(kUserImages); 130 131 if (prefs_users) { 132 for (ListValue::const_iterator it = prefs_users->begin(); 133 it < prefs_users->end(); 134 ++it) { 135 std::string email; 136 if ((*it)->GetAsString(&email)) { 137 User user; 138 user.set_email(email); 139 UserImages::const_iterator image_it = user_images_.find(email); 140 std::string image_path; 141 if (image_it == user_images_.end()) { 142 if (prefs_images && 143 prefs_images->GetStringWithoutPathExpansion(email, &image_path)) { 144 // Insert the default image so we don't send another request if 145 // GetUsers is called twice. 146 user_images_[email] = user.image(); 147 image_loader_->Start(email, image_path); 148 } 149 } else { 150 user.set_image(image_it->second); 151 } 152 users.push_back(user); 153 } 154 } 155 } 156 return users; 157} 158 159void UserManager::OffTheRecordUserLoggedIn() { 160 logged_in_user_ = User(); 161 logged_in_user_.set_email(kIncognitoUser); 162 NotifyOnLogin(); 163} 164 165void UserManager::UserLoggedIn(const std::string& email) { 166 if (email == kIncognitoUser) { 167 OffTheRecordUserLoggedIn(); 168 return; 169 } 170 171 // Get a copy of the current users. 172 std::vector<User> users = GetUsers(); 173 174 // Clear the prefs view of the users. 175 PrefService* prefs = g_browser_process->local_state(); 176 ListValue* prefs_users = prefs->GetMutableList(kLoggedInUsers); 177 prefs_users->Clear(); 178 179 logged_in_user_.set_email(email); 180 181 // Make sure this user is first. 182 prefs_users->Append(Value::CreateStringValue(email)); 183 for (std::vector<User>::iterator it = users.begin(); 184 it < users.end(); 185 ++it) { 186 std::string user_email = it->email(); 187 // Skip the most recent user. 188 if (email != user_email) { 189 prefs_users->Append(Value::CreateStringValue(user_email)); 190 } else { 191 logged_in_user_ = *it; 192 } 193 } 194 prefs->SavePersistentPrefs(); 195 NotifyOnLogin(); 196} 197 198void UserManager::RemoveUser(const std::string& email) { 199 // Get a copy of the current users. 200 std::vector<User> users = GetUsers(); 201 202 // Clear the prefs view of the users. 203 PrefService* prefs = g_browser_process->local_state(); 204 ListValue* prefs_users = prefs->GetMutableList(kLoggedInUsers); 205 prefs_users->Clear(); 206 207 for (std::vector<User>::iterator it = users.begin(); 208 it < users.end(); 209 ++it) { 210 std::string user_email = it->email(); 211 // Skip user that we would like to delete. 212 if (email != user_email) 213 prefs_users->Append(Value::CreateStringValue(user_email)); 214 } 215 prefs->SavePersistentPrefs(); 216} 217 218bool UserManager::IsKnownUser(const std::string& email) { 219 std::vector<User> users = GetUsers(); 220 for (std::vector<User>::iterator it = users.begin(); 221 it < users.end(); 222 ++it) { 223 if (it->email() == email) 224 return true; 225 } 226 227 return false; 228} 229 230void UserManager::SetLoggedInUserImage(const SkBitmap& image) { 231 if (logged_in_user_.email().empty()) 232 return; 233 logged_in_user_.set_image(image); 234 OnImageLoaded(logged_in_user_.email(), image); 235} 236 237void UserManager::SaveUserImage(const std::string& username, 238 const SkBitmap& image) { 239 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 240 std::string filename = username + ".png"; 241 FilePath user_data_dir; 242 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 243 FilePath image_path = user_data_dir.AppendASCII(filename); 244 LOG(INFO) << "Saving user image to " << image_path.value(); 245 246 ChromeThread::PostTask( 247 ChromeThread::FILE, 248 FROM_HERE, 249 NewRunnableFunction(&save_image_to_file, 250 image, image_path, username)); 251} 252 253void UserManager::OnImageLoaded(const std::string& username, 254 const SkBitmap& image) { 255 LOG(INFO) << "Loaded image for " << username; 256 user_images_[username] = image; 257 User user; 258 user.set_email(username); 259 user.set_image(image); 260 NotificationService::current()->Notify( 261 NotificationType::LOGIN_USER_IMAGE_CHANGED, 262 Source<UserManager>(this), 263 Details<const User>(&user)); 264} 265 266// Private constructor and destructor. Do nothing. 267UserManager::UserManager() 268 : ALLOW_THIS_IN_INITIALIZER_LIST(image_loader_(new UserImageLoader(this))), 269 current_user_is_owner_(false) { 270 registrar_.Add(this, NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED, 271 NotificationService::AllSources()); 272} 273 274UserManager::~UserManager() { 275 image_loader_->set_delegate(NULL); 276} 277 278void UserManager::NotifyOnLogin() { 279 NotificationService::current()->Notify( 280 NotificationType::LOGIN_USER_CHANGED, 281 Source<UserManager>(this), 282 Details<const User>(&logged_in_user_)); 283 284 chromeos::CrosLibrary::Get()->GetInputMethodLibrary()-> 285 SetDeferImeStartup(false); 286 // Shut down the IME so that it will reload the user's settings. 287 chromeos::CrosLibrary::Get()->GetInputMethodLibrary()-> 288 StopInputMethodProcesses(); 289 // Let the window manager know that we're logged in now. 290 WmIpc::instance()->SetLoggedInProperty(true); 291 // Ensure we've opened the real user's key/certificate database. 292 base::OpenPersistentNSSDB(); 293 294 // Schedules current user ownership check on file thread. 295 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, 296 NewRunnableFunction(&CheckOwnership)); 297} 298 299void UserManager::Observe(NotificationType type, 300 const NotificationSource& source, 301 const NotificationDetails& details) { 302 if (type == NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED) { 303 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, 304 NewRunnableFunction(&CheckOwnership)); 305 } 306} 307 308} // namespace chromeos 309