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 using user_manager::UserManager; | |
31 using user_manager::User; | |
32 using user_manager::UserList; | |
33 | |
34 namespace { | |
35 | |
36 // Limits the number of logged in users to 10 due to memory constraints. | |
37 constexpr uint32_t kMaxUsers = 10; | |
38 | |
39 uint32_t GetSessionId(const User* user) { | |
40 const UserList logged_in_users = UserManager::Get()->GetLoggedInUsers(); | |
James Cook
2016/12/06 18:08:25
Just to double-check: This order in this list does
xiyuan
2016/12/06 19:24:21
Correct.
GetLoggedInUsers() reflects the order of
| |
41 // TODO(xiyuan): Update with real session id when user session tracking | |
42 // code is moved from UserManager to SessionManager. | |
43 for (size_t i = 0; i < logged_in_users.size(); ++i) { | |
44 if (logged_in_users[i] == user) | |
45 return i + 1; | |
46 } | |
47 | |
48 NOTREACHED(); | |
49 return 0u; | |
50 } | |
51 | |
52 ash::mojom::UserSessionPtr UserToUserSession(const User& user) { | |
53 ash::mojom::UserSessionPtr session = ash::mojom::UserSession::New(); | |
54 session->session_id = GetSessionId(&user); | |
55 session->type = user.GetType(); | |
56 // TODO(xiyuan): Add type map for AccountId. | |
57 session->account_id = user.GetAccountId().Serialize(); | |
58 session->display_name = base::UTF16ToUTF8(user.display_name()); | |
59 session->display_email = user.display_email(); | |
60 | |
61 // TODO(xiyuan): Observe user image change and update. | |
62 // Tracked in http://crbug.com/670422 | |
63 // TODO(xiyuan): Support multiple scale factor. | |
64 session->avatar = *user.GetImage().bitmap(); | |
65 if (session->avatar.isNull()) { | |
66 session->avatar = *ResourceBundle::GetSharedInstance() | |
67 .GetImageSkiaNamed(IDR_PROFILE_PICTURE_LOADING) | |
68 ->bitmap(); | |
69 } | |
70 | |
71 return session; | |
72 } | |
73 | |
74 void DoSwitchUser(const AccountId& account_id) { | |
75 UserManager::Get()->SwitchActiveUser(account_id); | |
76 } | |
77 | |
78 } // namespace | |
79 | |
80 SessionControllerClient::SessionControllerClient() : binding_(this) { | |
81 session_manager::SessionManager::Get()->AddObserver(this); | |
82 UserManager::Get()->AddSessionStateObserver(this); | |
83 | |
84 ConnectToSessionControllerAndSetClient(); | |
85 SendSessionInfoIfChanged(); | |
86 // User sessions and their order will be sent via UserSessionStateObserver | |
87 // even for crash-n-restart. | |
88 } | |
89 | |
90 SessionControllerClient::~SessionControllerClient() { | |
91 session_manager::SessionManager::Get()->RemoveObserver(this); | |
92 UserManager::Get()->RemoveSessionStateObserver(this); | |
93 } | |
94 | |
95 void SessionControllerClient::RequestLockScreen() { | |
96 DoLockScreen(); | |
97 } | |
98 | |
99 void SessionControllerClient::SwitchActiveUser( | |
100 const std::string& serialized_account_id) { | |
101 // TODO(xiyuan): Add type map for AccountId. | |
102 AccountId account_id(EmptyAccountId()); | |
103 if (!AccountId::Deserialize(serialized_account_id, &account_id)) { | |
104 LOG(ERROR) << "Bad account id for SwitchActiveUser."; | |
105 return; | |
106 } | |
107 | |
108 DoSwitchActiveUser(account_id); | |
109 } | |
110 | |
111 void SessionControllerClient::CycleActiveUser(bool next_user) { | |
112 DoCycleActiveUser(next_user); | |
113 } | |
114 | |
115 void SessionControllerClient::ActiveUserChanged(const User* active_user) { | |
116 SendSessionInfoIfChanged(); | |
117 | |
118 // UserAddedToSession is not called for the primary user session so send its | |
119 // meta data here once. | |
120 if (!primary_user_session_sent_ && | |
121 UserManager::Get()->GetPrimaryUser() == active_user) { | |
122 primary_user_session_sent_ = true; | |
123 SendUserSession(*active_user); | |
124 } | |
125 | |
126 SendUserSessionOrder(); | |
127 } | |
128 | |
129 void SessionControllerClient::UserAddedToSession(const User* added_user) { | |
130 SendSessionInfoIfChanged(); | |
131 SendUserSession(*added_user); | |
132 } | |
133 | |
134 // static | |
135 bool SessionControllerClient::CanLockScreen() { | |
136 return !UserManager::Get()->GetUnlockUsers().empty(); | |
137 } | |
138 | |
139 // static | |
140 bool SessionControllerClient::ShouldLockScreenAutomatically() { | |
141 // TODO(xiyuan): Observe prefs::kEnableAutoScreenLock and update ash. | |
142 // Tracked in http://crbug.com/670423 | |
143 const UserList logged_in_users = UserManager::Get()->GetLoggedInUsers(); | |
144 for (auto* user : logged_in_users) { | |
145 Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user); | |
146 if (profile && | |
147 profile->GetPrefs()->GetBoolean(prefs::kEnableAutoScreenLock)) { | |
148 return true; | |
149 } | |
150 } | |
151 return false; | |
152 } | |
153 | |
154 // static | |
155 ash::AddUserSessionPolicy SessionControllerClient::GetAddUserSessionPolicy() { | |
156 UserManager* const user_manager = UserManager::Get(); | |
157 if (user_manager->GetUsersAllowedForMultiProfile().empty()) | |
158 return ash::AddUserSessionPolicy::ERROR_NO_ELIGIBLE_USERS; | |
159 | |
160 if (chromeos::MultiProfileUserController::GetPrimaryUserPolicy() != | |
161 chromeos::MultiProfileUserController::ALLOWED) { | |
162 return ash::AddUserSessionPolicy::ERROR_NOT_ALLOWED_PRIMARY_USER; | |
163 } | |
164 | |
165 if (UserManager::Get()->GetLoggedInUsers().size() >= kMaxUsers) | |
166 return ash::AddUserSessionPolicy::ERROR_MAXIMUM_USERS_REACHED; | |
167 | |
168 return ash::AddUserSessionPolicy::ALLOWED; | |
169 } | |
170 | |
171 // static | |
172 void SessionControllerClient::DoLockScreen() { | |
173 if (!CanLockScreen()) | |
174 return; | |
175 | |
176 VLOG(1) << "Requesting screen lock from SessionControllerClient"; | |
177 chromeos::DBusThreadManager::Get() | |
178 ->GetSessionManagerClient() | |
179 ->RequestLockScreen(); | |
180 } | |
181 | |
182 // static | |
183 void SessionControllerClient::DoSwitchActiveUser(const AccountId& account_id) { | |
184 // Disallow switching to an already active user since that might crash. | |
185 // Also check that we got a user id and not an email address. | |
186 DCHECK_EQ( | |
187 account_id.GetUserEmail(), | |
188 gaia::CanonicalizeEmail(gaia::SanitizeEmail(account_id.GetUserEmail()))); | |
189 if (account_id == UserManager::Get()->GetActiveUser()->GetAccountId()) | |
190 return; | |
191 | |
192 TrySwitchingActiveUser(base::Bind(&DoSwitchUser, account_id)); | |
193 } | |
194 | |
195 // static | |
196 void SessionControllerClient::DoCycleActiveUser(bool next_user) { | |
197 const UserList& logged_in_users = UserManager::Get()->GetLoggedInUsers(); | |
198 if (logged_in_users.size() <= 1) | |
199 return; | |
200 | |
201 AccountId account_id = UserManager::Get()->GetActiveUser()->GetAccountId(); | |
202 | |
203 // Get an iterator positioned at the active user. | |
204 auto it = std::find_if(logged_in_users.begin(), logged_in_users.end(), | |
205 [account_id](const User* user) { | |
206 return user->GetAccountId() == account_id; | |
207 }); | |
208 | |
209 // Active user not found. | |
210 if (it == logged_in_users.end()) | |
211 return; | |
212 | |
213 // Get the user's email to select, wrapping to the start/end of the list if | |
214 // necessary. | |
215 if (next_user) { | |
216 if (++it == logged_in_users.end()) | |
217 account_id = (*logged_in_users.begin())->GetAccountId(); | |
218 else | |
219 account_id = (*it)->GetAccountId(); | |
220 } else { | |
221 if (it == logged_in_users.begin()) | |
222 it = logged_in_users.end(); | |
223 account_id = (*(--it))->GetAccountId(); | |
224 } | |
225 | |
226 DoSwitchActiveUser(account_id); | |
227 } | |
228 | |
229 void SessionControllerClient::OnSessionStateChanged() { | |
230 SendSessionInfoIfChanged(); | |
231 } | |
232 | |
233 void SessionControllerClient::ConnectToSessionControllerAndSetClient() { | |
234 service_manager::Connector* connector = | |
235 content::ServiceManagerConnection::GetForProcess()->GetConnector(); | |
236 | |
237 // Under mash the SessionController interface is in the ash process. In | |
238 // classic ash we provide it to ourself. | |
239 if (chrome::IsRunningInMash()) { | |
240 connector->ConnectToInterface("ash", &session_controller_); | |
241 } else { | |
242 connector->ConnectToInterface(content::mojom::kBrowserServiceName, | |
243 &session_controller_); | |
244 } | |
245 | |
246 // Set as |session_controller_|'s client. | |
247 session_controller_->SetClient(binding_.CreateInterfacePtrAndBind()); | |
248 } | |
249 | |
250 void SessionControllerClient::SendSessionInfoIfChanged() { | |
251 ash::mojom::SessionInfoPtr info = ash::mojom::SessionInfo::New(); | |
252 info->max_users = kMaxUsers; | |
253 info->can_lock_screen = CanLockScreen(); | |
254 info->should_lock_screen_automatically = ShouldLockScreenAutomatically(); | |
255 info->add_user_session_policy = GetAddUserSessionPolicy(); | |
256 info->state = session_manager::SessionManager::Get()->session_state(); | |
257 | |
258 if (info != last_sent_session_info_) { | |
259 last_sent_session_info_ = info->Clone(); | |
260 session_controller_->SetSessionInfo(std::move(info)); | |
261 } | |
262 } | |
263 | |
264 void SessionControllerClient::SendUserSession(const User& user) { | |
265 session_controller_->UpdateUserSession(UserToUserSession(user)); | |
266 } | |
267 | |
268 void SessionControllerClient::SendUserSessionOrder() { | |
269 UserManager* const user_manager = UserManager::Get(); | |
270 | |
271 const UserList logged_in_users = user_manager->GetLoggedInUsers(); | |
272 std::vector<uint32_t> order; | |
273 for (auto* user : user_manager->GetLRULoggedInUsers()) | |
274 order.push_back(GetSessionId(user)); | |
275 | |
276 ConnectToSessionControllerAndSetClient(); | |
James Cook
2016/12/06 18:08:25
Do you need this? You're not calling it in the oth
xiyuan
2016/12/06 19:24:21
Nope. Left overs from refactoring. Removed now.
| |
277 session_controller_->SetUserSessionOrder(order); | |
278 } | |
OLD | NEW |