• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/chromeos/login/login_utils.h"
6 
7 #include <vector>
8 
9 #include "base/command_line.h"
10 #include "base/file_path.h"
11 #include "base/file_util.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/memory/singleton.h"
14 #include "base/path_service.h"
15 #include "base/string_util.h"
16 #include "base/stringprintf.h"
17 #include "base/synchronization/lock.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "base/time.h"
20 #include "base/utf_string_conversions.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/chromeos/boot_times_loader.h"
23 #include "chrome/browser/chromeos/cros/login_library.h"
24 #include "chrome/browser/chromeos/cros/network_library.h"
25 #include "chrome/browser/chromeos/input_method/input_method_util.h"
26 #include "chrome/browser/chromeos/login/background_view.h"
27 #include "chrome/browser/chromeos/login/cookie_fetcher.h"
28 #include "chrome/browser/chromeos/login/google_authenticator.h"
29 #include "chrome/browser/chromeos/login/language_switch_menu.h"
30 #include "chrome/browser/chromeos/login/ownership_service.h"
31 #include "chrome/browser/chromeos/login/parallel_authenticator.h"
32 #include "chrome/browser/chromeos/login/user_image_downloader.h"
33 #include "chrome/browser/chromeos/login/user_manager.h"
34 #include "chrome/browser/chromeos/proxy_config_service.h"
35 #include "chrome/browser/extensions/extension_service.h"
36 #include "chrome/browser/net/chrome_url_request_context.h"
37 #include "chrome/browser/net/gaia/token_service.h"
38 #include "chrome/browser/net/preconnect.h"
39 #include "chrome/browser/net/pref_proxy_config_service.h"
40 #include "chrome/browser/plugin_updater.h"
41 #include "chrome/browser/prefs/pref_member.h"
42 #include "chrome/browser/profiles/profile.h"
43 #include "chrome/browser/profiles/profile_manager.h"
44 #include "chrome/browser/sync/profile_sync_service.h"
45 #include "chrome/browser/ui/browser_init.h"
46 #include "chrome/common/chrome_paths.h"
47 #include "chrome/common/chrome_switches.h"
48 #include "chrome/common/logging_chrome.h"
49 #include "chrome/common/net/gaia/gaia_auth_fetcher.h"
50 #include "chrome/common/net/gaia/gaia_constants.h"
51 #include "chrome/common/pref_names.h"
52 #include "chrome/common/url_constants.h"
53 #include "content/browser/browser_thread.h"
54 #include "googleurl/src/gurl.h"
55 #include "net/base/cookie_store.h"
56 #include "net/proxy/proxy_config_service.h"
57 #include "net/url_request/url_request_context.h"
58 #include "net/url_request/url_request_context_getter.h"
59 #include "views/widget/widget_gtk.h"
60 #include "ui/gfx/gl/gl_switches.h"
61 
62 namespace chromeos {
63 
64 namespace {
65 
66 // Affixes for Auth token received from ClientLogin request.
67 const char kAuthPrefix[] = "Auth=";
68 const char kAuthSuffix[] = "\n";
69 
70 // Increase logging level for Guest mode to avoid LOG(INFO) messages in logs.
71 const char kGuestModeLoggingLevel[] = "1";
72 
73 // Format of command line switch.
74 const char kSwitchFormatString[] = " --%s=\"%s\"";
75 
76 // User name which is used in the Guest session.
77 const char kGuestUserName[] = "";
78 
79 // Resets the proxy configuration service for the default request context.
80 class ResetDefaultProxyConfigServiceTask : public Task {
81  public:
ResetDefaultProxyConfigServiceTask(net::ProxyConfigService * proxy_config_service)82   ResetDefaultProxyConfigServiceTask(
83       net::ProxyConfigService* proxy_config_service)
84       : proxy_config_service_(proxy_config_service) {}
~ResetDefaultProxyConfigServiceTask()85   virtual ~ResetDefaultProxyConfigServiceTask() {}
86 
87   // Task override.
Run()88   virtual void Run() {
89     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
90     net::URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
91     DCHECK(getter);
92     if (getter) {
93       getter->GetURLRequestContext()->proxy_service()->ResetConfigService(
94           proxy_config_service_.release());
95     }
96   }
97 
98  private:
99   scoped_ptr<net::ProxyConfigService> proxy_config_service_;
100 
101   DISALLOW_COPY_AND_ASSIGN(ResetDefaultProxyConfigServiceTask);
102 };
103 
104 }  // namespace
105 
106 class LoginUtilsImpl : public LoginUtils,
107                        public ProfileManager::Observer {
108  public:
LoginUtilsImpl()109   LoginUtilsImpl()
110       : background_view_(NULL) {
111   }
112 
113   virtual void PrepareProfile(
114       const std::string& username,
115       const std::string& password,
116       const GaiaAuthConsumer::ClientLoginResult& credentials,
117       bool pending_requests,
118       LoginUtils::Delegate* delegate);
119 
120   // Invoked after the tmpfs is successfully mounted.
121   // Launches a browser in the incognito mode.
122   virtual void CompleteOffTheRecordLogin(const GURL& start_url);
123 
124   // Invoked when the user is logging in for the first time, or is logging in as
125   // a guest user.
126   virtual void SetFirstLoginPrefs(PrefService* prefs);
127 
128   // Creates and returns the authenticator to use. The caller owns the returned
129   // Authenticator and must delete it when done.
130   virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer);
131 
132   // Warms the url used by authentication.
133   virtual void PrewarmAuthentication();
134 
135   // Given the credentials try to exchange them for
136   // full-fledged Google authentication cookies.
137   virtual void FetchCookies(
138       Profile* profile,
139       const GaiaAuthConsumer::ClientLoginResult& credentials);
140 
141   // Supply credentials for sync and others to use.
142   virtual void FetchTokens(
143       Profile* profile,
144       const GaiaAuthConsumer::ClientLoginResult& credentials);
145 
146   // Sets the current background view.
147   virtual void SetBackgroundView(chromeos::BackgroundView* background_view);
148 
149   // Gets the current background view.
150   virtual chromeos::BackgroundView* GetBackgroundView();
151 
152   // ProfileManager::Observer implementation:
153   virtual void OnProfileCreated(Profile* profile);
154 
155  protected:
156   virtual std::string GetOffTheRecordCommandLine(
157       const GURL& start_url,
158       const CommandLine& base_command_line,
159       CommandLine *command_line);
160 
161  private:
162   // Check user's profile for kApplicationLocale setting.
163   void RespectLocalePreference(Profile* pref);
164 
165   // The current background view.
166   chromeos::BackgroundView* background_view_;
167 
168   std::string username_;
169   std::string password_;
170   GaiaAuthConsumer::ClientLoginResult credentials_;
171   bool pending_requests_;
172 
173   // Delegate to be fired when the profile will be prepared.
174   LoginUtils::Delegate* delegate_;
175 
176   DISALLOW_COPY_AND_ASSIGN(LoginUtilsImpl);
177 };
178 
179 class LoginUtilsWrapper {
180  public:
GetInstance()181   static LoginUtilsWrapper* GetInstance() {
182     return Singleton<LoginUtilsWrapper>::get();
183   }
184 
get()185   LoginUtils* get() {
186     base::AutoLock create(create_lock_);
187     if (!ptr_.get())
188       reset(new LoginUtilsImpl);
189     return ptr_.get();
190   }
191 
reset(LoginUtils * ptr)192   void reset(LoginUtils* ptr) {
193     ptr_.reset(ptr);
194   }
195 
196  private:
197   friend struct DefaultSingletonTraits<LoginUtilsWrapper>;
198 
LoginUtilsWrapper()199   LoginUtilsWrapper() {}
200 
201   base::Lock create_lock_;
202   scoped_ptr<LoginUtils> ptr_;
203 
204   DISALLOW_COPY_AND_ASSIGN(LoginUtilsWrapper);
205 };
206 
PrepareProfile(const std::string & username,const std::string & password,const GaiaAuthConsumer::ClientLoginResult & credentials,bool pending_requests,LoginUtils::Delegate * delegate)207 void LoginUtilsImpl::PrepareProfile(
208     const std::string& username,
209     const std::string& password,
210     const GaiaAuthConsumer::ClientLoginResult& credentials,
211     bool pending_requests,
212     LoginUtils::Delegate* delegate) {
213   BootTimesLoader* btl = BootTimesLoader::Get();
214 
215   VLOG(1) << "Completing login for " << username;
216   btl->AddLoginTimeMarker("CompletingLogin", false);
217 
218   if (CrosLibrary::Get()->EnsureLoaded()) {
219     CrosLibrary::Get()->GetLoginLibrary()->StartSession(username, "");
220     btl->AddLoginTimeMarker("StartedSession", false);
221   }
222 
223   UserManager::Get()->UserLoggedIn(username);
224   btl->AddLoginTimeMarker("UserLoggedIn", false);
225 
226   // Switch log file as soon as possible.
227   logging::RedirectChromeLogging(*(CommandLine::ForCurrentProcess()));
228   btl->AddLoginTimeMarker("LoggingRedirected", false);
229 
230   username_ = username;
231   password_ = password;
232   credentials_ = credentials;
233   pending_requests_ = pending_requests;
234   delegate_ = delegate;
235 
236   // The default profile will have been changed because the ProfileManager
237   // will process the notification that the UserManager sends out.
238   ProfileManager::CreateDefaultProfileAsync(this);
239 }
240 
OnProfileCreated(Profile * profile)241 void LoginUtilsImpl::OnProfileCreated(Profile* profile) {
242   CHECK(profile);
243 
244   BootTimesLoader* btl = BootTimesLoader::Get();
245   btl->AddLoginTimeMarker("UserProfileGotten", false);
246 
247   // Change the proxy configuration service of the default request context to
248   // use the preference configuration from the logged-in profile. This ensures
249   // that requests done through the default context use the proxy configuration
250   // provided by configuration policy.
251   //
252   // Note: Many of the clients of the default request context should probably be
253   // fixed to use the request context of the profile they are associated with.
254   // This includes preconnect, autofill, metrics service to only name a few;
255   // see http://code.google.com/p/chromium/issues/detail?id=64339 for details.
256   //
257   // TODO(mnissler) Revisit when support for device-specific policy arrives, at
258   // which point the default request context can directly be managed through
259   // device policy.
260   net::ProxyConfigService* proxy_config_service =
261       new PrefProxyConfigService(
262           profile->GetProxyConfigTracker(),
263           new chromeos::ProxyConfigService(
264               g_browser_process->chromeos_proxy_config_service_impl()));
265   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
266                           new ResetDefaultProxyConfigServiceTask(
267                               proxy_config_service));
268 
269   // Since we're doing parallel authentication, only new user sign in
270   // would perform online auth before calling PrepareProfile.
271   // For existing users there's usually a pending online auth request.
272   // Cookies will be fetched after it's is succeeded.
273   if (!pending_requests_) {
274     FetchCookies(profile, credentials_);
275   }
276 
277   // Init extension event routers; this normally happens in browser_main
278   // but on Chrome OS it has to be deferred until the user finishes
279   // logging in and the profile is not OTR.
280   if (profile->GetExtensionService() &&
281       profile->GetExtensionService()->extensions_enabled()) {
282     profile->GetExtensionService()->InitEventRouters();
283   }
284   btl->AddLoginTimeMarker("ExtensionsServiceStarted", false);
285 
286   // Supply credentials for sync and others to use. Load tokens from disk.
287   TokenService* token_service = profile->GetTokenService();
288   token_service->Initialize(GaiaConstants::kChromeOSSource,
289                             profile);
290   token_service->LoadTokensFromDB();
291 
292   // For existing users there's usually a pending online auth request.
293   // Tokens will be fetched after it's is succeeded.
294   if (!pending_requests_) {
295     FetchTokens(profile, credentials_);
296   }
297   btl->AddLoginTimeMarker("TokensGotten", false);
298 
299   // Set the CrOS user by getting this constructor run with the
300   // user's email on first retrieval.
301   profile->GetProfileSyncService(username_)->SetPassphrase(password_,
302                                                            false,
303                                                            true);
304   btl->AddLoginTimeMarker("SyncStarted", false);
305 
306   // Own TPM device if, for any reason, it has not been done in EULA
307   // wizard screen.
308   if (CrosLibrary::Get()->EnsureLoaded()) {
309     CryptohomeLibrary* cryptohome = CrosLibrary::Get()->GetCryptohomeLibrary();
310     if (cryptohome->TpmIsEnabled() && !cryptohome->TpmIsBeingOwned()) {
311       if (cryptohome->TpmIsOwned()) {
312         cryptohome->TpmClearStoredPassword();
313       } else {
314         cryptohome->TpmCanAttemptOwnership();
315       }
316     }
317   }
318   btl->AddLoginTimeMarker("TPMOwned", false);
319 
320   RespectLocalePreference(profile);
321 
322   if (UserManager::Get()->current_user_is_new()) {
323     SetFirstLoginPrefs(profile->GetPrefs());
324   }
325 
326   // Enable/disable plugins based on user preferences.
327   PluginUpdater::GetInstance()->UpdatePluginGroupsStateFromPrefs(profile);
328   btl->AddLoginTimeMarker("PluginsStateUpdated", false);
329 
330   // We suck. This is a hack since we do not have the enterprise feature
331   // done yet to pull down policies from the domain admin. We'll take this
332   // out when we get that done properly.
333   // TODO(xiyuan): Remove this once enterprise feature is ready.
334   if (EndsWith(username_, "@google.com", true)) {
335     PrefService* pref_service = profile->GetPrefs();
336     pref_service->SetBoolean(prefs::kEnableScreenLock, true);
337   }
338 
339   profile->OnLogin();
340 
341   delegate_->OnProfilePrepared(profile);
342 
343   // TODO(altimofeev): Need to sanitize memory used to store password.
344   password_ = "";
345   username_ = "";
346   credentials_ = GaiaAuthConsumer::ClientLoginResult();
347 }
348 
FetchCookies(Profile * profile,const GaiaAuthConsumer::ClientLoginResult & credentials)349 void LoginUtilsImpl::FetchCookies(
350     Profile* profile,
351     const GaiaAuthConsumer::ClientLoginResult& credentials) {
352   // Take the credentials passed in and try to exchange them for
353   // full-fledged Google authentication cookies.  This is
354   // best-effort; it's possible that we'll fail due to network
355   // troubles or some such.
356   // CookieFetcher will delete itself once done.
357   CookieFetcher* cf = new CookieFetcher(profile);
358   cf->AttemptFetch(credentials.data);
359   BootTimesLoader::Get()->AddLoginTimeMarker("CookieFetchStarted", false);
360 }
361 
FetchTokens(Profile * profile,const GaiaAuthConsumer::ClientLoginResult & credentials)362 void LoginUtilsImpl::FetchTokens(
363     Profile* profile,
364     const GaiaAuthConsumer::ClientLoginResult& credentials) {
365   TokenService* token_service = profile->GetTokenService();
366   token_service->UpdateCredentials(credentials);
367   if (token_service->AreCredentialsValid()) {
368     token_service->StartFetchingTokens();
369   }
370 }
371 
RespectLocalePreference(Profile * profile)372 void LoginUtilsImpl::RespectLocalePreference(Profile* profile) {
373   DCHECK(profile != NULL);
374   PrefService* prefs = profile->GetPrefs();
375   DCHECK(prefs != NULL);
376   if (g_browser_process == NULL)
377     return;
378 
379   std::string pref_locale = prefs->GetString(prefs::kApplicationLocale);
380   if (pref_locale.empty())
381     pref_locale = prefs->GetString(prefs::kApplicationLocaleBackup);
382   if (pref_locale.empty())
383     pref_locale = g_browser_process->GetApplicationLocale();
384   DCHECK(!pref_locale.empty());
385   profile->ChangeAppLocale(pref_locale, Profile::APP_LOCALE_CHANGED_VIA_LOGIN);
386   // Here we don't enable keyboard layouts. Input methods are set up when
387   // the user first logs in. Then the user may customize the input methods.
388   // Hence changing input methods here, just because the user's UI language
389   // is different from the login screen UI language, is not desirable. Note
390   // that input method preferences are synced, so users can use their
391   // farovite input methods as soon as the preferences are synced.
392   LanguageSwitchMenu::SwitchLanguage(pref_locale);
393 }
394 
CompleteOffTheRecordLogin(const GURL & start_url)395 void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) {
396   VLOG(1) << "Completing incognito login";
397 
398   UserManager::Get()->OffTheRecordUserLoggedIn();
399 
400   if (CrosLibrary::Get()->EnsureLoaded()) {
401     // For guest session we ask session manager to restart Chrome with --bwsi
402     // flag. We keep only some of the arguments of this process.
403     const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
404     CommandLine command_line(browser_command_line.GetProgram());
405     std::string cmd_line_str =
406         GetOffTheRecordCommandLine(start_url,
407                                    browser_command_line,
408                                    &command_line);
409 
410     CrosLibrary::Get()->GetLoginLibrary()->RestartJob(getpid(), cmd_line_str);
411   }
412 }
413 
GetOffTheRecordCommandLine(const GURL & start_url,const CommandLine & base_command_line,CommandLine * command_line)414 std::string LoginUtilsImpl::GetOffTheRecordCommandLine(
415     const GURL& start_url,
416     const CommandLine& base_command_line,
417     CommandLine* command_line) {
418   static const char* kForwardSwitches[] = {
419       switches::kEnableLogging,
420       switches::kEnableAcceleratedPlugins,
421       switches::kUseGL,
422       switches::kUserDataDir,
423       switches::kScrollPixels,
424       switches::kEnableGView,
425       switches::kNoFirstRun,
426       switches::kLoginProfile,
427       switches::kCompressSystemFeedback,
428       switches::kDisableSeccompSandbox,
429       switches::kPpapiFlashInProcess,
430       switches::kPpapiFlashPath,
431       switches::kPpapiFlashVersion,
432 #if defined(HAVE_XINPUT2)
433       switches::kTouchDevices,
434 #endif
435   };
436   command_line->CopySwitchesFrom(base_command_line,
437                                  kForwardSwitches,
438                                  arraysize(kForwardSwitches));
439   command_line->AppendSwitch(switches::kGuestSession);
440   command_line->AppendSwitch(switches::kIncognito);
441   command_line->AppendSwitchASCII(switches::kLoggingLevel,
442                                  kGuestModeLoggingLevel);
443 
444   command_line->AppendSwitchASCII(switches::kLoginUser, kGuestUserName);
445 
446   if (start_url.is_valid())
447     command_line->AppendArg(start_url.spec());
448 
449   // Override the value of the homepage that is set in first run mode.
450   // TODO(altimofeev): extend action of the |kNoFirstRun| to cover this case.
451   command_line->AppendSwitchASCII(
452       switches::kHomePage,
453       GURL(chrome::kChromeUINewTabURL).spec());
454 
455   std::string cmd_line_str = command_line->command_line_string();
456   // Special workaround for the arguments that should be quoted.
457   // Copying switches won't be needed when Guest mode won't need restart
458   // http://crosbug.com/6924
459   if (base_command_line.HasSwitch(switches::kRegisterPepperPlugins)) {
460     cmd_line_str += base::StringPrintf(
461         kSwitchFormatString,
462         switches::kRegisterPepperPlugins,
463         base_command_line.GetSwitchValueNative(
464             switches::kRegisterPepperPlugins).c_str());
465   }
466 
467   return cmd_line_str;
468 }
469 
SetFirstLoginPrefs(PrefService * prefs)470 void LoginUtilsImpl::SetFirstLoginPrefs(PrefService* prefs) {
471   VLOG(1) << "Setting first login prefs";
472   BootTimesLoader* btl = BootTimesLoader::Get();
473   std::string locale = g_browser_process->GetApplicationLocale();
474 
475   // First, we'll set kLanguagePreloadEngines.
476   InputMethodLibrary* library = CrosLibrary::Get()->GetInputMethodLibrary();
477   std::vector<std::string> input_method_ids;
478   input_method::GetFirstLoginInputMethodIds(locale,
479                                             library->current_input_method(),
480                                             &input_method_ids);
481   // Save the input methods in the user's preferences.
482   StringPrefMember language_preload_engines;
483   language_preload_engines.Init(prefs::kLanguagePreloadEngines,
484                                 prefs, NULL);
485   language_preload_engines.SetValue(JoinString(input_method_ids, ','));
486   btl->AddLoginTimeMarker("IMEStarted", false);
487 
488   // Second, we'll set kLanguagePreferredLanguages.
489   std::vector<std::string> language_codes;
490   // The current locale should be on the top.
491   language_codes.push_back(locale);
492 
493   // Add input method IDs based on the input methods, as there may be
494   // input methods that are unrelated to the current locale. Example: the
495   // hardware keyboard layout xkb:us::eng is used for logging in, but the
496   // UI language is set to French. In this case, we should set "fr,en"
497   // to the preferred languages preference.
498   std::vector<std::string> candidates;
499   input_method::GetLanguageCodesFromInputMethodIds(
500       input_method_ids, &candidates);
501   for (size_t i = 0; i < candidates.size(); ++i) {
502     const std::string& candidate = candidates[i];
503     // Skip if it's already in language_codes.
504     if (std::count(language_codes.begin(), language_codes.end(),
505                    candidate) == 0) {
506       language_codes.push_back(candidate);
507     }
508   }
509   // Save the preferred languages in the user's preferences.
510   StringPrefMember language_preferred_languages;
511   language_preferred_languages.Init(prefs::kLanguagePreferredLanguages,
512                                     prefs, NULL);
513   language_preferred_languages.SetValue(JoinString(language_codes, ','));
514   prefs->ScheduleSavePersistentPrefs();
515 }
516 
CreateAuthenticator(LoginStatusConsumer * consumer)517 Authenticator* LoginUtilsImpl::CreateAuthenticator(
518     LoginStatusConsumer* consumer) {
519   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kParallelAuth))
520     return new ParallelAuthenticator(consumer);
521   else
522     return new GoogleAuthenticator(consumer);
523 }
524 
525 // We use a special class for this so that it can be safely leaked if we
526 // never connect. At shutdown the order is not well defined, and it's possible
527 // for the infrastructure needed to unregister might be unstable and crash.
528 class WarmingObserver : public NetworkLibrary::NetworkManagerObserver {
529  public:
WarmingObserver()530   WarmingObserver() {
531     NetworkLibrary *netlib = CrosLibrary::Get()->GetNetworkLibrary();
532     netlib->AddNetworkManagerObserver(this);
533   }
534 
535   // If we're now connected, prewarm the auth url.
OnNetworkManagerChanged(NetworkLibrary * netlib)536   void OnNetworkManagerChanged(NetworkLibrary* netlib) {
537     if (netlib->Connected()) {
538       const int kConnectionsNeeded = 1;
539       chrome_browser_net::PreconnectOnUIThread(
540           GURL(GaiaAuthFetcher::kClientLoginUrl),
541           chrome_browser_net::UrlInfo::EARLY_LOAD_MOTIVATED,
542           kConnectionsNeeded);
543       netlib->RemoveNetworkManagerObserver(this);
544       delete this;
545     }
546   }
547 };
548 
PrewarmAuthentication()549 void LoginUtilsImpl::PrewarmAuthentication() {
550   if (CrosLibrary::Get()->EnsureLoaded()) {
551     NetworkLibrary *network = CrosLibrary::Get()->GetNetworkLibrary();
552     if (network->Connected()) {
553       const int kConnectionsNeeded = 1;
554       chrome_browser_net::PreconnectOnUIThread(
555           GURL(GaiaAuthFetcher::kClientLoginUrl),
556           chrome_browser_net::UrlInfo::EARLY_LOAD_MOTIVATED,
557           kConnectionsNeeded);
558     } else {
559       new WarmingObserver();
560     }
561   }
562 }
563 
SetBackgroundView(BackgroundView * background_view)564 void LoginUtilsImpl::SetBackgroundView(BackgroundView* background_view) {
565   background_view_ = background_view;
566 }
567 
GetBackgroundView()568 BackgroundView* LoginUtilsImpl::GetBackgroundView() {
569   return background_view_;
570 }
571 
Get()572 LoginUtils* LoginUtils::Get() {
573   return LoginUtilsWrapper::GetInstance()->get();
574 }
575 
Set(LoginUtils * mock)576 void LoginUtils::Set(LoginUtils* mock) {
577   LoginUtilsWrapper::GetInstance()->reset(mock);
578 }
579 
DoBrowserLaunch(Profile * profile)580 void LoginUtils::DoBrowserLaunch(Profile* profile) {
581   BootTimesLoader::Get()->AddLoginTimeMarker("BrowserLaunched", false);
582 
583   // Update command line in case loose values were added.
584   CommandLine::ForCurrentProcess()->InitFromArgv(
585       CommandLine::ForCurrentProcess()->argv());
586 
587   VLOG(1) << "Launching browser...";
588   BrowserInit browser_init;
589   int return_code;
590   browser_init.LaunchBrowser(*CommandLine::ForCurrentProcess(),
591                              profile,
592                              FilePath(),
593                              true,
594                              &return_code);
595 }
596 
597 }  // namespace chromeos
598