1 // Copyright 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/app_mode/kiosk_profile_loader.h"
7 #include "base/logging.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_util.h"
11 #include "base/sys_info.h"
12 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
13 #include "chrome/browser/chromeos/login/auth/login_status_consumer.h"
14 #include "chrome/browser/chromeos/login/auth/user_context.h"
15 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
16 #include "chrome/browser/chromeos/login/login_utils.h"
17 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
18 #include "chrome/browser/chromeos/login/users/user_manager.h"
19 #include "chrome/browser/chromeos/settings/cros_settings.h"
20 #include "chrome/browser/lifetime/application_lifetime.h"
21 #include "chromeos/cryptohome/async_method_caller.h"
22 #include "chromeos/dbus/cryptohome_client.h"
23 #include "chromeos/dbus/dbus_thread_manager.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "google_apis/gaia/gaia_auth_util.h"
27 using content::BrowserThread
;
33 KioskAppLaunchError::Error
LoginFailureToKioskAppLaunchError(
34 const LoginFailure
& error
) {
35 switch (error
.reason()) {
36 case LoginFailure::COULD_NOT_MOUNT_TMPFS
:
37 case LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME
:
38 return KioskAppLaunchError::UNABLE_TO_MOUNT
;
39 case LoginFailure::DATA_REMOVAL_FAILED
:
40 return KioskAppLaunchError::UNABLE_TO_REMOVE
;
41 case LoginFailure::USERNAME_HASH_FAILED
:
42 return KioskAppLaunchError::UNABLE_TO_RETRIEVE_HASH
;
45 return KioskAppLaunchError::UNABLE_TO_MOUNT
;
51 ////////////////////////////////////////////////////////////////////////////////
52 // KioskProfileLoader::CryptohomedChecker ensures cryptohome daemon is up
53 // and running by issuing an IsMounted call. If the call does not go through
54 // and chromeos::DBUS_METHOD_CALL_SUCCESS is not returned, it will retry after
55 // some time out and at the maximum five times before it gives up. Upon
56 // success, it resumes the launch by logging in as a kiosk mode account.
58 class KioskProfileLoader::CryptohomedChecker
59 : public base::SupportsWeakPtr
<CryptohomedChecker
> {
61 explicit CryptohomedChecker(KioskProfileLoader
* loader
)
65 ~CryptohomedChecker() {}
68 chromeos::DBusThreadManager::Get()->GetCryptohomeClient()->IsMounted(
69 base::Bind(&CryptohomedChecker::OnCryptohomeIsMounted
,
74 void OnCryptohomeIsMounted(chromeos::DBusMethodCallStatus call_status
,
76 if (call_status
!= chromeos::DBUS_METHOD_CALL_SUCCESS
) {
77 const int kMaxRetryTimes
= 5;
79 if (retry_count_
> kMaxRetryTimes
) {
80 LOG(ERROR
) << "Could not talk to cryptohomed for launching kiosk app.";
81 ReportCheckResult(KioskAppLaunchError::CRYPTOHOMED_NOT_RUNNING
);
85 const int retry_delay_in_milliseconds
= 500 * (1 << retry_count_
);
86 base::MessageLoop::current()->PostDelayedTask(
88 base::Bind(&CryptohomedChecker::StartCheck
, AsWeakPtr()),
89 base::TimeDelta::FromMilliseconds(retry_delay_in_milliseconds
));
94 LOG(ERROR
) << "Cryptohome is mounted before launching kiosk app.";
96 // Proceed only when cryptohome is not mounded or running on dev box.
97 if (!is_mounted
|| !base::SysInfo::IsRunningOnChromeOS())
98 ReportCheckResult(KioskAppLaunchError::NONE
);
100 ReportCheckResult(KioskAppLaunchError::ALREADY_MOUNTED
);
103 void ReportCheckResult(KioskAppLaunchError::Error error
) {
104 if (error
== KioskAppLaunchError::NONE
)
105 loader_
->LoginAsKioskAccount();
107 loader_
->ReportLaunchResult(error
);
110 KioskProfileLoader
* loader_
;
113 DISALLOW_COPY_AND_ASSIGN(CryptohomedChecker
);
117 ////////////////////////////////////////////////////////////////////////////////
118 // KioskProfileLoader
120 KioskProfileLoader::KioskProfileLoader(const std::string
& app_user_id
,
121 bool use_guest_mount
,
123 : user_id_(app_user_id
),
124 use_guest_mount_(use_guest_mount
),
125 delegate_(delegate
) {}
127 KioskProfileLoader::~KioskProfileLoader() {}
129 void KioskProfileLoader::Start() {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
131 login_performer_
.reset();
132 cryptohomed_checker_
.reset(new CryptohomedChecker(this));
133 cryptohomed_checker_
->StartCheck();
136 void KioskProfileLoader::LoginAsKioskAccount() {
137 login_performer_
.reset(new LoginPerformer(this));
138 login_performer_
->LoginAsKioskAccount(user_id_
, use_guest_mount_
);
141 void KioskProfileLoader::ReportLaunchResult(KioskAppLaunchError::Error error
) {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
144 if (error
!= KioskAppLaunchError::NONE
) {
145 delegate_
->OnProfileLoadFailed(error
);
149 void KioskProfileLoader::OnLoginSuccess(const UserContext
& user_context
) {
150 // LoginPerformer will delete itself.
151 login_performer_
->set_delegate(NULL
);
152 ignore_result(login_performer_
.release());
154 // If we are launching a demo session, we need to start MountGuest with the
155 // guest username; this is because there are several places in the cros code
156 // which rely on the username sent to cryptohome to be $guest. Back in Chrome
157 // we switch this back to the demo user name to correctly identify this
158 // user as a demo user.
159 UserContext context
= user_context
;
160 if (context
.GetUserID() == UserManager::kGuestUserName
)
161 context
.SetUserID(DemoAppLauncher::kDemoUserName
);
162 LoginUtils::Get()->PrepareProfile(context
,
163 std::string(), // display email
164 false, // has_cookies
165 false, // has_active_session
169 void KioskProfileLoader::OnLoginFailure(const LoginFailure
& error
) {
170 ReportLaunchResult(LoginFailureToKioskAppLaunchError(error
));
173 void KioskProfileLoader::WhiteListCheckFailed(const std::string
& email
) {
177 void KioskProfileLoader::PolicyLoadFailed() {
178 ReportLaunchResult(KioskAppLaunchError::POLICY_LOAD_FAILED
);
181 void KioskProfileLoader::OnOnlineChecked(
182 const std::string
& email
, bool success
) {
186 void KioskProfileLoader::OnProfilePrepared(Profile
* profile
) {
187 // This object could be deleted any time after successfully reporting
188 // a profile load, so invalidate the LoginUtils delegate now.
189 LoginUtils::Get()->DelegateDeleted(this);
191 delegate_
->OnProfileLoaded(profile
);
192 ReportLaunchResult(KioskAppLaunchError::NONE
);
195 } // namespace chromeos