1 // Copyright (c) 2013 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.
5 #include "chrome/browser/chromeos/login/user_manager_impl.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 #include "base/files/file_path.h"
15 #include "base/logging.h"
16 #include "base/metrics/histogram.h"
17 #include "base/prefs/pref_registry_simple.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/prefs/scoped_user_pref_update.h"
20 #include "base/rand_util.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/sys_info.h"
25 #include "base/threading/worker_pool.h"
26 #include "base/values.h"
27 #include "chrome/browser/app_mode/app_mode_utils.h"
28 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/chrome_notification_types.h"
30 #include "chrome/browser/chromeos/base/locale_util.h"
31 #include "chrome/browser/chromeos/login/auth_sync_observer.h"
32 #include "chrome/browser/chromeos/login/auth_sync_observer_factory.h"
33 #include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h"
34 #include "chrome/browser/chromeos/login/login_display.h"
35 #include "chrome/browser/chromeos/login/login_utils.h"
36 #include "chrome/browser/chromeos/login/multi_profile_first_run_notification.h"
37 #include "chrome/browser/chromeos/login/multi_profile_user_controller.h"
38 #include "chrome/browser/chromeos/login/remove_user_delegate.h"
39 #include "chrome/browser/chromeos/login/supervised_user_manager_impl.h"
40 #include "chrome/browser/chromeos/login/user_image_manager_impl.h"
41 #include "chrome/browser/chromeos/login/wizard_controller.h"
42 #include "chrome/browser/chromeos/policy/device_local_account.h"
43 #include "chrome/browser/chromeos/profiles/profile_helper.h"
44 #include "chrome/browser/chromeos/session_length_limiter.h"
45 #include "chrome/browser/lifetime/application_lifetime.h"
46 #include "chrome/browser/policy/browser_policy_connector.h"
47 #include "chrome/browser/profiles/profile.h"
48 #include "chrome/browser/profiles/profile_manager.h"
49 #include "chrome/browser/sync/profile_sync_service.h"
50 #include "chrome/browser/sync/profile_sync_service_factory.h"
51 #include "chrome/common/chrome_constants.h"
52 #include "chrome/common/chrome_switches.h"
53 #include "chrome/common/pref_names.h"
54 #include "chromeos/chromeos_switches.h"
55 #include "chromeos/cryptohome/async_method_caller.h"
56 #include "chromeos/dbus/dbus_thread_manager.h"
57 #include "chromeos/login/login_state.h"
58 #include "chromeos/settings/cros_settings_names.h"
59 #include "content/public/browser/browser_thread.h"
60 #include "content/public/browser/notification_service.h"
61 #include "google_apis/gaia/gaia_auth_util.h"
62 #include "google_apis/gaia/google_service_auth_error.h"
63 #include "policy/policy_constants.h"
64 #include "ui/base/l10n/l10n_util.h"
65 #include "ui/views/corewm/corewm_switches.h"
67 using content::BrowserThread
;
72 // A vector pref of the the regular users known on this device, arranged in LRU
74 const char kRegularUsers
[] = "LoggedInUsers";
76 // A vector pref of the public accounts defined on this device.
77 const char kPublicAccounts
[] = "PublicAccounts";
79 // A string pref that gets set when a public account is removed but a user is
80 // currently logged into that account, requiring the account's data to be
81 // removed after logout.
82 const char kPublicAccountPendingDataRemoval
[] =
83 "PublicAccountPendingDataRemoval";
85 // A dictionary that maps usernames to the displayed name.
86 const char kUserDisplayName
[] = "UserDisplayName";
88 // A dictionary that maps usernames to the user's given name.
89 const char kUserGivenName
[] = "UserGivenName";
91 // A dictionary that maps usernames to the displayed (non-canonical) emails.
92 const char kUserDisplayEmail
[] = "UserDisplayEmail";
94 // A dictionary that maps usernames to OAuth token presence flag.
95 const char kUserOAuthTokenStatus
[] = "OAuthTokenStatus";
97 // A string pref containing the ID of the last user who logged in if it was
98 // a regular user or an empty string if it was another type of user (guest,
99 // kiosk, public account, etc.).
100 const char kLastLoggedInRegularUser
[] = "LastLoggedInRegularUser";
102 // Upper bound for a histogram metric reporting the amount of time between
103 // one regular user logging out and a different regular user logging in.
104 const int kLogoutToLoginDelayMaxSec
= 1800;
106 // Callback that is called after user removal is complete.
107 void OnRemoveUserComplete(const std::string
& user_email
,
109 cryptohome::MountError return_code
) {
110 // Log the error, but there's not much we can do.
112 LOG(ERROR
) << "Removal of cryptohome for " << user_email
113 << " failed, return code: " << return_code
;
117 // Helper function that copies users from |users_list| to |users_vector| and
118 // |users_set|. Duplicates and users already present in |existing_users| are
120 void ParseUserList(const ListValue
& users_list
,
121 const std::set
<std::string
>& existing_users
,
122 std::vector
<std::string
>* users_vector
,
123 std::set
<std::string
>* users_set
) {
124 users_vector
->clear();
126 for (size_t i
= 0; i
< users_list
.GetSize(); ++i
) {
128 if (!users_list
.GetString(i
, &email
) || email
.empty()) {
129 LOG(ERROR
) << "Corrupt entry in user list at index " << i
<< ".";
132 if (existing_users
.find(email
) != existing_users
.end() ||
133 !users_set
->insert(email
).second
) {
134 LOG(ERROR
) << "Duplicate user: " << email
;
137 users_vector
->push_back(email
);
141 class UserHashMatcher
{
143 explicit UserHashMatcher(const std::string
& h
) : username_hash(h
) {}
144 bool operator()(const User
* user
) const {
145 return user
->username_hash() == username_hash
;
149 const std::string
& username_hash
;
152 // Runs on SequencedWorkerPool thread. Passes resolved locale to
153 // |on_resolve_callback| on UI thread.
155 const std::string
& raw_locale
,
156 base::Callback
<void(const std::string
&)> on_resolve_callback
) {
157 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI
));
158 std::string resolved_locale
;
160 l10n_util::CheckAndResolveLocale(raw_locale
, &resolved_locale
);
161 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
162 base::Bind(on_resolve_callback
, resolved_locale
));
168 void UserManager::RegisterPrefs(PrefRegistrySimple
* registry
) {
169 registry
->RegisterListPref(kRegularUsers
);
170 registry
->RegisterListPref(kPublicAccounts
);
171 registry
->RegisterStringPref(kPublicAccountPendingDataRemoval
, "");
172 registry
->RegisterStringPref(kLastLoggedInRegularUser
, "");
173 registry
->RegisterDictionaryPref(kUserOAuthTokenStatus
);
174 registry
->RegisterDictionaryPref(kUserDisplayName
);
175 registry
->RegisterDictionaryPref(kUserGivenName
);
176 registry
->RegisterDictionaryPref(kUserDisplayEmail
);
177 SupervisedUserManager::RegisterPrefs(registry
);
178 SessionLengthLimiter::RegisterPrefs(registry
);
181 UserManagerImpl::UserManagerImpl()
182 : cros_settings_(CrosSettings::Get()),
183 device_local_account_policy_service_(NULL
),
184 user_loading_stage_(STAGE_NOT_LOADED
),
187 session_started_(false),
188 user_sessions_restored_(false),
189 is_current_user_owner_(false),
190 is_current_user_new_(false),
191 is_current_user_ephemeral_regular_user_(false),
192 ephemeral_users_enabled_(false),
193 user_image_manager_(new UserImageManagerImpl(cros_settings_
, this)),
194 supervised_user_manager_(new SupervisedUserManagerImpl(this)),
195 manager_creation_time_(base::TimeTicks::Now()),
196 multi_profile_first_run_notification_(
197 new MultiProfileFirstRunNotification
) {
198 // UserManager instance should be used only on UI thread.
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
200 registrar_
.Add(this, chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED
,
201 content::NotificationService::AllSources());
202 registrar_
.Add(this, chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
,
203 content::NotificationService::AllSources());
205 chrome::NOTIFICATION_PROFILE_CREATED
,
206 content::NotificationService::AllSources());
207 RetrieveTrustedDevicePolicies();
208 local_accounts_subscription_
= cros_settings_
->AddSettingsObserver(
209 kAccountsPrefDeviceLocalAccounts
,
210 base::Bind(&UserManagerImpl::RetrieveTrustedDevicePolicies
,
211 base::Unretained(this)));
212 supervised_users_subscription_
= cros_settings_
->AddSettingsObserver(
213 kAccountsPrefSupervisedUsersEnabled
,
214 base::Bind(&UserManagerImpl::RetrieveTrustedDevicePolicies
,
215 base::Unretained(this)));
216 multi_profile_user_controller_
.reset(new MultiProfileUserController(
217 this, g_browser_process
->local_state()));
221 UserManagerImpl::~UserManagerImpl() {
222 // Can't use STLDeleteElements because of the private destructor of User.
223 for (UserList::iterator it
= users_
.begin(); it
!= users_
.end();
224 it
= users_
.erase(it
)) {
225 if (active_user_
== *it
)
229 // These are pointers to the same User instances that were in users_ list.
230 logged_in_users_
.clear();
231 lru_logged_in_users_
.clear();
236 void UserManagerImpl::Shutdown() {
237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
238 local_accounts_subscription_
.reset();
239 supervised_users_subscription_
.reset();
240 // Stop the session length limiter.
241 session_length_limiter_
.reset();
243 if (device_local_account_policy_service_
)
244 device_local_account_policy_service_
->RemoveObserver(this);
246 user_image_manager_
->Shutdown();
247 multi_profile_user_controller_
.reset();
250 UserImageManager
* UserManagerImpl::GetUserImageManager() {
251 return user_image_manager_
.get();
254 SupervisedUserManager
* UserManagerImpl::GetSupervisedUserManager() {
255 return supervised_user_manager_
.get();
258 const UserList
& UserManagerImpl::GetUsers() const {
259 const_cast<UserManagerImpl
*>(this)->EnsureUsersLoaded();
263 UserList
UserManagerImpl::GetUsersAdmittedForMultiProfile() const {
264 if (!UserManager::IsMultipleProfilesAllowed())
268 const UserList
& users
= GetUsers();
269 for (UserList::const_iterator it
= users
.begin(); it
!= users
.end(); ++it
) {
270 if ((*it
)->GetType() == User::USER_TYPE_REGULAR
&&
271 !(*it
)->is_logged_in() &&
272 multi_profile_user_controller_
->IsUserAllowedInSession(
274 result
.push_back(*it
);
280 const UserList
& UserManagerImpl::GetLoggedInUsers() const {
281 return logged_in_users_
;
284 const UserList
& UserManagerImpl::GetLRULoggedInUsers() {
285 // If there is no user logged in, we return the active user as the only one.
286 if (lru_logged_in_users_
.empty() && active_user_
) {
287 temp_single_logged_in_users_
.clear();
288 temp_single_logged_in_users_
.insert(temp_single_logged_in_users_
.begin(),
290 return temp_single_logged_in_users_
;
292 return lru_logged_in_users_
;
295 UserList
UserManagerImpl::GetUnlockUsers() const {
296 UserList unlock_users
;
298 unlock_users
.push_back(primary_user_
);
302 const std::string
& UserManagerImpl::GetOwnerEmail() {
306 void UserManagerImpl::UserLoggedIn(const std::string
& user_id
,
307 const std::string
& username_hash
,
308 bool browser_restart
) {
309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
311 if (!CommandLine::ForCurrentProcess()->HasSwitch(::switches::kMultiProfiles
))
312 DCHECK(!IsUserLoggedIn());
314 User
* user
= FindUserInListAndModify(user_id
);
315 if (active_user_
&& user
) {
316 user
->set_is_logged_in(true);
317 user
->set_username_hash(username_hash
);
318 logged_in_users_
.push_back(user
);
319 lru_logged_in_users_
.push_back(user
);
320 // Reset the new user flag if the user already exists.
321 is_current_user_new_
= false;
322 // Set active user wallpaper back.
323 WallpaperManager::Get()->SetUserWallpaper(active_user_
->email());
324 NotifyUserAddedToSession(user
);
328 policy::DeviceLocalAccount::Type device_local_account_type
;
329 if (user_id
== UserManager::kGuestUserName
) {
331 } else if (user_id
== UserManager::kRetailModeUserName
) {
332 RetailModeUserLoggedIn();
333 } else if (policy::IsDeviceLocalAccountUser(user_id
,
334 &device_local_account_type
) &&
335 device_local_account_type
==
336 policy::DeviceLocalAccount::TYPE_KIOSK_APP
) {
337 KioskAppLoggedIn(user_id
);
341 if (user
&& user
->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT
) {
342 PublicAccountUserLoggedIn(user
);
343 } else if ((user
&& user
->GetType() == User::USER_TYPE_LOCALLY_MANAGED
) ||
344 (!user
&& gaia::ExtractDomainName(user_id
) ==
345 UserManager::kLocallyManagedUserDomain
)) {
346 LocallyManagedUserLoggedIn(user_id
);
347 } else if (browser_restart
&& user_id
== g_browser_process
->local_state()->
348 GetString(kPublicAccountPendingDataRemoval
)) {
349 PublicAccountUserLoggedIn(User::CreatePublicAccountUser(user_id
));
350 } else if (user_id
!= owner_email_
&& !user
&&
351 (AreEphemeralUsersEnabled() || browser_restart
)) {
352 RegularUserLoggedInAsEphemeral(user_id
);
354 RegularUserLoggedIn(user_id
);
357 // Initialize the session length limiter and start it only if
358 // session limit is defined by the policy.
359 session_length_limiter_
.reset(new SessionLengthLimiter(NULL
,
362 DCHECK(active_user_
);
363 active_user_
->set_is_logged_in(true);
364 active_user_
->set_is_active(true);
365 active_user_
->set_username_hash(username_hash
);
367 // Place user who just signed in to the top of the logged in users.
368 logged_in_users_
.insert(logged_in_users_
.begin(), active_user_
);
369 SetLRUUser(active_user_
);
371 if (!primary_user_
) {
372 primary_user_
= active_user_
;
373 if (primary_user_
->GetType() == User::USER_TYPE_REGULAR
)
374 SendRegularUserLoginMetrics(user_id
);
377 UMA_HISTOGRAM_ENUMERATION("UserManager.LoginUserType",
378 active_user_
->GetType(), User::NUM_USER_TYPES
);
380 g_browser_process
->local_state()->SetString(kLastLoggedInRegularUser
,
381 (active_user_
->GetType() == User::USER_TYPE_REGULAR
) ? user_id
: "");
386 void UserManagerImpl::SwitchActiveUser(const std::string
& user_id
) {
387 if (!CommandLine::ForCurrentProcess()->HasSwitch(::switches::kMultiProfiles
))
390 User
* user
= FindUserAndModify(user_id
);
392 NOTREACHED() << "Switching to a non-existing user";
395 if (user
== active_user_
) {
396 NOTREACHED() << "Switching to a user who is already active";
399 if (!user
->is_logged_in()) {
400 NOTREACHED() << "Switching to a user that is not logged in";
403 if (user
->GetType() != User::USER_TYPE_REGULAR
) {
404 NOTREACHED() << "Switching to a non-regular user";
407 if (user
->username_hash().empty()) {
408 NOTREACHED() << "Switching to a user that doesn't have username_hash set";
412 DCHECK(active_user_
);
413 active_user_
->set_is_active(false);
414 user
->set_is_active(true);
417 // Move the user to the front.
418 SetLRUUser(active_user_
);
420 NotifyActiveUserHashChanged(active_user_
->username_hash());
421 NotifyActiveUserChanged(active_user_
);
424 void UserManagerImpl::RestoreActiveSessions() {
425 DBusThreadManager::Get()->GetSessionManagerClient()->RetrieveActiveSessions(
426 base::Bind(&UserManagerImpl::OnRestoreActiveSessions
,
427 base::Unretained(this)));
430 void UserManagerImpl::SessionStarted() {
431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
432 session_started_
= true;
434 content::NotificationService::current()->Notify(
435 chrome::NOTIFICATION_SESSION_STARTED
,
436 content::Source
<UserManager
>(this),
437 content::Details
<const User
>(active_user_
));
438 if (is_current_user_new_
) {
439 // Make sure that the new user's data is persisted to Local State.
440 g_browser_process
->local_state()->CommitPendingWrite();
444 void UserManagerImpl::RemoveUser(const std::string
& user_id
,
445 RemoveUserDelegate
* delegate
) {
446 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
448 const User
* user
= FindUser(user_id
);
449 if (!user
|| (user
->GetType() != User::USER_TYPE_REGULAR
&&
450 user
->GetType() != User::USER_TYPE_LOCALLY_MANAGED
))
453 // Sanity check: we must not remove single user. This check may seem
454 // redundant at a first sight because this single user must be an owner and
455 // we perform special check later in order not to remove an owner. However
456 // due to non-instant nature of ownership assignment this later check may
457 // sometimes fail. See http://crosbug.com/12723
458 if (users_
.size() < 2)
461 // Sanity check: do not allow any of the the logged in users to be removed.
462 for (UserList::const_iterator it
= logged_in_users_
.begin();
463 it
!= logged_in_users_
.end(); ++it
) {
464 if ((*it
)->email() == user_id
)
468 RemoveUserInternal(user_id
, delegate
);
471 void UserManagerImpl::RemoveUserInternal(const std::string
& user_email
,
472 RemoveUserDelegate
* delegate
) {
473 CrosSettings
* cros_settings
= CrosSettings::Get();
475 // Ensure the value of owner email has been fetched.
476 if (CrosSettingsProvider::TRUSTED
!= cros_settings
->PrepareTrustedValues(
477 base::Bind(&UserManagerImpl::RemoveUserInternal
,
478 base::Unretained(this),
479 user_email
, delegate
))) {
480 // Value of owner email is not fetched yet. RemoveUserInternal will be
481 // called again after fetch completion.
485 cros_settings
->GetString(kDeviceOwner
, &owner
);
486 if (user_email
== owner
) {
487 // Owner is not allowed to be removed from the device.
490 RemoveNonOwnerUserInternal(user_email
, delegate
);
493 void UserManagerImpl::RemoveNonOwnerUserInternal(const std::string
& user_email
,
494 RemoveUserDelegate
* delegate
) {
496 delegate
->OnBeforeUserRemoved(user_email
);
497 RemoveUserFromList(user_email
);
498 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
499 user_email
, base::Bind(&OnRemoveUserComplete
, user_email
));
502 delegate
->OnUserRemoved(user_email
);
505 void UserManagerImpl::RemoveUserFromList(const std::string
& user_id
) {
506 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
507 RemoveNonCryptohomeData(user_id
);
508 if (user_loading_stage_
== STAGE_LOADED
) {
509 User
* user
= RemoveRegularOrLocallyManagedUserFromList(user_id
);
511 } else if (user_loading_stage_
== STAGE_LOADING
) {
512 DCHECK(gaia::ExtractDomainName(user_id
) ==
513 UserManager::kLocallyManagedUserDomain
);
514 // Special case, removing partially-constructed supervised user during user
516 ListPrefUpdate
users_update(g_browser_process
->local_state(),
518 users_update
->Remove(base::StringValue(user_id
), NULL
);
520 NOTREACHED() << "Users are not loaded yet.";
523 // Make sure that new data is persisted to Local State.
524 g_browser_process
->local_state()->CommitPendingWrite();
527 bool UserManagerImpl::IsKnownUser(const std::string
& user_id
) const {
528 return FindUser(user_id
) != NULL
;
531 const User
* UserManagerImpl::FindUser(const std::string
& user_id
) const {
532 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
533 if (active_user_
&& active_user_
->email() == user_id
)
535 return FindUserInList(user_id
);
538 User
* UserManagerImpl::FindUserAndModify(const std::string
& user_id
) {
539 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
540 if (active_user_
&& active_user_
->email() == user_id
)
542 return FindUserInListAndModify(user_id
);
545 const User
* UserManagerImpl::GetLoggedInUser() const {
546 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
550 User
* UserManagerImpl::GetLoggedInUser() {
551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
555 const User
* UserManagerImpl::GetActiveUser() const {
556 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
560 User
* UserManagerImpl::GetActiveUser() {
561 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
565 const User
* UserManagerImpl::GetPrimaryUser() const {
566 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
567 return primary_user_
;
570 User
* UserManagerImpl::GetUserByProfile(Profile
* profile
) const {
571 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
572 if (ProfileHelper::IsSigninProfile(profile
))
575 if (IsMultipleProfilesAllowed()) {
576 const std::string username_hash
=
577 ProfileHelper::GetUserIdHashFromProfile(profile
);
578 const UserList
& users
= GetUsers();
579 const UserList::const_iterator pos
= std::find_if(
580 users
.begin(), users
.end(), UserHashMatcher(username_hash
));
581 return (pos
!= users
.end()) ? *pos
: NULL
;
586 Profile
* UserManagerImpl::GetProfileByUser(const User
* user
) const {
587 if (IsMultipleProfilesAllowed())
588 return ProfileHelper::GetProfileByUserIdHash(user
->username_hash());
589 return g_browser_process
->profile_manager()->GetDefaultProfile();
592 void UserManagerImpl::SaveUserOAuthStatus(
593 const std::string
& user_id
,
594 User::OAuthTokenStatus oauth_token_status
) {
595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
597 DVLOG(1) << "Saving user OAuth token status in Local State";
598 User
* user
= FindUserAndModify(user_id
);
600 user
->set_oauth_token_status(oauth_token_status
);
602 GetUserFlow(user_id
)->HandleOAuthTokenStatusChange(oauth_token_status
);
604 // Do not update local store if data stored or cached outside the user's
605 // cryptohome is to be treated as ephemeral.
606 if (IsUserNonCryptohomeDataEphemeral(user_id
))
609 PrefService
* local_state
= g_browser_process
->local_state();
611 DictionaryPrefUpdate
oauth_status_update(local_state
, kUserOAuthTokenStatus
);
612 oauth_status_update
->SetWithoutPathExpansion(user_id
,
613 new base::FundamentalValue(static_cast<int>(oauth_token_status
)));
616 User::OAuthTokenStatus
UserManagerImpl::LoadUserOAuthStatus(
617 const std::string
& user_id
) const {
618 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
620 PrefService
* local_state
= g_browser_process
->local_state();
621 const DictionaryValue
* prefs_oauth_status
=
622 local_state
->GetDictionary(kUserOAuthTokenStatus
);
623 int oauth_token_status
= User::OAUTH_TOKEN_STATUS_UNKNOWN
;
624 if (prefs_oauth_status
&&
625 prefs_oauth_status
->GetIntegerWithoutPathExpansion(
626 user_id
, &oauth_token_status
)) {
627 User::OAuthTokenStatus result
=
628 static_cast<User::OAuthTokenStatus
>(oauth_token_status
);
629 if (result
== User::OAUTH2_TOKEN_STATUS_INVALID
)
630 GetUserFlow(user_id
)->HandleOAuthTokenStatusChange(result
);
633 return User::OAUTH_TOKEN_STATUS_UNKNOWN
;
636 void UserManagerImpl::SaveUserDisplayName(const std::string
& user_id
,
637 const base::string16
& display_name
) {
638 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
640 if (User
* user
= FindUserAndModify(user_id
)) {
641 user
->set_display_name(display_name
);
643 // Do not update local store if data stored or cached outside the user's
644 // cryptohome is to be treated as ephemeral.
645 if (!IsUserNonCryptohomeDataEphemeral(user_id
)) {
646 PrefService
* local_state
= g_browser_process
->local_state();
648 DictionaryPrefUpdate
display_name_update(local_state
, kUserDisplayName
);
649 display_name_update
->SetWithoutPathExpansion(
651 new base::StringValue(display_name
));
653 supervised_user_manager_
->UpdateManagerName(user_id
, display_name
);
658 string16
UserManagerImpl::GetUserDisplayName(
659 const std::string
& user_id
) const {
660 const User
* user
= FindUser(user_id
);
661 return user
? user
->display_name() : base::string16();
664 void UserManagerImpl::SaveUserDisplayEmail(const std::string
& user_id
,
665 const std::string
& display_email
) {
666 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
668 User
* user
= FindUserAndModify(user_id
);
670 return; // Ignore if there is no such user.
672 user
->set_display_email(display_email
);
674 // Do not update local store if data stored or cached outside the user's
675 // cryptohome is to be treated as ephemeral.
676 if (IsUserNonCryptohomeDataEphemeral(user_id
))
679 PrefService
* local_state
= g_browser_process
->local_state();
681 DictionaryPrefUpdate
display_email_update(local_state
, kUserDisplayEmail
);
682 display_email_update
->SetWithoutPathExpansion(
684 new base::StringValue(display_email
));
687 std::string
UserManagerImpl::GetUserDisplayEmail(
688 const std::string
& user_id
) const {
689 const User
* user
= FindUser(user_id
);
690 return user
? user
->display_email() : user_id
;
693 void UserManagerImpl::UpdateUserAccountData(
694 const std::string
& user_id
,
695 const UserAccountData
& account_data
) {
696 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
698 SaveUserDisplayName(user_id
, account_data
.display_name());
700 if (User
* user
= FindUserAndModify(user_id
)) {
701 base::string16 given_name
= account_data
.given_name();
702 user
->set_given_name(given_name
);
703 if (!IsUserNonCryptohomeDataEphemeral(user_id
)) {
704 PrefService
* local_state
= g_browser_process
->local_state();
706 DictionaryPrefUpdate
given_name_update(local_state
, kUserGivenName
);
707 given_name_update
->SetWithoutPathExpansion(
709 new base::StringValue(given_name
));
713 UpdateUserAccountLocale(user_id
, account_data
.locale());
716 // TODO(alemate): http://crbug.com/288941 : Respect preferred language list in
717 // the Google user profile.
719 // Returns true if callback will be called.
720 bool UserManagerImpl::RespectLocalePreference(
723 scoped_ptr
<locale_util::SwitchLanguageCallback
> callback
) const {
724 if (g_browser_process
== NULL
)
726 if ((user
== NULL
) || (user
!= GetPrimaryUser()) ||
727 (!user
->is_profile_created()))
730 // In case of Multi Profile mode we don't apply profile locale because it is
732 if (GetLoggedInUsers().size() != 1)
734 const PrefService
* prefs
= profile
->GetPrefs();
738 std::string pref_locale
;
739 const std::string pref_app_locale
=
740 prefs
->GetString(prefs::kApplicationLocale
);
741 const std::string pref_bkup_locale
=
742 prefs
->GetString(prefs::kApplicationLocaleBackup
);
744 pref_locale
= pref_app_locale
;
745 if (pref_locale
.empty())
746 pref_locale
= pref_bkup_locale
;
748 const std::string
* account_locale
= NULL
;
749 if (pref_locale
.empty() && user
->has_gaia_account()) {
750 if (user
->GetAccountLocale() == NULL
)
751 return false; // wait until Account profile is loaded.
752 account_locale
= user
->GetAccountLocale();
753 pref_locale
= *account_locale
;
755 const std::string global_app_locale
=
756 g_browser_process
->GetApplicationLocale();
757 if (pref_locale
.empty())
758 pref_locale
= global_app_locale
;
759 DCHECK(!pref_locale
.empty());
760 LOG(WARNING
) << "RespectLocalePreference: "
761 << "app_locale='" << pref_app_locale
<< "', "
762 << "bkup_locale='" << pref_bkup_locale
<< "', "
763 << (account_locale
!= NULL
764 ? (std::string("account_locale='") + (*account_locale
) +
766 : (std::string("account_locale - unused. ")))
767 << " Selected '" << pref_locale
<< "'";
768 profile
->ChangeAppLocale(pref_locale
, Profile::APP_LOCALE_CHANGED_VIA_LOGIN
);
769 // Here we don't enable keyboard layouts. Input methods are set up when
770 // the user first logs in. Then the user may customize the input methods.
771 // Hence changing input methods here, just because the user's UI language
772 // is different from the login screen UI language, is not desirable. Note
773 // that input method preferences are synced, so users can use their
774 // farovite input methods as soon as the preferences are synced.
775 locale_util::SwitchLanguage(pref_locale
, false, callback
.Pass());
780 void UserManagerImpl::Observe(int type
,
781 const content::NotificationSource
& source
,
782 const content::NotificationDetails
& details
) {
784 case chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED
:
785 if (!device_local_account_policy_service_
) {
786 device_local_account_policy_service_
=
787 g_browser_process
->browser_policy_connector()->
788 GetDeviceLocalAccountPolicyService();
789 if (device_local_account_policy_service_
)
790 device_local_account_policy_service_
->AddObserver(this);
792 RetrieveTrustedDevicePolicies();
795 case chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
:
796 if (IsUserLoggedIn() &&
797 !IsLoggedInAsGuest() &&
798 !IsLoggedInAsKioskApp()) {
799 Profile
* profile
= content::Details
<Profile
>(details
).ptr();
800 if (!profile
->IsOffTheRecord()) {
801 AuthSyncObserver
* sync_observer
=
802 AuthSyncObserverFactory::GetInstance()->GetForProfile(profile
);
803 sync_observer
->StartObserving();
804 multi_profile_user_controller_
->StartObserving(profile
);
805 multi_profile_first_run_notification_
->UserProfilePrepared(profile
);
809 case chrome::NOTIFICATION_PROFILE_CREATED
: {
810 Profile
* profile
= content::Source
<Profile
>(source
).ptr();
811 User
* user
= GetUserByProfile(profile
);
813 user
->set_profile_is_created();
822 void UserManagerImpl::OnPolicyUpdated(const std::string
& user_id
) {
823 UpdatePublicAccountDisplayName(user_id
);
824 NotifyUserListChanged();
827 void UserManagerImpl::OnDeviceLocalAccountsChanged() {
828 // No action needed here, changes to the list of device-local accounts get
829 // handled via the kAccountsPrefDeviceLocalAccounts device setting observer.
832 bool UserManagerImpl::IsCurrentUserOwner() const {
833 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
834 base::AutoLock
lk(is_current_user_owner_lock_
);
835 return is_current_user_owner_
;
838 void UserManagerImpl::SetCurrentUserIsOwner(bool is_current_user_owner
) {
839 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
841 base::AutoLock
lk(is_current_user_owner_lock_
);
842 is_current_user_owner_
= is_current_user_owner
;
847 bool UserManagerImpl::IsCurrentUserNew() const {
848 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
849 return is_current_user_new_
;
852 bool UserManagerImpl::IsCurrentUserNonCryptohomeDataEphemeral() const {
853 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
854 return IsUserLoggedIn() &&
855 IsUserNonCryptohomeDataEphemeral(GetLoggedInUser()->email());
858 bool UserManagerImpl::CanCurrentUserLock() const {
859 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
860 return IsUserLoggedIn() && active_user_
->can_lock();
863 bool UserManagerImpl::IsUserLoggedIn() const {
864 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
868 bool UserManagerImpl::IsLoggedInAsRegularUser() const {
869 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
870 return IsUserLoggedIn() &&
871 active_user_
->GetType() == User::USER_TYPE_REGULAR
;
874 bool UserManagerImpl::IsLoggedInAsDemoUser() const {
875 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
876 return IsUserLoggedIn() &&
877 active_user_
->GetType() == User::USER_TYPE_RETAIL_MODE
;
880 bool UserManagerImpl::IsLoggedInAsPublicAccount() const {
881 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
882 return IsUserLoggedIn() &&
883 active_user_
->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT
;
886 bool UserManagerImpl::IsLoggedInAsGuest() const {
887 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
888 return IsUserLoggedIn() &&
889 active_user_
->GetType() == User::USER_TYPE_GUEST
;
892 bool UserManagerImpl::IsLoggedInAsLocallyManagedUser() const {
893 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
894 return IsUserLoggedIn() &&
895 active_user_
->GetType() == User::USER_TYPE_LOCALLY_MANAGED
;
898 bool UserManagerImpl::IsLoggedInAsKioskApp() const {
899 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
900 return IsUserLoggedIn() &&
901 active_user_
->GetType() == User::USER_TYPE_KIOSK_APP
;
904 bool UserManagerImpl::IsLoggedInAsStub() const {
905 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
906 return IsUserLoggedIn() && active_user_
->email() == kStubUser
;
909 bool UserManagerImpl::IsSessionStarted() const {
910 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
911 return session_started_
;
914 bool UserManagerImpl::UserSessionsRestored() const {
915 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
916 return user_sessions_restored_
;
919 bool UserManagerImpl::HasBrowserRestarted() const {
920 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
921 return base::SysInfo::IsRunningOnChromeOS() &&
922 command_line
->HasSwitch(switches::kLoginUser
) &&
923 !command_line
->HasSwitch(switches::kLoginPassword
);
926 bool UserManagerImpl::IsUserNonCryptohomeDataEphemeral(
927 const std::string
& user_id
) const {
928 // Data belonging to the guest, retail mode and stub users is always
930 if (user_id
== UserManager::kGuestUserName
||
931 user_id
== UserManager::kRetailModeUserName
||
932 user_id
== kStubUser
) {
936 // Data belonging to the owner, anyone found on the user list and obsolete
937 // public accounts whose data has not been removed yet is not ephemeral.
938 if (user_id
== owner_email_
|| UserExistsInList(user_id
) ||
939 user_id
== g_browser_process
->local_state()->
940 GetString(kPublicAccountPendingDataRemoval
)) {
944 // Data belonging to the currently logged-in user is ephemeral when:
945 // a) The user logged into a regular account while the ephemeral users policy
948 // b) The user logged into any other account type.
949 if (IsUserLoggedIn() && (user_id
== GetLoggedInUser()->email()) &&
950 (is_current_user_ephemeral_regular_user_
|| !IsLoggedInAsRegularUser())) {
954 // Data belonging to any other user is ephemeral when:
955 // a) Going through the regular login flow and the ephemeral users policy is
958 // b) The browser is restarting after a crash.
959 return AreEphemeralUsersEnabled() || HasBrowserRestarted();
962 void UserManagerImpl::AddObserver(UserManager::Observer
* obs
) {
963 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
964 observer_list_
.AddObserver(obs
);
967 void UserManagerImpl::RemoveObserver(UserManager::Observer
* obs
) {
968 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
969 observer_list_
.RemoveObserver(obs
);
972 void UserManagerImpl::AddSessionStateObserver(
973 UserManager::UserSessionStateObserver
* obs
) {
974 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
975 session_state_observer_list_
.AddObserver(obs
);
978 void UserManagerImpl::RemoveSessionStateObserver(
979 UserManager::UserSessionStateObserver
* obs
) {
980 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
981 session_state_observer_list_
.RemoveObserver(obs
);
984 void UserManagerImpl::NotifyLocalStateChanged() {
985 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
986 FOR_EACH_OBSERVER(UserManager::Observer
, observer_list_
,
987 LocalStateChanged(this));
990 void UserManagerImpl::OnProfilePrepared(Profile
* profile
) {
991 LoginUtils::Get()->DoBrowserLaunch(profile
,
992 NULL
); // host_, not needed here
994 if (!CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestName
)) {
995 // Did not log in (we crashed or are debugging), need to restore Sync.
996 // TODO(nkostylev): Make sure that OAuth state is restored correctly for all
997 // users once it is fully multi-profile aware. http://crbug.com/238987
998 // For now if we have other user pending sessions they'll override OAuth
999 // session restore for previous users.
1000 LoginUtils::Get()->RestoreAuthenticationSession(profile
);
1003 // Restore other user sessions if any.
1004 RestorePendingUserSessions();
1007 void UserManagerImpl::EnsureUsersLoaded() {
1008 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1009 if (!g_browser_process
|| !g_browser_process
->local_state())
1012 if (user_loading_stage_
!= STAGE_NOT_LOADED
)
1014 user_loading_stage_
= STAGE_LOADING
;
1015 // Clean up user list first. All code down the path should be synchronous,
1016 // so that local state after transaction rollback is in consistent state.
1017 // This process also should not trigger EnsureUsersLoaded again.
1018 if (supervised_user_manager_
->HasFailedUserCreationTransaction())
1019 supervised_user_manager_
->RollbackUserCreationTransaction();
1021 PrefService
* local_state
= g_browser_process
->local_state();
1022 const ListValue
* prefs_regular_users
= local_state
->GetList(kRegularUsers
);
1023 const ListValue
* prefs_public_accounts
=
1024 local_state
->GetList(kPublicAccounts
);
1025 const DictionaryValue
* prefs_display_names
=
1026 local_state
->GetDictionary(kUserDisplayName
);
1027 const DictionaryValue
* prefs_given_names
=
1028 local_state
->GetDictionary(kUserGivenName
);
1029 const DictionaryValue
* prefs_display_emails
=
1030 local_state
->GetDictionary(kUserDisplayEmail
);
1032 // Load regular users and locally managed users.
1033 std::vector
<std::string
> regular_users
;
1034 std::set
<std::string
> regular_users_set
;
1035 ParseUserList(*prefs_regular_users
, std::set
<std::string
>(),
1036 ®ular_users
, ®ular_users_set
);
1037 for (std::vector
<std::string
>::const_iterator it
= regular_users
.begin();
1038 it
!= regular_users
.end(); ++it
) {
1040 const std::string domain
= gaia::ExtractDomainName(*it
);
1041 if (domain
== UserManager::kLocallyManagedUserDomain
)
1042 user
= User::CreateLocallyManagedUser(*it
);
1044 user
= User::CreateRegularUser(*it
);
1045 user
->set_oauth_token_status(LoadUserOAuthStatus(*it
));
1046 users_
.push_back(user
);
1048 base::string16 display_name
;
1049 if (prefs_display_names
->GetStringWithoutPathExpansion(*it
,
1051 user
->set_display_name(display_name
);
1054 base::string16 given_name
;
1055 if (prefs_given_names
->GetStringWithoutPathExpansion(*it
, &given_name
)) {
1056 user
->set_given_name(given_name
);
1059 std::string display_email
;
1060 if (prefs_display_emails
->GetStringWithoutPathExpansion(*it
,
1062 user
->set_display_email(display_email
);
1066 // Load public accounts.
1067 std::vector
<std::string
> public_accounts
;
1068 std::set
<std::string
> public_accounts_set
;
1069 ParseUserList(*prefs_public_accounts
, regular_users_set
,
1070 &public_accounts
, &public_accounts_set
);
1071 for (std::vector
<std::string
>::const_iterator it
= public_accounts
.begin();
1072 it
!= public_accounts
.end(); ++it
) {
1073 users_
.push_back(User::CreatePublicAccountUser(*it
));
1074 UpdatePublicAccountDisplayName(*it
);
1076 user_loading_stage_
= STAGE_LOADED
;
1078 user_image_manager_
->LoadUserImages(users_
);
1081 void UserManagerImpl::RetrieveTrustedDevicePolicies() {
1082 ephemeral_users_enabled_
= false;
1085 // Schedule a callback if device policy has not yet been verified.
1086 if (CrosSettingsProvider::TRUSTED
!= cros_settings_
->PrepareTrustedValues(
1087 base::Bind(&UserManagerImpl::RetrieveTrustedDevicePolicies
,
1088 base::Unretained(this)))) {
1092 cros_settings_
->GetBoolean(kAccountsPrefEphemeralUsersEnabled
,
1093 &ephemeral_users_enabled_
);
1094 cros_settings_
->GetString(kDeviceOwner
, &owner_email_
);
1096 EnsureUsersLoaded();
1098 bool changed
= UpdateAndCleanUpPublicAccounts(
1099 policy::GetDeviceLocalAccounts(cros_settings_
));
1101 // If ephemeral users are enabled and we are on the login screen, take this
1102 // opportunity to clean up by removing all regular users except the owner.
1103 if (ephemeral_users_enabled_
&& !IsUserLoggedIn()) {
1104 ListPrefUpdate
prefs_users_update(g_browser_process
->local_state(),
1106 prefs_users_update
->Clear();
1107 for (UserList::iterator it
= users_
.begin(); it
!= users_
.end(); ) {
1108 const std::string user_email
= (*it
)->email();
1109 if ((*it
)->GetType() == User::USER_TYPE_REGULAR
&&
1110 user_email
!= owner_email_
) {
1111 RemoveNonCryptohomeData(user_email
);
1113 it
= users_
.erase(it
);
1116 if ((*it
)->GetType() != User::USER_TYPE_PUBLIC_ACCOUNT
)
1117 prefs_users_update
->Append(new base::StringValue(user_email
));
1124 NotifyUserListChanged();
1127 bool UserManagerImpl::AreEphemeralUsersEnabled() const {
1128 return ephemeral_users_enabled_
&&
1129 (g_browser_process
->browser_policy_connector()->IsEnterpriseManaged() ||
1130 !owner_email_
.empty());
1133 UserList
& UserManagerImpl::GetUsersAndModify() {
1134 EnsureUsersLoaded();
1138 const User
* UserManagerImpl::FindUserInList(const std::string
& user_id
) const {
1139 const UserList
& users
= GetUsers();
1140 for (UserList::const_iterator it
= users
.begin(); it
!= users
.end(); ++it
) {
1141 if ((*it
)->email() == user_id
)
1147 const bool UserManagerImpl::UserExistsInList(const std::string
& user_id
) const {
1148 PrefService
* local_state
= g_browser_process
->local_state();
1149 const ListValue
* user_list
= local_state
->GetList(kRegularUsers
);
1150 for (size_t i
= 0; i
< user_list
->GetSize(); ++i
) {
1152 if (user_list
->GetString(i
, &email
) && (user_id
== email
))
1158 User
* UserManagerImpl::FindUserInListAndModify(const std::string
& user_id
) {
1159 UserList
& users
= GetUsersAndModify();
1160 for (UserList::iterator it
= users
.begin(); it
!= users
.end(); ++it
) {
1161 if ((*it
)->email() == user_id
)
1167 void UserManagerImpl::GuestUserLoggedIn() {
1168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1169 active_user_
= User::CreateGuestUser();
1170 // TODO(nkostylev): Add support for passing guest session cryptohome
1171 // mount point. Legacy (--login-profile) value will be used for now.
1172 // http://crosbug.com/230859
1173 active_user_
->SetStubImage(User::kInvalidImageIndex
, false);
1174 // Initializes wallpaper after active_user_ is set.
1175 WallpaperManager::Get()->SetInitialUserWallpaper(UserManager::kGuestUserName
,
1179 void UserManagerImpl::AddUserRecord(User
* user
) {
1180 // Add the user to the front of the user list.
1181 ListPrefUpdate
prefs_users_update(g_browser_process
->local_state(),
1183 prefs_users_update
->Insert(0, new base::StringValue(user
->email()));
1184 users_
.insert(users_
.begin(), user
);
1187 void UserManagerImpl::RegularUserLoggedIn(const std::string
& user_id
) {
1188 // Remove the user from the user list.
1189 active_user_
= RemoveRegularOrLocallyManagedUserFromList(user_id
);
1191 // If the user was not found on the user list, create a new user.
1192 is_current_user_new_
= !active_user_
;
1193 if (!active_user_
) {
1194 active_user_
= User::CreateRegularUser(user_id
);
1195 active_user_
->set_oauth_token_status(LoadUserOAuthStatus(user_id
));
1196 SaveUserDisplayName(active_user_
->email(),
1197 UTF8ToUTF16(active_user_
->GetAccountName(true)));
1198 WallpaperManager::Get()->SetInitialUserWallpaper(user_id
, true);
1201 AddUserRecord(active_user_
);
1203 user_image_manager_
->UserLoggedIn(user_id
, is_current_user_new_
, false);
1205 WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
1207 default_pinned_apps_field_trial::SetupForUser(user_id
, is_current_user_new_
);
1209 // Make sure that new data is persisted to Local State.
1210 g_browser_process
->local_state()->CommitPendingWrite();
1213 void UserManagerImpl::RegularUserLoggedInAsEphemeral(
1214 const std::string
& user_id
) {
1215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1216 is_current_user_new_
= true;
1217 is_current_user_ephemeral_regular_user_
= true;
1218 active_user_
= User::CreateRegularUser(user_id
);
1219 user_image_manager_
->UserLoggedIn(user_id
, is_current_user_new_
, false);
1220 WallpaperManager::Get()->SetInitialUserWallpaper(user_id
, false);
1223 void UserManagerImpl::LocallyManagedUserLoggedIn(
1224 const std::string
& user_id
) {
1225 // TODO(nkostylev): Refactor, share code with RegularUserLoggedIn().
1227 // Remove the user from the user list.
1228 active_user_
= RemoveRegularOrLocallyManagedUserFromList(user_id
);
1229 // If the user was not found on the user list, create a new user.
1230 if (!active_user_
) {
1231 is_current_user_new_
= true;
1232 active_user_
= User::CreateLocallyManagedUser(user_id
);
1233 // Leaving OAuth token status at the default state = unknown.
1234 WallpaperManager::Get()->SetInitialUserWallpaper(user_id
, true);
1236 if (supervised_user_manager_
->CheckForFirstRun(user_id
)) {
1237 is_current_user_new_
= true;
1238 WallpaperManager::Get()->SetInitialUserWallpaper(user_id
, true);
1240 is_current_user_new_
= false;
1244 // Add the user to the front of the user list.
1245 ListPrefUpdate
prefs_users_update(g_browser_process
->local_state(),
1247 prefs_users_update
->Insert(0, new base::StringValue(user_id
));
1248 users_
.insert(users_
.begin(), active_user_
);
1250 // Now that user is in the list, save display name.
1251 if (is_current_user_new_
) {
1252 SaveUserDisplayName(active_user_
->email(),
1253 active_user_
->GetDisplayName());
1256 user_image_manager_
->UserLoggedIn(user_id
, is_current_user_new_
, true);
1257 WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
1259 // Make sure that new data is persisted to Local State.
1260 g_browser_process
->local_state()->CommitPendingWrite();
1263 void UserManagerImpl::PublicAccountUserLoggedIn(User
* user
) {
1264 is_current_user_new_
= true;
1265 active_user_
= user
;
1266 // The UserImageManager chooses a random avatar picture when a user logs in
1267 // for the first time. Tell the UserImageManager that this user is not new to
1268 // prevent the avatar from getting changed.
1269 user_image_manager_
->UserLoggedIn(user
->email(), false, true);
1270 WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
1273 void UserManagerImpl::KioskAppLoggedIn(const std::string
& app_id
) {
1274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1275 policy::DeviceLocalAccount::Type device_local_account_type
;
1276 DCHECK(policy::IsDeviceLocalAccountUser(app_id
,
1277 &device_local_account_type
));
1278 DCHECK_EQ(policy::DeviceLocalAccount::TYPE_KIOSK_APP
,
1279 device_local_account_type
);
1281 active_user_
= User::CreateKioskAppUser(app_id
);
1282 active_user_
->SetStubImage(User::kInvalidImageIndex
, false);
1283 WallpaperManager::Get()->SetInitialUserWallpaper(app_id
, false);
1285 // TODO(bartfab): Add KioskAppUsers to the users_ list and keep metadata like
1286 // the kiosk_app_id in these objects, removing the need to re-parse the
1287 // device-local account list here to extract the kiosk_app_id.
1288 const std::vector
<policy::DeviceLocalAccount
> device_local_accounts
=
1289 policy::GetDeviceLocalAccounts(cros_settings_
);
1290 const policy::DeviceLocalAccount
* account
= NULL
;
1291 for (std::vector
<policy::DeviceLocalAccount
>::const_iterator
1292 it
= device_local_accounts
.begin();
1293 it
!= device_local_accounts
.end(); ++it
) {
1294 if (it
->user_id
== app_id
) {
1299 std::string kiosk_app_id
;
1301 kiosk_app_id
= account
->kiosk_app_id
;
1303 LOG(ERROR
) << "Logged into nonexistent kiosk-app account: " << app_id
;
1307 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
1308 command_line
->AppendSwitch(::switches::kForceAppMode
);
1309 command_line
->AppendSwitchASCII(::switches::kAppId
, kiosk_app_id
);
1311 // Disable window animation since kiosk app runs in a single full screen
1312 // window and window animation causes start-up janks.
1313 command_line
->AppendSwitch(
1314 views::corewm::switches::kWindowAnimationsDisabled
);
1317 void UserManagerImpl::RetailModeUserLoggedIn() {
1318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1319 is_current_user_new_
= true;
1320 active_user_
= User::CreateRetailModeUser();
1321 user_image_manager_
->UserLoggedIn(UserManager::kRetailModeUserName
,
1322 is_current_user_new_
,
1324 WallpaperManager::Get()->SetInitialUserWallpaper(
1325 UserManager::kRetailModeUserName
, false);
1328 void UserManagerImpl::NotifyOnLogin() {
1329 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1330 NotifyActiveUserHashChanged(active_user_
->username_hash());
1331 NotifyActiveUserChanged(active_user_
);
1334 // TODO(nkostylev): Deprecate this notification in favor of
1335 // ActiveUserChanged() observer call.
1336 content::NotificationService::current()->Notify(
1337 chrome::NOTIFICATION_LOGIN_USER_CHANGED
,
1338 content::Source
<UserManager
>(this),
1339 content::Details
<const User
>(active_user_
));
1341 // Owner must be first user in session. DeviceSettingsService can't deal with
1342 // multiple user and will mix up ownership, crbug.com/230018.
1343 if (GetLoggedInUsers().size() == 1) {
1344 // Indicate to DeviceSettingsService that the owner key may have become
1346 DeviceSettingsService::Get()->SetUsername(active_user_
->email());
1350 void UserManagerImpl::UpdateOwnership() {
1351 bool is_owner
= DeviceSettingsService::Get()->HasPrivateOwnerKey();
1352 VLOG(1) << "Current user " << (is_owner
? "is owner" : "is not owner");
1354 SetCurrentUserIsOwner(is_owner
);
1357 void UserManagerImpl::RemoveNonCryptohomeData(const std::string
& user_id
) {
1358 WallpaperManager::Get()->RemoveUserWallpaperInfo(user_id
);
1359 user_image_manager_
->DeleteUserImage(user_id
);
1361 PrefService
* prefs
= g_browser_process
->local_state();
1362 DictionaryPrefUpdate
prefs_oauth_update(prefs
, kUserOAuthTokenStatus
);
1364 prefs_oauth_update
->GetIntegerWithoutPathExpansion(user_id
, &oauth_status
);
1365 prefs_oauth_update
->RemoveWithoutPathExpansion(user_id
, NULL
);
1367 DictionaryPrefUpdate
prefs_display_name_update(prefs
, kUserDisplayName
);
1368 prefs_display_name_update
->RemoveWithoutPathExpansion(user_id
, NULL
);
1370 DictionaryPrefUpdate
prefs_given_name_update(prefs
, kUserGivenName
);
1371 prefs_given_name_update
->RemoveWithoutPathExpansion(user_id
, NULL
);
1373 DictionaryPrefUpdate
prefs_display_email_update(prefs
, kUserDisplayEmail
);
1374 prefs_display_email_update
->RemoveWithoutPathExpansion(user_id
, NULL
);
1376 supervised_user_manager_
->RemoveNonCryptohomeData(user_id
);
1378 multi_profile_user_controller_
->RemoveCachedValue(user_id
);
1381 User
* UserManagerImpl::RemoveRegularOrLocallyManagedUserFromList(
1382 const std::string
& user_id
) {
1383 ListPrefUpdate
prefs_users_update(g_browser_process
->local_state(),
1385 prefs_users_update
->Clear();
1387 for (UserList::iterator it
= users_
.begin(); it
!= users_
.end(); ) {
1388 const std::string user_email
= (*it
)->email();
1389 if (user_email
== user_id
) {
1391 it
= users_
.erase(it
);
1393 if ((*it
)->GetType() == User::USER_TYPE_REGULAR
||
1394 (*it
)->GetType() == User::USER_TYPE_LOCALLY_MANAGED
) {
1395 prefs_users_update
->Append(new base::StringValue(user_email
));
1403 void UserManagerImpl::CleanUpPublicAccountNonCryptohomeDataPendingRemoval() {
1404 PrefService
* local_state
= g_browser_process
->local_state();
1405 const std::string public_account_pending_data_removal
=
1406 local_state
->GetString(kPublicAccountPendingDataRemoval
);
1407 if (public_account_pending_data_removal
.empty() ||
1408 (IsUserLoggedIn() &&
1409 public_account_pending_data_removal
== GetActiveUser()->email())) {
1413 RemoveNonCryptohomeData(public_account_pending_data_removal
);
1414 local_state
->ClearPref(kPublicAccountPendingDataRemoval
);
1417 void UserManagerImpl::CleanUpPublicAccountNonCryptohomeData(
1418 const std::vector
<std::string
>& old_public_accounts
) {
1419 std::set
<std::string
> users
;
1420 for (UserList::const_iterator it
= users_
.begin(); it
!= users_
.end(); ++it
)
1421 users
.insert((*it
)->email());
1423 // If the user is logged into a public account that has been removed from the
1424 // user list, mark the account's data as pending removal after logout.
1425 if (IsLoggedInAsPublicAccount()) {
1426 const std::string active_user_id
= GetActiveUser()->email();
1427 if (users
.find(active_user_id
) == users
.end()) {
1428 g_browser_process
->local_state()->SetString(
1429 kPublicAccountPendingDataRemoval
, active_user_id
);
1430 users
.insert(active_user_id
);
1434 // Remove the data belonging to any other public accounts that are no longer
1435 // found on the user list.
1436 for (std::vector
<std::string
>::const_iterator
1437 it
= old_public_accounts
.begin();
1438 it
!= old_public_accounts
.end(); ++it
) {
1439 if (users
.find(*it
) == users
.end())
1440 RemoveNonCryptohomeData(*it
);
1444 bool UserManagerImpl::UpdateAndCleanUpPublicAccounts(
1445 const std::vector
<policy::DeviceLocalAccount
>& device_local_accounts
) {
1446 // Try to remove any public account data marked as pending removal.
1447 CleanUpPublicAccountNonCryptohomeDataPendingRemoval();
1449 // Get the current list of public accounts.
1450 std::vector
<std::string
> old_public_accounts
;
1451 for (UserList::const_iterator it
= users_
.begin(); it
!= users_
.end(); ++it
) {
1452 if ((*it
)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT
)
1453 old_public_accounts
.push_back((*it
)->email());
1456 // Get the new list of public accounts from policy.
1457 std::vector
<std::string
> new_public_accounts
;
1458 for (std::vector
<policy::DeviceLocalAccount
>::const_iterator it
=
1459 device_local_accounts
.begin();
1460 it
!= device_local_accounts
.end(); ++it
) {
1461 // TODO(mnissler, nkostylev, bartfab): Process Kiosk Apps within the
1462 // standard login framework: http://crbug.com/234694
1463 if (it
->type
== policy::DeviceLocalAccount::TYPE_PUBLIC_SESSION
)
1464 new_public_accounts
.push_back(it
->user_id
);
1467 // If the list of public accounts has not changed, return.
1468 if (new_public_accounts
.size() == old_public_accounts
.size()) {
1469 bool changed
= false;
1470 for (size_t i
= 0; i
< new_public_accounts
.size(); ++i
) {
1471 if (new_public_accounts
[i
] != old_public_accounts
[i
]) {
1480 // Persist the new list of public accounts in a pref.
1481 ListPrefUpdate
prefs_public_accounts_update(g_browser_process
->local_state(),
1483 prefs_public_accounts_update
->Clear();
1484 for (std::vector
<std::string
>::const_iterator
1485 it
= new_public_accounts
.begin();
1486 it
!= new_public_accounts
.end(); ++it
) {
1487 prefs_public_accounts_update
->AppendString(*it
);
1490 // Remove the old public accounts from the user list.
1491 for (UserList::iterator it
= users_
.begin(); it
!= users_
.end(); ) {
1492 if ((*it
)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT
) {
1493 if (*it
!= GetLoggedInUser())
1495 it
= users_
.erase(it
);
1501 // Add the new public accounts to the front of the user list.
1502 for (std::vector
<std::string
>::const_reverse_iterator
1503 it
= new_public_accounts
.rbegin();
1504 it
!= new_public_accounts
.rend(); ++it
) {
1505 if (IsLoggedInAsPublicAccount() && *it
== GetActiveUser()->email())
1506 users_
.insert(users_
.begin(), GetLoggedInUser());
1508 users_
.insert(users_
.begin(), User::CreatePublicAccountUser(*it
));
1509 UpdatePublicAccountDisplayName(*it
);
1512 user_image_manager_
->LoadUserImages(
1513 UserList(users_
.begin(), users_
.begin() + new_public_accounts
.size()));
1515 // Remove data belonging to public accounts that are no longer found on the
1517 CleanUpPublicAccountNonCryptohomeData(old_public_accounts
);
1522 void UserManagerImpl::UpdatePublicAccountDisplayName(
1523 const std::string
& user_id
) {
1524 std::string display_name
;
1526 if (device_local_account_policy_service_
) {
1527 policy::DeviceLocalAccountPolicyBroker
* broker
=
1528 device_local_account_policy_service_
->GetBrokerForUser(user_id
);
1530 display_name
= broker
->GetDisplayName();
1533 // Set or clear the display name.
1534 SaveUserDisplayName(user_id
, UTF8ToUTF16(display_name
));
1537 UserFlow
* UserManagerImpl::GetCurrentUserFlow() const {
1538 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1539 if (!IsUserLoggedIn())
1540 return GetDefaultUserFlow();
1541 return GetUserFlow(GetLoggedInUser()->email());
1544 UserFlow
* UserManagerImpl::GetUserFlow(const std::string
& user_id
) const {
1545 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1546 FlowMap::const_iterator it
= specific_flows_
.find(user_id
);
1547 if (it
!= specific_flows_
.end())
1549 return GetDefaultUserFlow();
1552 void UserManagerImpl::SetUserFlow(const std::string
& user_id
, UserFlow
* flow
) {
1553 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1554 ResetUserFlow(user_id
);
1555 specific_flows_
[user_id
] = flow
;
1558 void UserManagerImpl::ResetUserFlow(const std::string
& user_id
) {
1559 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1560 FlowMap::iterator it
= specific_flows_
.find(user_id
);
1561 if (it
!= specific_flows_
.end()) {
1563 specific_flows_
.erase(it
);
1567 bool UserManagerImpl::GetAppModeChromeClientOAuthInfo(
1568 std::string
* chrome_client_id
, std::string
* chrome_client_secret
) {
1569 if (!chrome::IsRunningInForcedAppMode() ||
1570 chrome_client_id_
.empty() ||
1571 chrome_client_secret_
.empty()) {
1575 *chrome_client_id
= chrome_client_id_
;
1576 *chrome_client_secret
= chrome_client_secret_
;
1580 void UserManagerImpl::SetAppModeChromeClientOAuthInfo(
1581 const std::string
& chrome_client_id
,
1582 const std::string
& chrome_client_secret
) {
1583 if (!chrome::IsRunningInForcedAppMode())
1586 chrome_client_id_
= chrome_client_id
;
1587 chrome_client_secret_
= chrome_client_secret
;
1590 bool UserManagerImpl::AreLocallyManagedUsersAllowed() const {
1591 bool locally_managed_users_allowed
= false;
1592 cros_settings_
->GetBoolean(kAccountsPrefSupervisedUsersEnabled
,
1593 &locally_managed_users_allowed
);
1594 return locally_managed_users_allowed
||
1595 !g_browser_process
->browser_policy_connector()->IsEnterpriseManaged();
1598 base::FilePath
UserManagerImpl::GetUserProfileDir(
1599 const std::string
& user_id
) const {
1600 // TODO(dpolukhin): Remove Chrome OS specific profile path logic from
1601 // ProfileManager and use only this function to construct profile path.
1602 // TODO(nkostylev): Cleanup profile dir related code paths crbug.com/294233
1603 base::FilePath profile_dir
;
1604 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
1605 if (command_line
.HasSwitch(::switches::kMultiProfiles
)) {
1606 const User
* user
= FindUser(user_id
);
1607 if (user
&& !user
->username_hash().empty())
1608 profile_dir
= ProfileHelper::GetUserProfileDir(user
->username_hash());
1609 } else if (command_line
.HasSwitch(chromeos::switches::kLoginProfile
)) {
1610 profile_dir
= ProfileHelper::GetProfileDirByLegacyLoginProfileSwitch();
1612 // We should never be logged in with no profile dir unless
1613 // multi-profiles are enabled.
1615 profile_dir
= base::FilePath();
1618 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
1619 profile_dir
= profile_manager
->user_data_dir().Append(profile_dir
);
1624 UserFlow
* UserManagerImpl::GetDefaultUserFlow() const {
1625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1626 if (!default_flow_
.get())
1627 default_flow_
.reset(new DefaultUserFlow());
1628 return default_flow_
.get();
1631 void UserManagerImpl::NotifyUserListChanged() {
1632 content::NotificationService::current()->Notify(
1633 chrome::NOTIFICATION_USER_LIST_CHANGED
,
1634 content::Source
<UserManager
>(this),
1635 content::NotificationService::NoDetails());
1638 void UserManagerImpl::NotifyActiveUserChanged(const User
* active_user
) {
1639 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1640 FOR_EACH_OBSERVER(UserManager::UserSessionStateObserver
,
1641 session_state_observer_list_
,
1642 ActiveUserChanged(active_user
));
1645 void UserManagerImpl::NotifyUserAddedToSession(const User
* added_user
) {
1646 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1647 FOR_EACH_OBSERVER(UserManager::UserSessionStateObserver
,
1648 session_state_observer_list_
,
1649 UserAddedToSession(added_user
));
1652 void UserManagerImpl::NotifyActiveUserHashChanged(const std::string
& hash
) {
1653 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1654 FOR_EACH_OBSERVER(UserManager::UserSessionStateObserver
,
1655 session_state_observer_list_
,
1656 ActiveUserHashChanged(hash
));
1659 void UserManagerImpl::NotifyPendingUserSessionsRestoreFinished() {
1660 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1661 user_sessions_restored_
= true;
1662 FOR_EACH_OBSERVER(UserManager::UserSessionStateObserver
,
1663 session_state_observer_list_
,
1664 PendingUserSessionsRestoreFinished());
1667 void UserManagerImpl::UpdateLoginState() {
1668 if (!LoginState::IsInitialized())
1669 return; // LoginState may not be intialized in tests.
1670 LoginState::LoggedInState logged_in_state
;
1671 logged_in_state
= active_user_
? LoginState::LOGGED_IN_ACTIVE
1672 : LoginState::LOGGED_IN_NONE
;
1674 LoginState::LoggedInUserType login_user_type
;
1675 if (logged_in_state
== LoginState::LOGGED_IN_NONE
)
1676 login_user_type
= LoginState::LOGGED_IN_USER_NONE
;
1677 else if (is_current_user_owner_
)
1678 login_user_type
= LoginState::LOGGED_IN_USER_OWNER
;
1679 else if (active_user_
->GetType() == User::USER_TYPE_GUEST
)
1680 login_user_type
= LoginState::LOGGED_IN_USER_GUEST
;
1681 else if (active_user_
->GetType() == User::USER_TYPE_RETAIL_MODE
)
1682 login_user_type
= LoginState::LOGGED_IN_USER_RETAIL_MODE
;
1683 else if (active_user_
->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT
)
1684 login_user_type
= LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT
;
1685 else if (active_user_
->GetType() == User::USER_TYPE_LOCALLY_MANAGED
)
1686 login_user_type
= LoginState::LOGGED_IN_USER_LOCALLY_MANAGED
;
1687 else if (active_user_
->GetType() == User::USER_TYPE_KIOSK_APP
)
1688 login_user_type
= LoginState::LOGGED_IN_USER_KIOSK_APP
;
1690 login_user_type
= LoginState::LOGGED_IN_USER_REGULAR
;
1692 LoginState::Get()->SetLoggedInState(logged_in_state
, login_user_type
);
1695 void UserManagerImpl::SetLRUUser(User
* user
) {
1696 UserList::iterator it
= std::find(lru_logged_in_users_
.begin(),
1697 lru_logged_in_users_
.end(),
1699 if (it
!= lru_logged_in_users_
.end())
1700 lru_logged_in_users_
.erase(it
);
1701 lru_logged_in_users_
.insert(lru_logged_in_users_
.begin(), user
);
1704 void UserManagerImpl::OnRestoreActiveSessions(
1705 const SessionManagerClient::ActiveSessionsMap
& sessions
,
1708 LOG(ERROR
) << "Could not get list of active user sessions after crash.";
1709 // If we could not get list of active user sessions it is safer to just
1710 // sign out so that we don't get in the inconsistent state.
1711 DBusThreadManager::Get()->GetSessionManagerClient()->StopSession();
1715 // One profile has been already loaded on browser start.
1716 DCHECK(GetLoggedInUsers().size() == 1);
1717 DCHECK(GetActiveUser());
1718 std::string active_user_id
= GetActiveUser()->email();
1720 SessionManagerClient::ActiveSessionsMap::const_iterator it
;
1721 for (it
= sessions
.begin(); it
!= sessions
.end(); ++it
) {
1722 if (active_user_id
== it
->first
)
1724 pending_user_sessions_
[it
->first
] = it
->second
;
1726 RestorePendingUserSessions();
1729 void UserManagerImpl::RestorePendingUserSessions() {
1730 if (pending_user_sessions_
.empty()) {
1731 NotifyPendingUserSessionsRestoreFinished();
1735 // Get next user to restore sessions and delete it from list.
1736 SessionManagerClient::ActiveSessionsMap::const_iterator it
=
1737 pending_user_sessions_
.begin();
1738 std::string user_id
= it
->first
;
1739 std::string user_id_hash
= it
->second
;
1740 DCHECK(!user_id
.empty());
1741 DCHECK(!user_id_hash
.empty());
1742 pending_user_sessions_
.erase(user_id
);
1744 // Check that this user is not logged in yet.
1745 UserList logged_in_users
= GetLoggedInUsers();
1746 bool user_already_logged_in
= false;
1747 for (UserList::const_iterator it
= logged_in_users
.begin();
1748 it
!= logged_in_users
.end(); ++it
) {
1749 const User
* user
= (*it
);
1750 if (user
->email() == user_id
) {
1751 user_already_logged_in
= true;
1755 DCHECK(!user_already_logged_in
);
1757 if (!user_already_logged_in
) {
1758 // Will call OnProfilePrepared() once profile has been loaded.
1759 LoginUtils::Get()->PrepareProfile(UserContext(user_id
,
1760 std::string(), // password
1761 std::string(), // auth_code
1763 false), // using_oauth
1764 std::string(), // display_email
1765 false, // has_cookies
1766 true, // has_active_session
1769 RestorePendingUserSessions();
1773 void UserManagerImpl::SendRegularUserLoginMetrics(const std::string
& user_id
) {
1774 // If this isn't the first time Chrome was run after the system booted,
1775 // assume that Chrome was restarted because a previous session ended.
1776 if (!CommandLine::ForCurrentProcess()->HasSwitch(
1777 switches::kFirstExecAfterBoot
)) {
1778 const std::string last_email
=
1779 g_browser_process
->local_state()->GetString(kLastLoggedInRegularUser
);
1780 const base::TimeDelta time_to_login
=
1781 base::TimeTicks::Now() - manager_creation_time_
;
1782 if (!last_email
.empty() && user_id
!= last_email
&&
1783 time_to_login
.InSeconds() <= kLogoutToLoginDelayMaxSec
) {
1784 UMA_HISTOGRAM_CUSTOM_COUNTS("UserManager.LogoutToLoginDelay",
1785 time_to_login
.InSeconds(), 0, kLogoutToLoginDelayMaxSec
, 50);
1790 void UserManagerImpl::OnUserNotAllowed() {
1791 LOG(ERROR
) << "Shutdown session because a user is not allowed to be in the "
1793 chrome::AttemptUserExit();
1796 void UserManagerImpl::UpdateUserAccountLocale(const std::string
& user_id
,
1797 const std::string
& locale
) {
1798 if (!locale
.empty() &&
1799 locale
!= g_browser_process
->GetApplicationLocale()) {
1800 BrowserThread::PostBlockingPoolTask(
1802 base::Bind(ResolveLocale
, locale
,
1803 base::Bind(&UserManagerImpl::DoUpdateAccountLocale
,
1804 base::Unretained(this),
1807 DoUpdateAccountLocale(user_id
, locale
);
1811 void UserManagerImpl::DoUpdateAccountLocale(
1812 const std::string
& user_id
,
1813 const std::string
& resolved_locale
) {
1814 if (User
* user
= FindUserAndModify(user_id
))
1815 user
->SetAccountLocale(resolved_locale
);
1819 } // namespace chromeos