Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2033)

Unified Diff: chrome/browser/chromeos/login/user_manager_impl.cc

Issue 11419184: Add public accounts to UserManager (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Quickly fix comment in typo before anyone notices... Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/login/user_manager_impl.cc
diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc
index 14882c0688b8835c871a5ca38420c6e5a69598a6..f539da6c44ccfa4fdd0c48f9ad3296ed22801f2c 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_manager_impl.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/chromeos/login/user_manager_impl.h"
+#include <cstddef>
+
#include "ash/shell.h"
#include "base/bind.h"
#include "base/chromeos/chromeos_version.h"
@@ -23,7 +25,6 @@
#include "chrome/browser/chromeos/login/remove_user_delegate.h"
#include "chrome/browser/chromeos/login/user_image_manager_impl.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
@@ -44,8 +45,15 @@ namespace chromeos {
namespace {
-// A vector pref of the users who have logged into the device.
-const char kLoggedInUsers[] = "LoggedInUsers";
+// A vector pref of the regular users who have logged into this device.
+const char kRegularUsers[] = "LoggedInUsers";
Ivan Korotkov 2012/11/28 21:40:53 I'm very concerned about splitting users into seve
Nikita (slow) 2012/11/29 12:00:50 I agree with Ivan. We should have single LoggedInU
Ivan Korotkov 2012/11/29 12:06:31 As discussed over chat, this CL actually adds supp
bartfab (slow) 2012/11/29 14:18:09 I renamed |LocalUsers| to |PublicAccounts|. I left
+
+// A vector pref of the device-local users defined on this device.
+const char kLocalUsers[] = "LocalUsers";
+
+// A string pref that gets set when a device-local user is to be removed but is
+// currently logged in, requiring the user's data to be removed after logout.
+const char kUserPendingDataRemoval[] = "UserPendingDataRemoval";
// A dictionary that maps usernames to the displayed name.
const char kUserDisplayName[] = "UserDisplayName";
@@ -101,7 +109,10 @@ void RemoveUserInternal(const std::string& user_email,
// static
void UserManager::RegisterPrefs(PrefService* local_state) {
- local_state->RegisterListPref(kLoggedInUsers, PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterListPref(kRegularUsers, PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterListPref(kLocalUsers, PrefService::UNSYNCABLE_PREF);
+ local_state->RegisterStringPref(kUserPendingDataRemoval, "",
+ PrefService::UNSYNCABLE_PREF);
local_state->RegisterDictionaryPref(kUserOAuthTokenStatus,
PrefService::UNSYNCABLE_PREF);
local_state->RegisterDictionaryPref(kUserDisplayName,
@@ -111,7 +122,9 @@ void UserManager::RegisterPrefs(PrefService* local_state) {
}
UserManagerImpl::UserManagerImpl()
- : logged_in_user_(NULL),
+ : cros_settings_(CrosSettings::Get()),
+ users_loaded_(false),
+ logged_in_user_(NULL),
session_started_(false),
is_current_user_owner_(false),
is_current_user_new_(false),
@@ -137,12 +150,18 @@ UserManagerImpl::~UserManagerImpl() {
delete logged_in_user_;
}
+void UserManagerImpl::Shutdown() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ cros_settings_->RemoveSettingsObserver(kAccountsPrefDeviceLocalAccounts,
+ this);
+}
+
UserImageManager* UserManagerImpl::GetUserImageManager() {
return user_image_manager_.get();
}
const UserList& UserManagerImpl::GetUsers() const {
- const_cast<UserManagerImpl*>(this)->EnsureUsersLoaded();
+ EnsureUsersLoaded();
return users_;
}
@@ -168,35 +187,19 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
EnsureUsersLoaded();
- // Clear the prefs view of the users.
- PrefService* prefs = g_browser_process->local_state();
- ListPrefUpdate prefs_users_update(prefs, kLoggedInUsers);
- prefs_users_update->Clear();
+ // Remove the user from the user list.
+ logged_in_user_ = RemoveUserFromListInternal(email);
- // Make sure this user is first.
- prefs_users_update->Append(new base::StringValue(email));
- UserList::iterator logged_in_user = users_.end();
- for (UserList::iterator it = users_.begin(); it != users_.end(); ++it) {
- std::string user_email = (*it)->email();
- // Skip the most recent user.
- if (email != user_email)
- prefs_users_update->Append(new base::StringValue(user_email));
- else
- logged_in_user = it;
- }
+ // Add the user to the front of the persistent user list.
+ ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
+ kRegularUsers);
+ prefs_users_update->Insert(0, new base::StringValue(email));
- if (logged_in_user == users_.end()) {
+ // If the user was not found on the user list, create a new user.
+ if (!logged_in_user_) {
is_current_user_new_ = true;
logged_in_user_ = User::CreateRegularUser(email);
logged_in_user_->set_oauth_token_status(LoadUserOAuthStatus(email));
- } else {
- logged_in_user_ = *logged_in_user;
- users_.erase(logged_in_user);
- }
- // This user must be in the front of the user list.
- users_.insert(users_.begin(), logged_in_user_);
-
- if (is_current_user_new_) {
SaveUserDisplayName(logged_in_user_->email(),
UTF8ToUTF16(logged_in_user_->GetAccountName(true)));
WallpaperManager::Get()->SetInitialUserWallpaper(email, true);
@@ -209,9 +212,6 @@ void UserManagerImpl::UserLoggedIn(const std::string& email,
WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
}
Ivan Korotkov 2012/11/28 21:40:53 Why are you removing this bit?
Nikita (slow) 2012/11/29 12:00:50 To give more context: this call ensures that if si
bartfab (slow) 2012/11/29 14:18:09 I removed this at Julian's request. The local stat
Ivan Korotkov 2012/11/29 17:25:33 Right, but if browser crashes in the first few sec
bartfab (slow) 2012/11/29 18:56:17 Done.
- // Make sure we persist new user data to Local State.
- prefs->CommitPendingWrite();
-
NotifyOnLogin();
}
@@ -252,17 +252,14 @@ void UserManagerImpl::SessionStarted() {
chrome::NOTIFICATION_SESSION_STARTED,
content::NotificationService::AllSources(),
content::NotificationService::NoDetails());
- if (is_current_user_new_) {
- // Make sure we persist new user data to Local State.
Ivan Korotkov 2012/11/28 21:40:53 And this one.
Nikita (slow) 2012/11/29 12:00:50 Same here: ensures that new user avatar is saved i
bartfab (slow) 2012/11/29 14:18:09 Same as above.
bartfab (slow) 2012/11/29 18:56:17 Done.
- g_browser_process->local_state()->CommitPendingWrite();
- }
}
void UserManagerImpl::RemoveUser(const std::string& email,
RemoveUserDelegate* delegate) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!IsKnownUser(email))
+ const User* user = FindUser(email);
+ if (!user || user->GetType() != User::USER_TYPE_REGULAR)
return;
// Sanity check: we must not remove single user. This check may seem
@@ -283,7 +280,8 @@ void UserManagerImpl::RemoveUser(const std::string& email,
void UserManagerImpl::RemoveUserFromList(const std::string& email) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
EnsureUsersLoaded();
- RemoveUserFromListInternal(email);
+ RemoveNonCryptohomeData(email);
+ delete RemoveUserFromListInternal(email);
}
bool UserManagerImpl::IsKnownUser(const std::string& email) const {
@@ -429,13 +427,18 @@ void UserManagerImpl::Observe(int type,
}
}
break;
+ case chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED:
+ DCHECK_EQ(*content::Details<const std::string>(details).ptr(),
+ kAccountsPrefDeviceLocalAccounts);
+ RetrieveTrustedDevicePolicies();
+ break;
default:
NOTREACHED();
}
}
void UserManagerImpl::OnStateChanged() {
- DCHECK(IsUserLoggedIn() && !IsLoggedInAsGuest());
+ DCHECK(IsLoggedInAsRegularUser());
GoogleServiceAuthError::State state =
observed_sync_service_->GetAuthError().state();
if (state != GoogleServiceAuthError::NONE &&
@@ -484,6 +487,12 @@ bool UserManagerImpl::IsUserLoggedIn() const {
return logged_in_user_;
}
+bool UserManagerImpl::IsLoggedInAsRegularUser() const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return IsUserLoggedIn() &&
+ logged_in_user_->GetType() == User::USER_TYPE_REGULAR;
+}
+
bool UserManagerImpl::IsLoggedInAsDemoUser() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return IsUserLoggedIn() &&
@@ -551,48 +560,89 @@ void UserManagerImpl::NotifyLocalStateChanged() {
LocalStateChanged(this));
}
-void UserManagerImpl::EnsureUsersLoaded() {
+bool UserManagerImpl::ParseUserList(
Ivan Korotkov 2012/11/28 21:40:53 Since this is a utility method that has nothing to
bartfab (slow) 2012/11/29 14:18:09 Done.
+ const ListValue& users_list,
+ const std::set<std::string>& existing_users,
+ const std::string& logged_in_user,
+ std::vector<std::string>* users_vector,
+ std::set<std::string>* users_set) const {
+ users_vector->clear();
+ users_set->clear();
+ bool logged_in_user_on_list = false;
+ for (size_t i = 0; i < users_list.GetSize(); ++i) {
+ std::string email;
+ if (!users_list.GetString(i, &email) || email.empty()) {
+ LOG(ERROR) << "Corrupt entry in user list at index " << i << ".";
+ continue;
+ }
+ if (existing_users.find(email) != existing_users.end() ||
+ !users_set->insert(email).second) {
+ LOG(ERROR) << "Duplicate user: " << email;
+ continue;
+ }
+ if (email == logged_in_user) {
+ logged_in_user_on_list = true;
+ continue;
+ }
+ users_vector->push_back(email);
+ }
+ users_set->erase(logged_in_user);
+ return logged_in_user_on_list;
+}
+
+void UserManagerImpl::EnsureUsersLoaded() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!users_.empty())
- return;
if (!g_browser_process)
return;
+ if (users_loaded_)
+ return;
+ users_loaded_ = true;
+
PrefService* local_state = g_browser_process->local_state();
- const ListValue* prefs_users =
- local_state->GetList(kLoggedInUsers);
+ const ListValue* prefs_regular_users = local_state->GetList(kRegularUsers);
+ const ListValue* prefs_local_users = local_state->GetList(kLocalUsers);
const DictionaryValue* prefs_display_names =
local_state->GetDictionary(kUserDisplayName);
const DictionaryValue* prefs_display_emails =
local_state->GetDictionary(kUserDisplayEmail);
- if (!prefs_users)
- return;
-
- for (ListValue::const_iterator it = prefs_users->begin();
- it != prefs_users->end(); ++it) {
- std::string email;
- if ((*it)->GetAsString(&email)) {
- User* user = User::CreateRegularUser(email);
- user->set_oauth_token_status(LoadUserOAuthStatus(email));
- users_.push_back(user);
-
- string16 display_name;
- if (prefs_display_names &&
- prefs_display_names->GetStringWithoutPathExpansion(
- email, &display_name)) {
- user->set_display_name(display_name);
- }
+ // Load regular users.
+ std::vector<std::string> regular_users;
+ std::set<std::string> regular_users_set;
+ ParseUserList(*prefs_regular_users, std::set<std::string>(), "",
+ &regular_users, &regular_users_set);
+ for (std::vector<std::string>::const_iterator it = regular_users.begin();
+ it != regular_users.end(); ++it) {
+ User* user = User::CreateRegularUser(*it);
+ user->set_oauth_token_status(LoadUserOAuthStatus(*it));
+ users_.push_back(user);
+
+ string16 display_name;
+ if (prefs_display_names->GetStringWithoutPathExpansion(*it,
+ &display_name)) {
+ user->set_display_name(display_name);
+ }
- std::string display_email;
- if (prefs_display_emails &&
- prefs_display_emails->GetStringWithoutPathExpansion(
- email, &display_email)) {
- user->set_display_email(display_email);
- }
+ std::string display_email;
+ if (prefs_display_emails->GetStringWithoutPathExpansion(*it,
+ &display_email)) {
+ user->set_display_email(display_email);
}
}
+ // Load device-local users.
+ std::vector<std::string> local_users;
+ std::set<std::string> local_users_set;
+ ParseUserList(*prefs_local_users,regular_users_set, "",
+ &local_users, &local_users_set);
+ for (std::vector<std::string>::const_iterator it = local_users.begin();
+ it != local_users.end(); ++it) {
+ // Currently, all device-local users are public account users. This may
+ // change in the future.
+ users_.push_back(User::CreatePublicAccountUser(*it));
Ivan Korotkov 2012/11/28 21:40:53 Maybe CreateGaiaAccountUser? Public sounds somewha
bartfab (slow) 2012/11/29 14:18:09 As discussed offline, public accounts are non-GAIA
+ }
+
user_image_manager_->LoadUserImages(users_);
}
@@ -600,42 +650,50 @@ void UserManagerImpl::RetrieveTrustedDevicePolicies() {
ephemeral_users_enabled_ = false;
owner_email_ = "";
- CrosSettings* cros_settings = CrosSettings::Get();
// Schedule a callback if device policy has not yet been verified.
- if (CrosSettingsProvider::TRUSTED != cros_settings->PrepareTrustedValues(
+ if (CrosSettingsProvider::TRUSTED != cros_settings_->PrepareTrustedValues(
base::Bind(&UserManagerImpl::RetrieveTrustedDevicePolicies,
base::Unretained(this)))) {
return;
}
- cros_settings->GetBoolean(kAccountsPrefEphemeralUsersEnabled,
- &ephemeral_users_enabled_);
- cros_settings->GetString(kDeviceOwner, &owner_email_);
+ cros_settings_->GetBoolean(kAccountsPrefEphemeralUsersEnabled,
+ &ephemeral_users_enabled_);
+ cros_settings_->GetString(kDeviceOwner, &owner_email_);
+ const base::ListValue* local_users;
+ cros_settings_->GetList(kAccountsPrefDeviceLocalAccounts, &local_users);
+
+ EnsureUsersLoaded();
+
+ bool changed = UpdateLocalUsers(*local_users);
// If ephemeral users are enabled and we are on the login screen, take this
// opportunity to clean up by removing all users except the owner.
if (ephemeral_users_enabled_ && !IsUserLoggedIn()) {
scoped_ptr<base::ListValue> users(
- g_browser_process->local_state()->GetList(kLoggedInUsers)->DeepCopy());
+ g_browser_process->local_state()->GetList(kRegularUsers)->DeepCopy());
- bool changed = false;
for (base::ListValue::const_iterator user = users->begin();
user != users->end(); ++user) {
std::string user_email;
(*user)->GetAsString(&user_email);
if (user_email != owner_email_) {
- RemoveUserFromListInternal(user_email);
+ RemoveNonCryptohomeData(user_email);
+ delete RemoveUserFromListInternal(user_email);
changed = true;
}
}
+ }
- if (changed) {
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_POLICY_USER_LIST_CHANGED,
- content::Source<UserManager>(this),
- content::NotificationService::NoDetails());
- }
+ if (changed) {
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_POLICY_USER_LIST_CHANGED,
+ content::Source<UserManager>(this),
+ content::NotificationService::NoDetails());
}
+
+ cros_settings_->AddSettingsObserver(kAccountsPrefDeviceLocalAccounts,
+ this);
}
bool UserManagerImpl::AreEphemeralUsersEnabled() const {
@@ -681,24 +739,11 @@ void UserManagerImpl::CheckOwnership() {
base::Unretained(this)));
}
-void UserManagerImpl::RemoveUserFromListInternal(const std::string& email) {
- // Clear the prefs view of the users.
- PrefService* prefs = g_browser_process->local_state();
- ListPrefUpdate prefs_users_update(prefs, kLoggedInUsers);
- prefs_users_update->Clear();
-
- UserList::iterator user_to_remove = users_.end();
- for (UserList::iterator it = users_.begin(); it != users_.end(); ++it) {
- std::string user_email = (*it)->email();
- // Skip user that we would like to delete.
- if (email != user_email)
- prefs_users_update->Append(new base::StringValue(user_email));
- else
- user_to_remove = it;
- }
-
+void UserManagerImpl::RemoveNonCryptohomeData(const std::string& email) {
WallpaperManager::Get()->RemoveUserWallpaperInfo(email);
+ user_image_manager_->DeleteUserImage(email);
+ PrefService* prefs = g_browser_process->local_state();
DictionaryPrefUpdate prefs_oauth_update(prefs, kUserOAuthTokenStatus);
int oauth_status;
prefs_oauth_update->GetIntegerWithoutPathExpansion(email, &oauth_status);
@@ -709,11 +754,110 @@ void UserManagerImpl::RemoveUserFromListInternal(const std::string& email) {
DictionaryPrefUpdate prefs_display_email_update(prefs, kUserDisplayEmail);
prefs_display_email_update->RemoveWithoutPathExpansion(email, NULL);
+}
- if (user_to_remove != users_.end()) {
- delete *user_to_remove;
- users_.erase(user_to_remove);
+User *UserManagerImpl::RemoveUserFromListInternal(const std::string& email) {
Ivan Korotkov 2012/11/28 21:40:53 This looks like it really is RemoveRegularUser...?
bartfab (slow) 2012/11/29 14:18:09 Done. Though note that the method will handle othe
+ ListPrefUpdate prefs_users_update(g_browser_process->local_state(),
+ kRegularUsers);
+ prefs_users_update->Clear();
+ User* user = NULL;
+ for (UserList::iterator it = users_.begin(); it != users_.end(); ) {
+ const std::string user_email = (*it)->email();
+ if (user_email == email) {
+ user = *it;
+ it = users_.erase(it);
+ } else {
+ if ((*it)->GetType() == User::USER_TYPE_REGULAR)
+ prefs_users_update->Append(new base::StringValue(user_email));
+ ++it;
+ }
}
+ return user;
+}
+
+bool UserManagerImpl::UpdateLocalUsers(
+ const base::ListValue& local_users_list) {
+ PrefService* local_state = g_browser_process->local_state();
+
+ // Determine the currently logged-in user's email.
+ std::string logged_in_user;
Nikita (slow) 2012/11/29 16:42:50 Please rename to logged_in_user_email so that you
bartfab (slow) 2012/11/29 18:56:17 Done.
+ if (IsUserLoggedIn())
+ logged_in_user = GetLoggedInUser()->email();
+
+ // If there is a user whose data is pending removal and that user is not
+ // currently logged in, take this opportunity to remove the data.
+ std::string user_pending_data_removal =
+ local_state->GetString(kUserPendingDataRemoval);
+ if (!user_pending_data_removal.empty() &&
+ user_pending_data_removal != logged_in_user) {
+ RemoveNonCryptohomeData(user_pending_data_removal);
+ local_state->ClearPref(kUserPendingDataRemoval);
+ }
+
+ // Split the current user list into device-local users and regular users.
+ std::vector<std::string> old_local_users;
+ std::set<std::string> regular_users;
+ for (UserList::const_iterator it = users_.begin(); it != users_.end(); ++it) {
+ if ((*it)->is_device_local_account())
+ old_local_users.push_back((*it)->email());
+ else
+ regular_users.insert((*it)->email());
+ }
+
+ // Get the new list of device-local users from policy.
+ std::vector<std::string> new_local_users;
+ std::set<std::string> new_local_users_set;
+ std::string pending_remove;
+ if (!ParseUserList(local_users_list, regular_users, logged_in_user,
+ &new_local_users, &new_local_users_set) &&
+ IsUserLoggedIn()) {
+ User* user = GetLoggedInUser();
+ // If the currently logged-in user is a device-local user not found on the
+ // new list, mark that user's data as pending removal after logout.
+ if (user->is_device_local_account() && !user->is_builtin_account())
+ local_state->SetString(kUserPendingDataRemoval, logged_in_user);
+ }
+
+ // Persist the new list of device-local users in a pref.
+ ListPrefUpdate prefs_local_users_update(local_state, kLocalUsers);
+ scoped_ptr<base::ListValue> prefs_local_users(local_users_list.DeepCopy());
+ prefs_local_users_update->Swap(prefs_local_users.get());
+
+ // If the list of device-local users has not changed, return.
+ if (new_local_users.size() == old_local_users.size()) {
+ bool changed = false;
+ for (size_t i = 0; i < new_local_users.size(); ++i) {
+ if (new_local_users[i] != old_local_users[i]) {
+ changed = true;
+ break;
+ }
+ }
+ if (!changed)
+ return false;
+ }
+
+ // Remove the old device-local users from the user list.
+ for (UserList::iterator it = users_.begin(); it != users_.end(); ) {
+ if ((*it)->is_device_local_account()) {
+ delete *it;
+ it = users_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Add the new device-local users to the user list.
+ for (std::vector<std::string>::const_iterator it = new_local_users.begin();
+ it != new_local_users.end(); ++it) {
+ // Currently, all device-local users are public account users. This may
+ // change in the future.
+ users_.push_back(User::CreatePublicAccountUser(*it));
+ }
+
+ user_image_manager_->LoadUserImages(
+ UserList(users_.end() - new_local_users.size(), users_.end()));
+
+ return true;
}
} // namespace chromeos

Powered by Google App Engine
This is Rietveld 408576698