1 // Copyright 2014 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/session/session_manager.h" 6 7 #include <string> 8 9 #include "base/base_paths.h" 10 #include "base/bind.h" 11 #include "base/command_line.h" 12 #include "base/logging.h" 13 #include "base/path_service.h" 14 #include "base/prefs/pref_member.h" 15 #include "base/prefs/pref_registry_simple.h" 16 #include "base/prefs/pref_service.h" 17 #include "base/strings/string16.h" 18 #include "base/sys_info.h" 19 #include "base/task_runner_util.h" 20 #include "base/threading/worker_pool.h" 21 #include "chrome/browser/app_mode/app_mode_utils.h" 22 #include "chrome/browser/browser_process.h" 23 #include "chrome/browser/chrome_notification_types.h" 24 #include "chrome/browser/chromeos/boot_times_loader.h" 25 #include "chrome/browser/chromeos/input_method/input_method_util.h" 26 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h" 27 #include "chrome/browser/chromeos/login/profile_auth_data.h" 28 #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.h" 29 #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter_factory.h" 30 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h" 31 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.h" 32 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h" 33 #include "chrome/browser/chromeos/login/users/user.h" 34 #include "chrome/browser/chromeos/login/users/user_manager.h" 35 #include "chrome/browser/first_run/first_run.h" 36 #include "chrome/browser/google/google_brand_chromeos.h" 37 #include "chrome/browser/lifetime/application_lifetime.h" 38 #include "chrome/browser/profiles/profile.h" 39 #include "chrome/browser/profiles/profile_manager.h" 40 #include "chrome/browser/rlz/rlz.h" 41 #include "chrome/browser/signin/signin_manager_factory.h" 42 #include "chrome/common/chrome_switches.h" 43 #include "chrome/common/logging_chrome.h" 44 #include "chrome/common/pref_names.h" 45 #include "chromeos/chromeos_switches.h" 46 #include "chromeos/cryptohome/cryptohome_util.h" 47 #include "chromeos/dbus/cryptohome_client.h" 48 #include "chromeos/dbus/dbus_thread_manager.h" 49 #include "chromeos/dbus/session_manager_client.h" 50 #include "chromeos/ime/input_method_manager.h" 51 #include "components/signin/core/browser/signin_manager_base.h" 52 #include "content/public/browser/notification_service.h" 53 54 namespace chromeos { 55 56 namespace { 57 58 void InitLocaleAndInputMethodsForNewUser(PrefService* prefs) { 59 // First, we'll set kLanguagePreloadEngines. 60 std::string locale = g_browser_process->GetApplicationLocale(); 61 input_method::InputMethodManager* manager = 62 input_method::InputMethodManager::Get(); 63 std::vector<std::string> input_method_ids; 64 manager->GetInputMethodUtil()->GetFirstLoginInputMethodIds( 65 locale, manager->GetCurrentInputMethod(), &input_method_ids); 66 67 // Save the input methods in the user's preferences. 68 StringPrefMember language_preload_engines; 69 language_preload_engines.Init(prefs::kLanguagePreloadEngines, prefs); 70 language_preload_engines.SetValue(JoinString(input_method_ids, ',')); 71 BootTimesLoader::Get()->AddLoginTimeMarker("IMEStarted", false); 72 73 // Second, we'll set kLanguagePreferredLanguages. 74 std::vector<std::string> language_codes; 75 76 // The current locale should be on the top. 77 language_codes.push_back(locale); 78 79 // Add input method IDs based on the input methods, as there may be 80 // input methods that are unrelated to the current locale. Example: the 81 // hardware keyboard layout xkb:us::eng is used for logging in, but the 82 // UI language is set to French. In this case, we should set "fr,en" 83 // to the preferred languages preference. 84 std::vector<std::string> candidates; 85 manager->GetInputMethodUtil()->GetLanguageCodesFromInputMethodIds( 86 input_method_ids, &candidates); 87 for (size_t i = 0; i < candidates.size(); ++i) { 88 const std::string& candidate = candidates[i]; 89 // Skip if it's already in language_codes. 90 if (std::count(language_codes.begin(), language_codes.end(), 91 candidate) == 0) { 92 language_codes.push_back(candidate); 93 } 94 } 95 96 // Save the preferred languages in the user's preferences. 97 StringPrefMember language_preferred_languages; 98 language_preferred_languages.Init(prefs::kLanguagePreferredLanguages, prefs); 99 language_preferred_languages.SetValue(JoinString(language_codes, ',')); 100 } 101 102 #if defined(ENABLE_RLZ) 103 // Flag file that disables RLZ tracking, when present. 104 const base::FilePath::CharType kRLZDisabledFlagName[] = 105 FILE_PATH_LITERAL(".rlz_disabled"); 106 107 base::FilePath GetRlzDisabledFlagPath() { 108 base::FilePath homedir; 109 PathService::Get(base::DIR_HOME, &homedir); 110 return homedir.Append(kRLZDisabledFlagName); 111 } 112 #endif 113 114 } // namespace 115 116 // static 117 SessionManager* SessionManager::GetInstance() { 118 return Singleton<SessionManager, 119 DefaultSingletonTraits<SessionManager> >::get(); 120 } 121 122 // static 123 void SessionManager::RegisterPrefs(PrefRegistrySimple* registry) { 124 registry->RegisterStringPref(prefs::kRLZBrand, std::string()); 125 registry->RegisterBooleanPref(prefs::kRLZDisabled, false); 126 } 127 128 SessionManager::SessionManager() 129 : delegate_(NULL), 130 has_web_auth_cookies_(false), 131 exit_after_session_restore_(false), 132 session_restore_strategy_( 133 OAuth2LoginManager::RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN) { 134 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); 135 } 136 137 SessionManager::~SessionManager() { 138 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); 139 } 140 141 void SessionManager::OnSessionRestoreStateChanged( 142 Profile* user_profile, 143 OAuth2LoginManager::SessionRestoreState state) { 144 User::OAuthTokenStatus user_status = User::OAUTH_TOKEN_STATUS_UNKNOWN; 145 OAuth2LoginManager* login_manager = 146 OAuth2LoginManagerFactory::GetInstance()->GetForProfile(user_profile); 147 148 bool connection_error = false; 149 switch (state) { 150 case OAuth2LoginManager::SESSION_RESTORE_DONE: 151 user_status = User::OAUTH2_TOKEN_STATUS_VALID; 152 break; 153 case OAuth2LoginManager::SESSION_RESTORE_FAILED: 154 user_status = User::OAUTH2_TOKEN_STATUS_INVALID; 155 break; 156 case OAuth2LoginManager::SESSION_RESTORE_CONNECTION_FAILED: 157 connection_error = true; 158 break; 159 case OAuth2LoginManager::SESSION_RESTORE_NOT_STARTED: 160 case OAuth2LoginManager::SESSION_RESTORE_PREPARING: 161 case OAuth2LoginManager::SESSION_RESTORE_IN_PROGRESS: 162 return; 163 } 164 165 // We should not be clearing existing token state if that was a connection 166 // error. http://crbug.com/295245 167 if (!connection_error) { 168 // We are in one of "done" states here. 169 UserManager::Get()->SaveUserOAuthStatus( 170 UserManager::Get()->GetLoggedInUser()->email(), 171 user_status); 172 } 173 174 login_manager->RemoveObserver(this); 175 } 176 177 void SessionManager::OnNewRefreshTokenAvaiable(Profile* user_profile) { 178 // Check if we were waiting to restart chrome. 179 if (!exit_after_session_restore_) 180 return; 181 182 OAuth2LoginManager* login_manager = 183 OAuth2LoginManagerFactory::GetInstance()->GetForProfile(user_profile); 184 login_manager->RemoveObserver(this); 185 186 // Mark user auth token status as valid. 187 UserManager::Get()->SaveUserOAuthStatus( 188 UserManager::Get()->GetLoggedInUser()->email(), 189 User::OAUTH2_TOKEN_STATUS_VALID); 190 191 LOG(WARNING) << "Exiting after new refresh token fetched"; 192 193 // We need to restart cleanly in this case to make sure OAuth2 RT is actually 194 // saved. 195 chrome::AttemptRestart(); 196 } 197 198 void SessionManager::OnConnectionTypeChanged( 199 net::NetworkChangeNotifier::ConnectionType type) { 200 UserManager* user_manager = UserManager::Get(); 201 if (type == net::NetworkChangeNotifier::CONNECTION_NONE || 202 user_manager->IsLoggedInAsGuest() || !user_manager->IsUserLoggedIn()) { 203 return; 204 } 205 206 // Need to iterate over all users and their OAuth2 session state. 207 const UserList& users = user_manager->GetLoggedInUsers(); 208 for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) { 209 Profile* user_profile = user_manager->GetProfileByUser(*it); 210 bool should_restore_session = 211 pending_restore_sessions_.find((*it)->email()) != 212 pending_restore_sessions_.end(); 213 OAuth2LoginManager* login_manager = 214 OAuth2LoginManagerFactory::GetInstance()->GetForProfile(user_profile); 215 if (login_manager->state() == 216 OAuth2LoginManager::SESSION_RESTORE_IN_PROGRESS) { 217 // If we come online for the first time after successful offline login, 218 // we need to kick off OAuth token verification process again. 219 login_manager->ContinueSessionRestore(); 220 } else if (should_restore_session) { 221 pending_restore_sessions_.erase((*it)->email()); 222 RestoreAuthSessionImpl(user_profile, has_web_auth_cookies_); 223 } 224 } 225 } 226 227 void SessionManager::StartSession(const UserContext& user_context, 228 scoped_refptr<Authenticator> authenticator, 229 bool has_cookies, 230 bool has_active_session, 231 Delegate* delegate) { 232 authenticator_ = authenticator; 233 delegate_ = delegate; 234 235 VLOG(1) << "Starting session for " << user_context.GetUserID(); 236 237 PreStartSession(); 238 CreateUserSession(user_context, has_cookies); 239 240 if (!has_active_session) 241 StartCrosSession(); 242 243 // TODO(nkostylev): Notify UserLoggedIn() after profile is actually 244 // ready to be used (http://crbug.com/361528). 245 NotifyUserLoggedIn(); 246 PrepareProfile(); 247 } 248 249 void SessionManager::RestoreAuthenticationSession(Profile* user_profile) { 250 UserManager* user_manager = UserManager::Get(); 251 // We don't need to restore session for demo/guest/stub/public account users. 252 if (!user_manager->IsUserLoggedIn() || 253 user_manager->IsLoggedInAsGuest() || 254 user_manager->IsLoggedInAsPublicAccount() || 255 user_manager->IsLoggedInAsDemoUser() || 256 user_manager->IsLoggedInAsStub()) { 257 return; 258 } 259 260 User* user = user_manager->GetUserByProfile(user_profile); 261 DCHECK(user); 262 if (!net::NetworkChangeNotifier::IsOffline()) { 263 pending_restore_sessions_.erase(user->email()); 264 RestoreAuthSessionImpl(user_profile, false); 265 } else { 266 // Even if we're online we should wait till initial 267 // OnConnectionTypeChanged() call. Otherwise starting fetchers too early may 268 // end up canceling all request when initial network connection type is 269 // processed. See http://crbug.com/121643. 270 pending_restore_sessions_.insert(user->email()); 271 } 272 } 273 274 void SessionManager::InitRlz(Profile* profile) { 275 #if defined(ENABLE_RLZ) 276 if (!g_browser_process->local_state()->HasPrefPath(prefs::kRLZBrand)) { 277 // Read brand code asynchronously from an OEM data and repost ourselves. 278 google_brand::chromeos::InitBrand( 279 base::Bind(&SessionManager::InitRlz, AsWeakPtr(), profile)); 280 return; 281 } 282 base::PostTaskAndReplyWithResult( 283 base::WorkerPool::GetTaskRunner(false), 284 FROM_HERE, 285 base::Bind(&base::PathExists, GetRlzDisabledFlagPath()), 286 base::Bind(&SessionManager::InitRlzImpl, AsWeakPtr(), profile)); 287 #endif 288 } 289 290 OAuth2LoginManager::SessionRestoreStrategy 291 SessionManager::GetSigninSessionRestoreStrategy() { 292 return session_restore_strategy_; 293 } 294 295 // static 296 void SessionManager::SetFirstLoginPrefs(PrefService* prefs) { 297 VLOG(1) << "Setting first login prefs"; 298 InitLocaleAndInputMethodsForNewUser(prefs); 299 } 300 301 void SessionManager::CreateUserSession(const UserContext& user_context, 302 bool has_cookies) { 303 user_context_ = user_context; 304 has_web_auth_cookies_ = has_cookies; 305 InitSessionRestoreStrategy(); 306 } 307 308 void SessionManager::PreStartSession() { 309 // Switch log file as soon as possible. 310 if (base::SysInfo::IsRunningOnChromeOS()) 311 logging::RedirectChromeLogging(*(CommandLine::ForCurrentProcess())); 312 } 313 314 void SessionManager::StartCrosSession() { 315 BootTimesLoader* btl = BootTimesLoader::Get(); 316 btl->AddLoginTimeMarker("StartSession-Start", false); 317 DBusThreadManager::Get()->GetSessionManagerClient()-> 318 StartSession(user_context_.GetUserID()); 319 btl->AddLoginTimeMarker("StartSession-End", false); 320 } 321 322 void SessionManager:: NotifyUserLoggedIn() { 323 BootTimesLoader* btl = BootTimesLoader::Get(); 324 btl->AddLoginTimeMarker("UserLoggedIn-Start", false); 325 UserManager* user_manager = UserManager::Get(); 326 user_manager->UserLoggedIn(user_context_.GetUserID(), 327 user_context_.GetUserIDHash(), 328 false); 329 btl->AddLoginTimeMarker("UserLoggedIn-End", false); 330 } 331 332 void SessionManager::PrepareProfile() { 333 UserManager* user_manager = UserManager::Get(); 334 bool is_demo_session = 335 DemoAppLauncher::IsDemoAppSession(user_context_.GetUserID()); 336 337 // TODO(nkostylev): Figure out whether demo session is using the right profile 338 // path or not. See https://codereview.chromium.org/171423009 339 g_browser_process->profile_manager()->CreateProfileAsync( 340 user_manager->GetUserProfileDir(user_context_.GetUserID()), 341 base::Bind(&SessionManager::OnProfileCreated, AsWeakPtr(), 342 user_context_.GetUserID(), is_demo_session), 343 base::string16(), base::string16(), std::string()); 344 } 345 346 void SessionManager::OnProfileCreated(const std::string& user_id, 347 bool is_incognito_profile, 348 Profile* profile, 349 Profile::CreateStatus status) { 350 CHECK(profile); 351 352 switch (status) { 353 case Profile::CREATE_STATUS_CREATED: 354 // Profile created but before initializing extensions and promo resources. 355 InitProfilePreferences(profile, user_id); 356 break; 357 case Profile::CREATE_STATUS_INITIALIZED: 358 // Profile is created, extensions and promo resources are initialized. 359 // At this point all other Chrome OS services will be notified that it is 360 // safe to use this profile. 361 UserProfileInitialized(profile, is_incognito_profile); 362 break; 363 case Profile::CREATE_STATUS_LOCAL_FAIL: 364 case Profile::CREATE_STATUS_REMOTE_FAIL: 365 case Profile::CREATE_STATUS_CANCELED: 366 case Profile::MAX_CREATE_STATUS: 367 NOTREACHED(); 368 break; 369 } 370 } 371 372 void SessionManager::InitProfilePreferences(Profile* profile, 373 const std::string& user_id) { 374 if (UserManager::Get()->IsCurrentUserNew()) 375 SetFirstLoginPrefs(profile->GetPrefs()); 376 377 if (UserManager::Get()->IsLoggedInAsLocallyManagedUser()) { 378 User* active_user = UserManager::Get()->GetActiveUser(); 379 std::string managed_user_sync_id = 380 UserManager::Get()->GetSupervisedUserManager()-> 381 GetUserSyncId(active_user->email()); 382 profile->GetPrefs()->SetString(prefs::kSupervisedUserId, 383 managed_user_sync_id); 384 } else if (UserManager::Get()->IsLoggedInAsRegularUser()) { 385 // Make sure that the google service username is properly set (we do this 386 // on every sign in, not just the first login, to deal with existing 387 // profiles that might not have it set yet). 388 SigninManagerBase* signin_manager = 389 SigninManagerFactory::GetForProfile(profile); 390 signin_manager->SetAuthenticatedUsername(user_id); 391 } 392 } 393 394 void SessionManager::UserProfileInitialized(Profile* profile, 395 bool is_incognito_profile) { 396 if (is_incognito_profile) { 397 profile->OnLogin(); 398 // Send the notification before creating the browser so additional objects 399 // that need the profile (e.g. the launcher) can be created first. 400 content::NotificationService::current()->Notify( 401 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, 402 content::NotificationService::AllSources(), 403 content::Details<Profile>(profile)); 404 405 if (delegate_) 406 delegate_->OnProfilePrepared(profile); 407 408 return; 409 } 410 411 BootTimesLoader* btl = BootTimesLoader::Get(); 412 btl->AddLoginTimeMarker("UserProfileGotten", false); 413 414 if (user_context_.IsUsingOAuth()) { 415 // Transfer proxy authentication cache, cookies (optionally) and server 416 // bound certs from the profile that was used for authentication. This 417 // profile contains cookies that auth extension should have already put in 418 // place that will ensure that the newly created session is authenticated 419 // for the websites that work with the used authentication schema. 420 ProfileAuthData::Transfer( 421 authenticator_->authentication_profile(), 422 profile, 423 has_web_auth_cookies_, // transfer_cookies 424 base::Bind(&SessionManager::CompleteProfileCreateAfterAuthTransfer, 425 AsWeakPtr(), 426 profile)); 427 return; 428 } 429 430 FinalizePrepareProfile(profile); 431 } 432 433 void SessionManager::CompleteProfileCreateAfterAuthTransfer(Profile* profile) { 434 RestoreAuthSessionImpl(profile, has_web_auth_cookies_); 435 FinalizePrepareProfile(profile); 436 } 437 438 void SessionManager::FinalizePrepareProfile(Profile* profile) { 439 BootTimesLoader* btl = BootTimesLoader::Get(); 440 441 // Own TPM device if, for any reason, it has not been done in EULA screen. 442 CryptohomeClient* client = DBusThreadManager::Get()->GetCryptohomeClient(); 443 btl->AddLoginTimeMarker("TPMOwn-Start", false); 444 if (cryptohome_util::TpmIsEnabled() && !cryptohome_util::TpmIsBeingOwned()) { 445 if (cryptohome_util::TpmIsOwned()) { 446 client->CallTpmClearStoredPasswordAndBlock(); 447 } else { 448 client->TpmCanAttemptOwnership(EmptyVoidDBusMethodCallback()); 449 } 450 } 451 btl->AddLoginTimeMarker("TPMOwn-End", false); 452 453 UserManager* user_manager = UserManager::Get(); 454 if (user_manager->IsLoggedInAsRegularUser()) { 455 SAMLOfflineSigninLimiter* saml_offline_signin_limiter = 456 SAMLOfflineSigninLimiterFactory::GetForProfile(profile); 457 if (saml_offline_signin_limiter) 458 saml_offline_signin_limiter->SignedIn(user_context_.GetAuthFlow()); 459 } 460 461 profile->OnLogin(); 462 463 // Send the notification before creating the browser so additional objects 464 // that need the profile (e.g. the launcher) can be created first. 465 content::NotificationService::current()->Notify( 466 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, 467 content::NotificationService::AllSources(), 468 content::Details<Profile>(profile)); 469 470 // Initialize RLZ only for primary user. 471 if (user_manager->GetPrimaryUser() == 472 user_manager->GetUserByProfile(profile)) { 473 InitRlz(profile); 474 } 475 476 // TODO(altimofeev): This pointer should probably never be NULL, but it looks 477 // like LoginUtilsImpl::OnProfileCreated() may be getting called before 478 // SessionManager::PrepareProfile() has set |delegate_| when Chrome is killed 479 // during shutdown in tests -- see http://crosbug.com/18269. Replace this 480 // 'if' statement with a CHECK(delegate_) once the underlying issue is 481 // resolved. 482 if (delegate_) 483 delegate_->OnProfilePrepared(profile); 484 } 485 486 void SessionManager::InitSessionRestoreStrategy() { 487 CommandLine* command_line = CommandLine::ForCurrentProcess(); 488 bool in_app_mode = chrome::IsRunningInForcedAppMode(); 489 490 // Are we in kiosk app mode? 491 if (in_app_mode) { 492 if (command_line->HasSwitch(::switches::kAppModeOAuth2Token)) { 493 oauth2_refresh_token_ = command_line->GetSwitchValueASCII( 494 ::switches::kAppModeOAuth2Token); 495 } 496 497 if (command_line->HasSwitch(::switches::kAppModeAuthCode)) { 498 user_context_.SetAuthCode(command_line->GetSwitchValueASCII( 499 ::switches::kAppModeAuthCode)); 500 } 501 502 DCHECK(!has_web_auth_cookies_); 503 if (!user_context_.GetAuthCode().empty()) { 504 session_restore_strategy_ = OAuth2LoginManager::RESTORE_FROM_AUTH_CODE; 505 } else if (!oauth2_refresh_token_.empty()) { 506 session_restore_strategy_ = 507 OAuth2LoginManager::RESTORE_FROM_PASSED_OAUTH2_REFRESH_TOKEN; 508 } else { 509 session_restore_strategy_ = 510 OAuth2LoginManager::RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN; 511 } 512 return; 513 } 514 515 if (has_web_auth_cookies_) { 516 session_restore_strategy_ = OAuth2LoginManager::RESTORE_FROM_COOKIE_JAR; 517 } else if (!user_context_.GetAuthCode().empty()) { 518 session_restore_strategy_ = OAuth2LoginManager::RESTORE_FROM_AUTH_CODE; 519 } else { 520 session_restore_strategy_ = 521 OAuth2LoginManager::RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN; 522 } 523 } 524 525 void SessionManager::RestoreAuthSessionImpl(Profile* profile, 526 bool restore_from_auth_cookies) { 527 CHECK((authenticator_.get() && authenticator_->authentication_profile()) || 528 !restore_from_auth_cookies); 529 530 if (chrome::IsRunningInForcedAppMode() || 531 CommandLine::ForCurrentProcess()->HasSwitch( 532 chromeos::switches::kOobeSkipPostLogin)) { 533 return; 534 } 535 536 exit_after_session_restore_ = false; 537 538 // Remove legacy OAuth1 token if we have one. If it's valid, we should already 539 // have OAuth2 refresh token in OAuth2TokenService that could be used to 540 // retrieve all other tokens and user_context. 541 OAuth2LoginManager* login_manager = 542 OAuth2LoginManagerFactory::GetInstance()->GetForProfile(profile); 543 login_manager->AddObserver(this); 544 login_manager->RestoreSession( 545 authenticator_.get() && authenticator_->authentication_profile() 546 ? authenticator_->authentication_profile()->GetRequestContext() 547 : NULL, 548 session_restore_strategy_, 549 oauth2_refresh_token_, 550 user_context_.GetAuthCode()); 551 } 552 553 void SessionManager::InitRlzImpl(Profile* profile, bool disabled) { 554 #if defined(ENABLE_RLZ) 555 PrefService* local_state = g_browser_process->local_state(); 556 if (disabled) { 557 // Empty brand code means an organic install (no RLZ pings are sent). 558 google_brand::chromeos::ClearBrandForCurrentSession(); 559 } 560 if (disabled != local_state->GetBoolean(prefs::kRLZDisabled)) { 561 // When switching to RLZ enabled/disabled state, clear all recorded events. 562 RLZTracker::ClearRlzState(); 563 local_state->SetBoolean(prefs::kRLZDisabled, disabled); 564 } 565 // Init the RLZ library. 566 int ping_delay = profile->GetPrefs()->GetInteger( 567 first_run::GetPingDelayPrefName().c_str()); 568 // Negative ping delay means to send ping immediately after a first search is 569 // recorded. 570 RLZTracker::InitRlzFromProfileDelayed( 571 profile, UserManager::Get()->IsCurrentUserNew(), 572 ping_delay < 0, base::TimeDelta::FromMilliseconds(abs(ping_delay))); 573 if (delegate_) 574 delegate_->OnRlzInitialized(); 575 #endif 576 } 577 578 } // namespace chromeos 579