Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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/ui/ash/session_controller_client.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <utility> | |
| 9 | |
| 10 #include "ash/public/cpp/session_types.h" | |
| 11 #include "base/bind.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/strings/utf_string_conversions.h" | |
| 14 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h" | |
| 15 #include "chrome/browser/chromeos/profiles/profile_helper.h" | |
| 16 #include "chrome/browser/profiles/profile.h" | |
| 17 #include "chrome/browser/ui/ash/ash_util.h" | |
| 18 #include "chrome/browser/ui/ash/multi_user/user_switch_util.h" | |
| 19 #include "chrome/common/pref_names.h" | |
| 20 #include "chrome/grit/theme_resources.h" | |
| 21 #include "chromeos/dbus/dbus_thread_manager.h" | |
| 22 #include "chromeos/dbus/session_manager_client.h" | |
| 23 #include "components/prefs/pref_service.h" | |
| 24 #include "components/session_manager/core/session_manager.h" | |
| 25 #include "content/public/common/service_manager_connection.h" | |
| 26 #include "content/public/common/service_names.mojom.h" | |
| 27 #include "services/service_manager/public/cpp/connector.h" | |
| 28 #include "ui/base/resource/resource_bundle.h" | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 // Limits the number of logged in users to 10 due to memory constraints. | |
| 33 constexpr uint32_t kMaxUsers = 10; | |
| 34 | |
| 35 SessionControllerClient* instance = nullptr; | |
|
James Cook
2016/12/01 23:01:44
nit: I like g_instance for these.
xiyuan
2016/12/06 00:46:34
No longer needed and removed.
| |
| 36 | |
| 37 std::vector<ash::mojom::UserSessionPtr> GetUserSessions() { | |
| 38 user_manager::UserManager* const user_manager = | |
| 39 user_manager::UserManager::Get(); | |
| 40 | |
| 41 std::vector<ash::mojom::UserSessionPtr> sessions; | |
| 42 for (auto* user : user_manager->GetLRULoggedInUsers()) { | |
| 43 ash::mojom::UserSessionPtr session = ash::mojom::UserSession::New(); | |
| 44 session->type = user->GetType(); | |
| 45 // TODO(xiyuan): Add type map for AccountId. | |
| 46 session->account_id = user->GetAccountId().Serialize(); | |
| 47 session->display_name = base::UTF16ToUTF8(user->display_name()); | |
| 48 session->display_email = user->display_email(); | |
| 49 | |
| 50 // TODO(xiyuan): Observe user image change and update. | |
| 51 // Tracked in http://crbug.com/670422 | |
| 52 // TODO(xiyuan): Support multiple scale factor. | |
| 53 session->avatar = *user->GetImage().bitmap(); | |
| 54 if (session->avatar.isNull()) { | |
| 55 session->avatar = *ResourceBundle::GetSharedInstance() | |
| 56 .GetImageSkiaNamed(IDR_PROFILE_PICTURE_LOADING) | |
| 57 ->bitmap(); | |
| 58 } | |
| 59 | |
| 60 sessions.push_back(std::move(session)); | |
| 61 } | |
| 62 return sessions; | |
| 63 } | |
| 64 | |
| 65 void DoSwitchUser(const AccountId& account_id) { | |
| 66 user_manager::UserManager::Get()->SwitchActiveUser(account_id); | |
| 67 } | |
| 68 | |
| 69 } // namespace | |
| 70 | |
| 71 SessionControllerClient::SessionControllerClient() : binding_(this) { | |
| 72 DCHECK(!instance); | |
| 73 instance = this; | |
| 74 | |
| 75 session_manager::SessionManager::Get()->AddObserver(this); | |
| 76 user_manager::UserManager::Get()->AddSessionStateObserver(this); | |
| 77 | |
| 78 SendSessionInfo(); | |
| 79 } | |
| 80 | |
| 81 SessionControllerClient::~SessionControllerClient() { | |
| 82 DCHECK_EQ(this, instance); | |
| 83 instance = nullptr; | |
| 84 | |
| 85 session_manager::SessionManager::Get()->RemoveObserver(this); | |
| 86 user_manager::UserManager::Get()->RemoveSessionStateObserver(this); | |
| 87 } | |
| 88 | |
| 89 SessionControllerClient* SessionControllerClient::Get() { | |
| 90 return instance; | |
| 91 } | |
| 92 | |
| 93 void SessionControllerClient::RequestLockScreen() { | |
| 94 DoLockScreen(); | |
| 95 } | |
| 96 | |
| 97 void SessionControllerClient::SwitchActiveUser( | |
| 98 const std::string& serialized_account_id) { | |
| 99 // TODO(xiyuan): Add type map for AccountId. | |
| 100 AccountId account_id(EmptyAccountId()); | |
| 101 if (!AccountId::Deserialize(serialized_account_id, &account_id)) { | |
| 102 LOG(ERROR) << "Bad account id for SwitchActiveUser."; | |
| 103 return; | |
| 104 } | |
| 105 | |
| 106 DoSwitchActiveUser(account_id); | |
| 107 } | |
| 108 | |
| 109 void SessionControllerClient::CycleActiveUser(bool next_user) { | |
| 110 DoCycleActiveUser(next_user); | |
| 111 } | |
| 112 | |
| 113 void SessionControllerClient::ActiveUserChanged( | |
| 114 const user_manager::User* active_user) { | |
| 115 SendSessionInfo(); | |
| 116 } | |
| 117 | |
| 118 void SessionControllerClient::UserAddedToSession( | |
| 119 const user_manager::User* added_user) { | |
| 120 SendSessionInfo(); | |
| 121 } | |
| 122 | |
| 123 // static | |
| 124 bool SessionControllerClient::CanLockScreen() { | |
| 125 return !user_manager::UserManager::Get()->GetUnlockUsers().empty(); | |
| 126 } | |
| 127 | |
| 128 // static | |
| 129 bool SessionControllerClient::ShouldLockScreenAutomatically() { | |
| 130 // TODO(xiyuan): Observe prefs::kEnableAutoScreenLock and update ash. | |
| 131 // Tracked in http://crbug.com/670423 | |
| 132 const user_manager::UserList logged_in_users = | |
| 133 user_manager::UserManager::Get()->GetLoggedInUsers(); | |
| 134 for (auto* user : logged_in_users) { | |
| 135 Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user); | |
| 136 if (profile && | |
| 137 profile->GetPrefs()->GetBoolean(prefs::kEnableAutoScreenLock)) { | |
| 138 return true; | |
| 139 } | |
| 140 } | |
| 141 return false; | |
| 142 } | |
| 143 | |
| 144 // static | |
| 145 ash::AddUserSessionPolicy SessionControllerClient::GetAddUserSessionPolicy() { | |
| 146 user_manager::UserManager* const user_manager = | |
|
James Cook
2016/12/01 23:01:44
optional: Feel free to add "using user_manager::Us
xiyuan
2016/12/06 00:46:34
Done. And using user_manager::UserList and User as
| |
| 147 user_manager::UserManager::Get(); | |
| 148 if (user_manager->GetUsersAllowedForMultiProfile().empty()) | |
| 149 return ash::AddUserSessionPolicy::ERROR_NO_ELIGIBLE_USERS; | |
| 150 | |
| 151 if (chromeos::MultiProfileUserController::GetPrimaryUserPolicy() != | |
| 152 chromeos::MultiProfileUserController::ALLOWED) { | |
| 153 return ash::AddUserSessionPolicy::ERROR_NOT_ALLOWED_PRIMARY_USER; | |
| 154 } | |
| 155 | |
| 156 if (user_manager::UserManager::Get()->GetLoggedInUsers().size() >= kMaxUsers) | |
| 157 return ash::AddUserSessionPolicy::ERROR_MAXIMUM_USERS_REACHED; | |
| 158 | |
| 159 return ash::AddUserSessionPolicy::ALLOWED; | |
| 160 } | |
| 161 | |
| 162 // static | |
| 163 void SessionControllerClient::DoLockScreen() { | |
| 164 if (!CanLockScreen()) | |
| 165 return; | |
| 166 | |
| 167 VLOG(1) << "Requesting screen lock from SessionControllerClient"; | |
| 168 chromeos::DBusThreadManager::Get() | |
| 169 ->GetSessionManagerClient() | |
| 170 ->RequestLockScreen(); | |
| 171 } | |
| 172 | |
| 173 // static | |
| 174 void SessionControllerClient::DoSwitchActiveUser(const AccountId& account_id) { | |
| 175 // Disallow switching to an already active user since that might crash. | |
| 176 // Also check that we got a user id and not an email address. | |
| 177 DCHECK_EQ( | |
| 178 account_id.GetUserEmail(), | |
| 179 gaia::CanonicalizeEmail(gaia::SanitizeEmail(account_id.GetUserEmail()))); | |
| 180 if (account_id == | |
| 181 user_manager::UserManager::Get()->GetActiveUser()->GetAccountId()) { | |
| 182 return; | |
| 183 } | |
| 184 | |
| 185 TrySwitchingActiveUser(base::Bind(&DoSwitchUser, account_id)); | |
| 186 } | |
| 187 | |
| 188 // static | |
| 189 void SessionControllerClient::DoCycleActiveUser(bool next_user) { | |
| 190 const user_manager::UserList& logged_in_users = | |
| 191 user_manager::UserManager::Get()->GetLoggedInUsers(); | |
| 192 if (logged_in_users.size() <= 1) | |
| 193 return; | |
| 194 | |
| 195 AccountId account_id = | |
| 196 user_manager::UserManager::Get()->GetActiveUser()->GetAccountId(); | |
| 197 | |
| 198 // Get an iterator positioned at the active user. | |
| 199 auto it = std::find_if(logged_in_users.begin(), logged_in_users.end(), | |
| 200 [account_id](const user_manager::User* user) { | |
| 201 return user->GetAccountId() == account_id; | |
| 202 }); | |
| 203 | |
| 204 // Active user not found. | |
| 205 if (it == logged_in_users.end()) | |
| 206 return; | |
| 207 | |
| 208 // Get the user's email to select, wrapping to the start/end of the list if | |
| 209 // necessary. | |
| 210 if (next_user) { | |
| 211 if (++it == logged_in_users.end()) | |
| 212 account_id = (*logged_in_users.begin())->GetAccountId(); | |
| 213 else | |
| 214 account_id = (*it)->GetAccountId(); | |
| 215 } else { | |
| 216 if (it == logged_in_users.begin()) | |
| 217 it = logged_in_users.end(); | |
| 218 account_id = (*(--it))->GetAccountId(); | |
| 219 } | |
| 220 | |
| 221 DoSwitchActiveUser(account_id); | |
| 222 } | |
| 223 | |
| 224 void SessionControllerClient::OnSessionStateChanged() { | |
| 225 SendSessionInfo(); | |
| 226 } | |
| 227 | |
| 228 void SessionControllerClient::ConnectToSessionControllerAndSetClient() { | |
| 229 if (session_controller_.is_bound()) | |
| 230 return; | |
| 231 | |
| 232 service_manager::Connector* connector = | |
| 233 content::ServiceManagerConnection::GetForProcess()->GetConnector(); | |
| 234 | |
| 235 // Under mash the SessionController interface is in the ash process. In | |
| 236 // classic ash we provide it to ourself. | |
| 237 if (chrome::IsRunningInMash()) { | |
| 238 connector->ConnectToInterface("ash", &session_controller_); | |
| 239 } else { | |
| 240 connector->ConnectToInterface(content::mojom::kBrowserServiceName, | |
| 241 &session_controller_); | |
| 242 } | |
| 243 | |
| 244 // Tolerate ash crashing and coming back up. | |
|
James Cook
2016/12/01 23:01:44
Aside: This is fine, but for version 1 (and maybe
xiyuan
2016/12/06 00:46:34
Removed.
| |
| 245 session_controller_.set_connection_error_handler( | |
| 246 base::Bind(&SessionControllerClient::OnClientConnectionError, | |
| 247 base::Unretained(this))); | |
| 248 | |
| 249 // Set as |session_controller_|'s client. | |
| 250 session_controller_->SetClient(binding_.CreateInterfacePtrAndBind()); | |
| 251 } | |
| 252 | |
| 253 void SessionControllerClient::OnClientConnectionError() { | |
| 254 session_controller_.reset(); | |
| 255 } | |
| 256 | |
| 257 void SessionControllerClient::SendSessionInfo() { | |
| 258 ConnectToSessionControllerAndSetClient(); | |
| 259 | |
| 260 session_controller_->SetMaxUsers(kMaxUsers); | |
| 261 session_controller_->SetSessionState( | |
| 262 session_manager::SessionManager::Get()->session_state()); | |
| 263 session_controller_->SetCanLockScreen(CanLockScreen()); | |
| 264 session_controller_->SetShouldLockScreenAutomatically( | |
| 265 ShouldLockScreenAutomatically()); | |
| 266 session_controller_->SetAddUserSessionPolicy(GetAddUserSessionPolicy()); | |
| 267 session_controller_->SetUserSessions(GetUserSessions()); | |
|
James Cook
2016/12/01 23:01:44
Hmm, that's a lot of IPCs for a single state chang
xiyuan
2016/12/06 00:46:34
Changed.
- Combined simple info into a SessionInfo
| |
| 268 } | |
| OLD | NEW |