forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsession_controller.cc
407 lines (328 loc) · 12.8 KB
/
session_controller.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/session/session_controller.h"
#include <algorithm>
#include <utility>
#include "ash/public/interfaces/user_info.mojom.h"
#include "ash/session/session_observer.h"
#include "ash/shell.h"
#include "ash/system/power/power_event_observer.h"
#include "ash/wm/lock_state_controller.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "chromeos/chromeos_switches.h"
#include "components/signin/core/account_id/account_id.h"
#include "components/user_manager/user_type.h"
#include "services/service_manager/public/cpp/connector.h"
using session_manager::SessionState;
namespace ash {
namespace {
// Get the default session state. Default session state is ACTIVE when the
// process starts with a user session, i.e. the process has kLoginUser command
// line switch. This is needed because ash focus rules depends on whether
// session is blocked to pick an activatable window and chrome needs to create a
// focused browser window when starting with a user session (both in production
// and in tests). Using ACTIVE as default in this situation allows chrome to run
// without having to wait for session state to reach to ash. For other cases
// (oobe/login), there is only one login window. The login window always gets
// focus so default session state does not matter. Use UNKNOWN and wait for
// chrome to update ash for such cases.
SessionState GetDefaultSessionState() {
const bool start_with_user =
base::CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kLoginUser);
return start_with_user ? SessionState::ACTIVE : SessionState::UNKNOWN;
}
} // namespace
SessionController::SessionController()
: state_(GetDefaultSessionState()), weak_ptr_factory_(this) {}
SessionController::~SessionController() {
// Abort pending start lock request.
if (!start_lock_callback_.is_null())
std::move(start_lock_callback_).Run(false /* locked */);
}
void SessionController::BindRequest(mojom::SessionControllerRequest request) {
bindings_.AddBinding(this, std::move(request));
}
int SessionController::NumberOfLoggedInUsers() const {
return static_cast<int>(user_sessions_.size());
}
AddUserSessionPolicy SessionController::GetAddUserPolicy() const {
return add_user_session_policy_;
}
bool SessionController::IsActiveUserSessionStarted() const {
return !user_sessions_.empty();
}
bool SessionController::CanLockScreen() const {
return IsActiveUserSessionStarted() && can_lock_;
}
bool SessionController::IsScreenLocked() const {
return state_ == SessionState::LOCKED;
}
bool SessionController::ShouldLockScreenAutomatically() const {
return should_lock_screen_automatically_;
}
bool SessionController::IsUserSessionBlocked() const {
// User sessions are blocked when session state is not ACTIVE, with two
// exceptions:
// - LOGGED_IN_NOT_ACTIVE state. This is needed so that browser windows
// created by session restore (or a default new browser window) are properly
// activated before session state changes to ACTIVE.
// - LOCKED state with a running unlocking animation. This is needed because
// the unlocking animation hides the lock container at the end. During the
// unlock animation, IsUserSessionBlocked needs to return unblocked so that
// user windows are deemed activatable and ash correctly restores the active
// window before locking.
return state_ != SessionState::ACTIVE &&
state_ != SessionState::LOGGED_IN_NOT_ACTIVE &&
!(state_ == SessionState::LOCKED && is_unlocking_);
}
bool SessionController::IsInSecondaryLoginScreen() const {
return state_ == SessionState::LOGIN_SECONDARY;
}
SessionState SessionController::GetSessionState() const {
return state_;
}
bool SessionController::ShouldEnableSettings() const {
// Settings opens a web UI window, so it is not available at the lock screen.
if (!IsActiveUserSessionStarted() || IsScreenLocked() ||
IsInSecondaryLoginScreen()) {
return false;
}
return user_sessions_[0]->should_enable_settings;
}
bool SessionController::ShouldShowNotificationTray() const {
if (!IsActiveUserSessionStarted() || IsInSecondaryLoginScreen())
return false;
return user_sessions_[0]->should_show_notification_tray;
}
const std::vector<mojom::UserSessionPtr>& SessionController::GetUserSessions()
const {
return user_sessions_;
}
const mojom::UserSession* SessionController::GetUserSession(
UserIndex index) const {
if (index < 0 || index >= static_cast<UserIndex>(user_sessions_.size()))
return nullptr;
return user_sessions_[index].get();
}
bool SessionController::IsUserSupervised() const {
if (!IsActiveUserSessionStarted())
return false;
user_manager::UserType active_user_type = GetUserSession(0)->user_info->type;
return active_user_type == user_manager::USER_TYPE_SUPERVISED ||
active_user_type == user_manager::USER_TYPE_CHILD;
}
bool SessionController::IsUserChild() const {
if (!IsActiveUserSessionStarted())
return false;
user_manager::UserType active_user_type = GetUserSession(0)->user_info->type;
return active_user_type == user_manager::USER_TYPE_CHILD;
}
bool SessionController::IsKioskSession() const {
if (!IsActiveUserSessionStarted())
return false;
user_manager::UserType active_user_type = GetUserSession(0)->user_info->type;
return active_user_type == user_manager::USER_TYPE_KIOSK_APP ||
active_user_type == user_manager::USER_TYPE_ARC_KIOSK_APP;
}
void SessionController::LockScreen() {
if (client_)
client_->RequestLockScreen();
}
void SessionController::SwitchActiveUser(const AccountId& account_id) {
if (client_)
client_->SwitchActiveUser(account_id);
}
void SessionController::CycleActiveUser(CycleUserDirection direction) {
if (client_)
client_->CycleActiveUser(direction);
}
void SessionController::AddObserver(SessionObserver* observer) {
observers_.AddObserver(observer);
}
void SessionController::RemoveObserver(SessionObserver* observer) {
observers_.RemoveObserver(observer);
}
void SessionController::SetClient(mojom::SessionControllerClientPtr client) {
client_ = std::move(client);
}
void SessionController::SetSessionInfo(mojom::SessionInfoPtr info) {
can_lock_ = info->can_lock_screen;
should_lock_screen_automatically_ = info->should_lock_screen_automatically;
add_user_session_policy_ = info->add_user_session_policy;
SetSessionState(info->state);
}
void SessionController::UpdateUserSession(mojom::UserSessionPtr user_session) {
auto it =
std::find_if(user_sessions_.begin(), user_sessions_.end(),
[&user_session](const mojom::UserSessionPtr& session) {
return session->session_id == user_session->session_id;
});
if (it == user_sessions_.end()) {
AddUserSession(std::move(user_session));
return;
}
*it = std::move(user_session);
for (auto& observer : observers_)
observer.OnUserSessionUpdated((*it)->user_info->account_id);
UpdateLoginStatus();
}
void SessionController::SetUserSessionOrder(
const std::vector<uint32_t>& user_session_order) {
DCHECK_EQ(user_sessions_.size(), user_session_order.size());
// Adjusts |user_sessions_| to match the given order.
std::vector<mojom::UserSessionPtr> sessions;
for (const auto& session_id : user_session_order) {
auto it =
std::find_if(user_sessions_.begin(), user_sessions_.end(),
[session_id](const mojom::UserSessionPtr& session) {
return session && session->session_id == session_id;
});
if (it == user_sessions_.end()) {
LOG(ERROR) << "Unknown session id =" << session_id;
continue;
}
sessions.push_back(std::move(*it));
}
user_sessions_.swap(sessions);
// Check active user change and notifies observers.
if (user_sessions_[0]->session_id != active_session_id_) {
active_session_id_ = user_sessions_[0]->session_id;
for (auto& observer : observers_) {
observer.OnActiveUserSessionChanged(
user_sessions_[0]->user_info->account_id);
}
UpdateLoginStatus();
}
}
void SessionController::StartLock(StartLockCallback callback) {
DCHECK(start_lock_callback_.is_null());
start_lock_callback_ = std::move(callback);
LockStateController* const lock_state_controller =
Shell::Get()->lock_state_controller();
lock_state_controller->SetLockScreenDisplayedCallback(
base::Bind(&SessionController::OnLockAnimationFinished,
weak_ptr_factory_.GetWeakPtr()));
lock_state_controller->OnStartingLock();
}
void SessionController::NotifyChromeLockAnimationsComplete() {
Shell::Get()->power_event_observer()->OnLockAnimationsComplete();
}
void SessionController::RunUnlockAnimation(
RunUnlockAnimationCallback callback) {
is_unlocking_ = true;
// Shell could have no instance in tests.
if (Shell::HasInstance())
Shell::Get()->lock_state_controller()->OnLockScreenHide(
std::move(callback));
}
void SessionController::NotifyChromeTerminating() {
for (auto& observer : observers_)
observer.OnChromeTerminating();
}
void SessionController::SetSessionLengthLimit(base::TimeDelta length_limit,
base::TimeTicks start_time) {
session_length_limit_ = length_limit;
session_start_time_ = start_time;
for (auto& observer : observers_)
observer.OnSessionLengthLimitChanged();
}
void SessionController::ClearUserSessionsForTest() {
user_sessions_.clear();
}
void SessionController::FlushMojoForTest() {
client_.FlushForTesting();
}
void SessionController::LockScreenAndFlushForTest() {
LockScreen();
FlushMojoForTest();
}
void SessionController::SetSessionState(SessionState state) {
if (state_ == state)
return;
const bool was_locked = state_ == SessionState::LOCKED;
state_ = state;
for (auto& observer : observers_)
observer.OnSessionStateChanged(state_);
UpdateLoginStatus();
const bool locked = state_ == SessionState::LOCKED;
if (was_locked != locked) {
if (!locked)
is_unlocking_ = false;
for (auto& observer : observers_)
observer.OnLockStateChanged(locked);
}
}
void SessionController::AddUserSession(mojom::UserSessionPtr user_session) {
const AccountId account_id(user_session->user_info->account_id);
user_sessions_.push_back(std::move(user_session));
for (auto& observer : observers_)
observer.OnUserSessionAdded(account_id);
}
LoginStatus SessionController::CalculateLoginStatus() const {
// TODO(jamescook|xiyuan): There is not a 1:1 mapping of SessionState to
// LoginStatus. Fix the cases that don't match. http://crbug.com/701193
switch (state_) {
case SessionState::UNKNOWN:
case SessionState::OOBE:
case SessionState::LOGIN_PRIMARY:
case SessionState::LOGGED_IN_NOT_ACTIVE:
return LoginStatus::NOT_LOGGED_IN;
case SessionState::ACTIVE:
return CalculateLoginStatusForActiveSession();
case SessionState::LOCKED:
return LoginStatus::LOCKED;
case SessionState::LOGIN_SECONDARY:
// TODO: There is no LoginStatus for this.
return LoginStatus::USER;
}
NOTREACHED();
return LoginStatus::NOT_LOGGED_IN;
}
LoginStatus SessionController::CalculateLoginStatusForActiveSession() const {
DCHECK(state_ == SessionState::ACTIVE);
if (user_sessions_.empty()) // Can be empty in tests.
return LoginStatus::USER;
switch (user_sessions_[0]->user_info->type) {
case user_manager::USER_TYPE_REGULAR:
// TODO: This needs to distinguish between owner and non-owner.
return LoginStatus::USER;
case user_manager::USER_TYPE_GUEST:
return LoginStatus::GUEST;
case user_manager::USER_TYPE_PUBLIC_ACCOUNT:
return LoginStatus::PUBLIC;
case user_manager::USER_TYPE_SUPERVISED:
return LoginStatus::SUPERVISED;
case user_manager::USER_TYPE_KIOSK_APP:
return LoginStatus::KIOSK_APP;
case user_manager::USER_TYPE_CHILD:
return LoginStatus::SUPERVISED;
case user_manager::USER_TYPE_ARC_KIOSK_APP:
return LoginStatus::ARC_KIOSK_APP;
case user_manager::USER_TYPE_ACTIVE_DIRECTORY:
// TODO: There is no LoginStatus for this.
return LoginStatus::USER;
case user_manager::NUM_USER_TYPES:
// Avoid having a "default" case so the compiler catches new enum values.
NOTREACHED();
return LoginStatus::USER;
}
NOTREACHED();
return LoginStatus::USER;
}
void SessionController::UpdateLoginStatus() {
const LoginStatus new_login_status = CalculateLoginStatus();
if (new_login_status == login_status_)
return;
login_status_ = new_login_status;
for (auto& observer : observers_)
observer.OnLoginStatusChanged(login_status_);
}
void SessionController::OnLockAnimationFinished() {
if (!start_lock_callback_.is_null())
std::move(start_lock_callback_).Run(true /* locked */);
}
} // namespace ash