Observe and report kiosk login failure.

Kiosk login failure will cause browser restart preventing the record
from being enqueued, so in this CL the failure timestamp is stored
using pref service then retrieved and reported in the next session
which should not be a kiosk session because of the failure.

Bug: b:218751747
Change-Id: I661fdf17673e572674ee0598dd1a86e670c27795
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3499052
Reviewed-by: Gabriel Charette <[email protected]>
Commit-Queue: Ahmed Nasr <[email protected]>
Cr-Commit-Position: refs/heads/main@{#979485}
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter.cc b/chrome/browser/ash/login/reporting/login_logout_reporter.cc
index 849de275..6b0bcb4 100644
--- a/chrome/browser/ash/login/reporting/login_logout_reporter.cc
+++ b/chrome/browser/ash/login/reporting/login_logout_reporter.cc
@@ -5,18 +5,36 @@
 #include "chrome/browser/ash/login/reporting/login_logout_reporter.h"
 
 #include "base/logging.h"
+#include "base/task/bind_post_task.h"
 #include "chrome/browser/ash/login/existing_user_controller.h"
 #include "chrome/browser/ash/policy/core/device_local_account.h"
 #include "chrome/browser/ash/policy/reporting/user_event_reporter_helper.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/browser_process.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
 #include "components/user_manager/user_names.h"
+#include "content/public/browser/browser_thread.h"
 
 namespace ash {
 namespace reporting {
 namespace {
 
+constexpr char kLoginLogoutReporterDictionary[] =
+    "reporting.login_logout_reporter_dictionary";
+constexpr char kKioskLoginFailureTimestamp[] = "kiosk_login_failure_timestamp";
+
+PrefService* GetLocalState() {
+  if (!g_browser_process || !g_browser_process->local_state()) {
+    DVLOG(1) << "Could not get local state.";
+    return nullptr;
+  }
+  return g_browser_process->local_state();
+}
+
 LoginLogoutSessionType GetSessionType(const AccountId& account_id) {
   if (account_id == user_manager::GuestAccountId()) {
     return LoginLogoutSessionType::GUEST_SESSION;
@@ -94,15 +112,23 @@
       ->GetLastLoginAttemptAccountId();
 }
 
+// static
+void LoginLogoutReporter::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterDictionaryPref(kLoginLogoutReporterDictionary);
+}
+
 LoginLogoutReporter::LoginLogoutReporter(
     std::unique_ptr<::reporting::UserEventReporterHelper> reporter_helper,
     std::unique_ptr<Delegate> delegate,
-    policy::ManagedSessionService* managed_session_service)
+    policy::ManagedSessionService* managed_session_service,
+    base::Clock* clock)
     : reporter_helper_(std::move(reporter_helper)),
-      delegate_(std::move(delegate)) {
+      delegate_(std::move(delegate)),
+      clock_(clock) {
   if (managed_session_service) {
     managed_session_observation_.Observe(managed_session_service);
   }
+  MaybeReportKioskLoginFailure();
 }
 
 LoginLogoutReporter::~LoginLogoutReporter() = default;
@@ -122,10 +148,11 @@
 std::unique_ptr<LoginLogoutReporter> LoginLogoutReporter::CreateForTest(
     std::unique_ptr<::reporting::UserEventReporterHelper> reporter_helper,
     std::unique_ptr<LoginLogoutReporter::Delegate> delegate,
-    policy::ManagedSessionService* managed_session_service) {
-  return base::WrapUnique(new LoginLogoutReporter(std::move(reporter_helper),
-                                                  std::move(delegate),
-                                                  managed_session_service));
+    policy::ManagedSessionService* managed_session_service,
+    base::Clock* clock) {
+  return base::WrapUnique(
+      new LoginLogoutReporter(std::move(reporter_helper), std::move(delegate),
+                              managed_session_service, clock));
 }
 
 void LoginLogoutReporter::MaybeReportEvent(LoginLogoutRecord record,
@@ -140,7 +167,7 @@
        session_type == LoginLogoutSessionType::KIOSK_SESSION)) {
     return;
   }
-  record.set_event_timestamp_sec(base::Time::Now().ToTimeT());
+  record.set_event_timestamp_sec(clock_->Now().ToTimeT());
   record.set_session_type(session_type);
   const std::string& user_email = account_id.GetUserEmail();
   if (session_type == LoginLogoutSessionType::PUBLIC_ACCOUNT_SESSION ||
@@ -180,5 +207,70 @@
   MaybeReportEvent(std::move(record), account_id);
 }
 
+void LoginLogoutReporter::OnKioskLoginFailure() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (!base::FeatureList::IsEnabled(kEnableKioskAndGuestLoginLogoutReporting) ||
+      !reporter_helper_->ReportingEnabled(kReportDeviceLoginLogout) ||
+      !GetLocalState()) {
+    return;
+  }
+
+  DictionaryPrefUpdate dict_update(GetLocalState(),
+                                   kLoginLogoutReporterDictionary);
+  dict_update->GetDict().Set(kKioskLoginFailureTimestamp,
+                             static_cast<int>(clock_->Now().ToTimeT()));
+}
+
+void LoginLogoutReporter::MaybeReportKioskLoginFailure() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (!base::FeatureList::IsEnabled(kEnableKioskAndGuestLoginLogoutReporting) ||
+      !GetLocalState()) {
+    return;
+  }
+
+  const auto* pref =
+      GetLocalState()->FindPreference(kLoginLogoutReporterDictionary);
+  if (!pref) {
+    NOTREACHED() << "Cannot find pref.";
+    return;
+  }
+
+  absl::optional<int> last_kiosk_login_failure_timestamp =
+      pref->GetValue()->GetDict().FindInt(kKioskLoginFailureTimestamp);
+  if (!last_kiosk_login_failure_timestamp.has_value()) {
+    // No kiosk login failure to report.
+    return;
+  }
+
+  LoginLogoutRecord record;
+  record.set_event_timestamp_sec(last_kiosk_login_failure_timestamp.value());
+  record.set_session_type(LoginLogoutSessionType::KIOSK_SESSION);
+  record.mutable_login_event()->mutable_failure();
+
+  auto enqueue_cb = base::BindOnce([](::reporting::Status status) {
+    if (!status.ok()) {
+      DVLOG(1) << "Could not enqueue event to reporting queue because of: "
+               << status;
+      return;
+    }
+
+    if (!GetLocalState()) {
+      return;
+    }
+    DictionaryPrefUpdate dict_update(GetLocalState(),
+                                     kLoginLogoutReporterDictionary);
+    dict_update->RemoveKey(kKioskLoginFailureTimestamp);
+  });
+
+  // Enqueue callback should run on the UI thread (current thread) to access
+  // pref service.
+  reporter_helper_->ReportEvent(
+      &record, ::reporting::Priority::SECURITY,
+      base::BindPostTask(base::ThreadTaskRunnerHandle::Get(),
+                         std::move(enqueue_cb)));
+}
+
 }  // namespace reporting
 }  // namespace ash
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter.h b/chrome/browser/ash/login/reporting/login_logout_reporter.h
index 2e81f96..a21ff34b 100644
--- a/chrome/browser/ash/login/reporting/login_logout_reporter.h
+++ b/chrome/browser/ash/login/reporting/login_logout_reporter.h
@@ -5,15 +5,18 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_REPORTING_LOGIN_LOGOUT_REPORTER_H_
 #define CHROME_BROWSER_ASH_LOGIN_REPORTING_LOGIN_LOGOUT_REPORTER_H_
 
+#include <memory>
+
 #include "ash/components/login/auth/auth_status_consumer.h"
-#include "base/containers/queue.h"
 #include "base/feature_list.h"
 #include "base/scoped_observation.h"
+#include "base/time/clock.h"
+#include "base/time/default_clock.h"
 #include "chrome/browser/ash/policy/status_collector/managed_session_service.h"
 #include "chrome/browser/policy/messaging_layer/proto/synced/login_logout_event.pb.h"
 #include "chrome/browser/profiles/profile.h"
-#include "components/policy/core/common/cloud/dm_token.h"
-#include "components/reporting/client/report_queue_provider.h"
+
+class PrefRegistrySimple;
 
 namespace reporting {
 
@@ -51,7 +54,10 @@
   static std::unique_ptr<LoginLogoutReporter> CreateForTest(
       std::unique_ptr<::reporting::UserEventReporterHelper> reporter_helper,
       std::unique_ptr<Delegate> delegate,
-      policy::ManagedSessionService* managed_session_service = nullptr);
+      policy::ManagedSessionService* managed_session_service,
+      base::Clock* clock = base::DefaultClock::GetInstance());
+
+  static void RegisterPrefs(PrefRegistrySimple* registry);
 
   // Report user device failed login attempt.
   void OnLoginFailure(const AuthFailure& error) override;
@@ -62,16 +68,21 @@
   // Report user device logout.
   void OnSessionTerminationStarted(const user_manager::User* user) override;
 
+  void OnKioskLoginFailure() override;
+
  private:
   static const base::Feature kEnableKioskAndGuestLoginLogoutReporting;
 
   LoginLogoutReporter(
       std::unique_ptr<::reporting::UserEventReporterHelper> reporter_helper,
       std::unique_ptr<Delegate> delegate,
-      policy::ManagedSessionService* managed_session_service);
+      policy::ManagedSessionService* managed_session_service,
+      base::Clock* clock = base::DefaultClock::GetInstance());
 
   void MaybeReportEvent(LoginLogoutRecord record, const AccountId& account_id);
 
+  void MaybeReportKioskLoginFailure();
+
   std::unique_ptr<::reporting::UserEventReporterHelper> reporter_helper_;
 
   std::unique_ptr<Delegate> delegate_;
@@ -80,6 +91,8 @@
                           policy::ManagedSessionService::Observer>
       managed_session_observation_{this};
 
+  base::Clock* const clock_;
+
   // To be able to access |kEnableKioskAndGuestLoginLogoutReporting| in tests.
   friend class LoginLogoutTestHelper;
 };
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc b/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc
index b2c1d6a..39131b1 100644
--- a/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc
+++ b/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc
@@ -6,11 +6,14 @@
 
 #include "ash/components/login/session/session_termination_manager.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/simple_test_clock.h"
 #include "base/test/task_environment.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/ash/policy/core/device_local_account.h"
 #include "chrome/browser/ash/policy/reporting/user_event_reporter_helper_testing.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/test/base/scoped_testing_local_state.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "components/policy/core/common/cloud/dm_token.h"
@@ -133,19 +136,25 @@
   }
 
   std::unique_ptr<::reporting::UserEventReporterHelperTesting>
-  GetReporterHelper(bool reporting_enabled, bool should_report_user) {
+  GetReporterHelper(bool reporting_enabled,
+                    bool should_report_user,
+                    ::reporting::Status status = ::reporting::Status()) {
+    record_.Clear();
+    report_count_ = 0;
     auto mock_queue = std::unique_ptr<::reporting::MockReportQueue,
                                       base::OnTaskRunnerDeleter>(
         new testing::NiceMock<::reporting::MockReportQueue>(),
         base::OnTaskRunnerDeleter(base::SequencedTaskRunnerHandle::Get()));
 
     ON_CALL(*mock_queue, AddRecord(_, ::reporting::Priority::SECURITY, _))
-        .WillByDefault([&](base::StringPiece record_string,
+        .WillByDefault([this, status](
+                           base::StringPiece record_string,
                            ::reporting::Priority event_priority,
-                           ::reporting::ReportQueue::EnqueueCallback) {
+                           ::reporting::ReportQueue::EnqueueCallback cb) {
           ++report_count_;
           EXPECT_TRUE(record_.ParseFromArray(record_string.data(),
                                              record_string.size()));
+          std::move(cb).Run(status);
         });
 
     auto reporter_helper =
@@ -177,11 +186,16 @@
 class LoginLogoutReporterTest
     : public ::testing::TestWithParam<LoginLogoutReporterTestCase> {
  protected:
+  LoginLogoutReporterTest()
+      : local_state_(TestingBrowserProcess::GetGlobal()) {}
+
   void SetUp() override { test_helper_.Init(); }
 
   void TearDown() override { test_helper_.Shutdown(); }
 
   LoginLogoutTestHelper test_helper_;
+
+  ScopedTestingLocalState local_state_;
 };
 
 TEST_F(LoginLogoutReporterTest, ReportAffiliatedLogin) {
@@ -370,11 +384,16 @@
 
 class LoginFailureReporterTest : public ::testing::TestWithParam<AuthFailure> {
  protected:
+  LoginFailureReporterTest()
+      : local_state_(TestingBrowserProcess::GetGlobal()) {}
+
   void SetUp() override { test_helper_.Init(); }
 
   void TearDown() override { test_helper_.Shutdown(); }
 
   LoginLogoutTestHelper test_helper_;
+
+  ScopedTestingLocalState local_state_;
 };
 
 TEST_F(LoginFailureReporterTest, ReportAffiliatedLoginFailure_OwnerRequired) {
@@ -402,7 +421,7 @@
   EXPECT_THAT(record.affiliated_user().user_email(), StrEq(user_email));
   ASSERT_TRUE(record.has_session_type());
   EXPECT_THAT(record.session_type(),
-              testing::Eq(LoginLogoutSessionType::REGULAR_USER_SESSION));
+              Eq(LoginLogoutSessionType::REGULAR_USER_SESSION));
   ASSERT_TRUE(record.has_login_event());
   ASSERT_TRUE(record.login_event().has_failure());
   ASSERT_THAT(record.login_event().failure().reason(),
@@ -435,7 +454,7 @@
   EXPECT_THAT(record.affiliated_user().user_email(), StrEq(user_email));
   ASSERT_TRUE(record.has_session_type());
   EXPECT_THAT(record.session_type(),
-              testing::Eq(LoginLogoutSessionType::REGULAR_USER_SESSION));
+              Eq(LoginLogoutSessionType::REGULAR_USER_SESSION));
   ASSERT_TRUE(record.has_login_event());
   ASSERT_TRUE(record.login_event().has_failure());
   ASSERT_THAT(record.login_event().failure().reason(),
@@ -464,7 +483,7 @@
   EXPECT_FALSE(record.has_affiliated_user());
   ASSERT_TRUE(record.has_session_type());
   EXPECT_THAT(record.session_type(),
-              testing::Eq(LoginLogoutSessionType::REGULAR_USER_SESSION));
+              Eq(LoginLogoutSessionType::REGULAR_USER_SESSION));
   ASSERT_TRUE(record.has_login_event());
   ASSERT_TRUE(record.login_event().has_failure());
   ASSERT_THAT(record.login_event().failure().reason(),
@@ -497,7 +516,7 @@
   EXPECT_FALSE(record.has_affiliated_user());
   ASSERT_TRUE(record.has_session_type());
   EXPECT_THAT(record.session_type(),
-              testing::Eq(LoginLogoutSessionType::PUBLIC_ACCOUNT_SESSION));
+              Eq(LoginLogoutSessionType::PUBLIC_ACCOUNT_SESSION));
   ASSERT_TRUE(record.has_login_event());
   ASSERT_TRUE(record.login_event().has_failure());
   ASSERT_THAT(record.login_event().failure().reason(),
@@ -530,7 +549,7 @@
   EXPECT_FALSE(record.has_affiliated_user());
   ASSERT_TRUE(record.has_session_type());
   EXPECT_THAT(record.session_type(),
-              testing::Eq(LoginLogoutSessionType::PUBLIC_ACCOUNT_SESSION));
+              Eq(LoginLogoutSessionType::PUBLIC_ACCOUNT_SESSION));
   ASSERT_TRUE(record.has_login_event());
   ASSERT_TRUE(record.login_event().has_failure());
   ASSERT_THAT(record.login_event().failure().reason(),
@@ -559,8 +578,7 @@
   EXPECT_FALSE(record.has_logout_event());
   EXPECT_FALSE(record.has_affiliated_user());
   ASSERT_TRUE(record.has_session_type());
-  EXPECT_THAT(record.session_type(),
-              testing::Eq(LoginLogoutSessionType::GUEST_SESSION));
+  EXPECT_THAT(record.session_type(), Eq(LoginLogoutSessionType::GUEST_SESSION));
   ASSERT_TRUE(record.has_login_event());
   ASSERT_TRUE(record.login_event().has_failure());
   ASSERT_THAT(record.login_event().failure().reason(),
@@ -605,6 +623,239 @@
   ASSERT_THAT(test_helper_.GetReportCount(), Eq(0));
 }
 
+TEST_F(LoginFailureReporterTest, ReportKioskLoginFailure) {
+  const base::Time failure_time = base::Time::Now();
+  // Kiosk login failure session.
+  {
+    base::SimpleTestClock test_clock;
+    test_clock.SetNow(failure_time);
+    policy::ManagedSessionService managed_session_service;
+    auto reporter_helper = test_helper_.GetReporterHelper(
+        /*reporting_enabled=*/true,
+        /*should_report_user=*/false);
+
+    auto reporter = LoginLogoutReporter::CreateForTest(
+        std::move(reporter_helper),
+        std::make_unique<LoginLogoutReporterTestDelegate>(),
+        &managed_session_service, &test_clock);
+    base::RunLoop().RunUntilIdle();
+
+    managed_session_service.OnKioskProfileLoadFailed();
+
+    ASSERT_THAT(test_helper_.GetReportCount(), Eq(0));
+  }
+
+  // Next session after kiosk login failure session.
+  {
+    base::SimpleTestClock test_clock;
+    test_clock.SetNow(failure_time + base::Hours(10));
+    policy::ManagedSessionService managed_session_service;
+    // Only |reporting_enabled| value at the time of kiosk login failure matter.
+    auto reporter_helper = test_helper_.GetReporterHelper(
+        /*reporting_enabled=*/false,
+        /*should_report_user=*/false);
+
+    auto reporter = LoginLogoutReporter::CreateForTest(
+        std::move(reporter_helper),
+        std::make_unique<LoginLogoutReporterTestDelegate>(),
+        &managed_session_service, &test_clock);
+    base::RunLoop().RunUntilIdle();
+    const LoginLogoutRecord& record = test_helper_.GetRecord();
+
+    ASSERT_THAT(test_helper_.GetReportCount(), Eq(1));
+    ASSERT_TRUE(record.has_event_timestamp_sec());
+    EXPECT_THAT(record.event_timestamp_sec(), Eq(failure_time.ToTimeT()));
+    EXPECT_FALSE(record.is_guest_session());
+    EXPECT_FALSE(record.has_logout_event());
+    EXPECT_FALSE(record.has_affiliated_user());
+    ASSERT_TRUE(record.has_session_type());
+    EXPECT_THAT(record.session_type(),
+                Eq(LoginLogoutSessionType::KIOSK_SESSION));
+    ASSERT_TRUE(record.has_login_event());
+    ASSERT_TRUE(record.login_event().has_failure());
+    EXPECT_FALSE(record.login_event().failure().has_reason());
+  }
+
+  // Next session after kiosk login failure reporting session.
+  {
+    base::SimpleTestClock test_clock;
+    test_clock.SetNow(failure_time + base::Hours(20));
+    policy::ManagedSessionService managed_session_service;
+    auto reporter_helper = test_helper_.GetReporterHelper(
+        /*reporting_enabled=*/true,
+        /*should_report_user=*/false);
+
+    auto reporter = LoginLogoutReporter::CreateForTest(
+        std::move(reporter_helper),
+        std::make_unique<LoginLogoutReporterTestDelegate>(),
+        &managed_session_service, &test_clock);
+    base::RunLoop().RunUntilIdle();
+
+    ASSERT_THAT(test_helper_.GetReportCount(), Eq(0));
+  }
+}
+
+TEST_F(LoginFailureReporterTest, ReportKioskLoginFailure_ReportingError) {
+  const base::Time failure_time = base::Time::Now();
+  // Kiosk login failure session.
+  {
+    base::SimpleTestClock test_clock;
+    test_clock.SetNow(failure_time);
+    policy::ManagedSessionService managed_session_service;
+    auto reporter_helper = test_helper_.GetReporterHelper(
+        /*reporting_enabled=*/true,
+        /*should_report_user=*/false);
+
+    auto reporter = LoginLogoutReporter::CreateForTest(
+        std::move(reporter_helper),
+        std::make_unique<LoginLogoutReporterTestDelegate>(),
+        &managed_session_service, &test_clock);
+    base::RunLoop().RunUntilIdle();
+
+    managed_session_service.OnKioskProfileLoadFailed();
+
+    ASSERT_THAT(test_helper_.GetReportCount(), Eq(0));
+  }
+
+  // Next session after kiosk login failure session.
+  // Reporting error.
+  {
+    base::SimpleTestClock test_clock;
+    test_clock.SetNow(failure_time + base::Hours(10));
+    policy::ManagedSessionService managed_session_service;
+    // Only |reporting_enabled| value at the time of kiosk login failure matter.
+    auto reporter_helper = test_helper_.GetReporterHelper(
+        /*reporting_enabled=*/true,
+        /*should_report_user=*/false,
+        ::reporting::Status(::reporting::error::INTERNAL, ""));
+
+    auto reporter = LoginLogoutReporter::CreateForTest(
+        std::move(reporter_helper),
+        std::make_unique<LoginLogoutReporterTestDelegate>(),
+        &managed_session_service, &test_clock);
+    base::RunLoop().RunUntilIdle();
+
+    ASSERT_THAT(test_helper_.GetReportCount(), Eq(1));
+  }
+
+  // Next session after reporting error session.
+  // Report success.
+  {
+    base::SimpleTestClock test_clock;
+    test_clock.SetNow(failure_time + base::Hours(20));
+    policy::ManagedSessionService managed_session_service;
+    auto reporter_helper = test_helper_.GetReporterHelper(
+        /*reporting_enabled=*/true,
+        /*should_report_user=*/false);
+
+    auto reporter = LoginLogoutReporter::CreateForTest(
+        std::move(reporter_helper),
+        std::make_unique<LoginLogoutReporterTestDelegate>(),
+        &managed_session_service, &test_clock);
+    base::RunLoop().RunUntilIdle();
+    const LoginLogoutRecord& record = test_helper_.GetRecord();
+
+    ASSERT_THAT(test_helper_.GetReportCount(), Eq(1));
+    ASSERT_TRUE(record.has_event_timestamp_sec());
+    EXPECT_THAT(record.event_timestamp_sec(), Eq(failure_time.ToTimeT()));
+    EXPECT_FALSE(record.is_guest_session());
+    EXPECT_FALSE(record.has_logout_event());
+    EXPECT_FALSE(record.has_affiliated_user());
+    ASSERT_TRUE(record.has_session_type());
+    EXPECT_THAT(record.session_type(),
+                Eq(LoginLogoutSessionType::KIOSK_SESSION));
+    ASSERT_TRUE(record.has_login_event());
+    ASSERT_TRUE(record.login_event().has_failure());
+    EXPECT_FALSE(record.login_event().failure().has_reason());
+  }
+}
+
+TEST_F(LoginFailureReporterTest, ReportKioskLoginFailure_ReportingDisabled) {
+  const base::Time failure_time = base::Time::Now();
+  // Kiosk login failure session.
+  {
+    base::SimpleTestClock test_clock;
+    test_clock.SetNow(failure_time);
+    policy::ManagedSessionService managed_session_service;
+    auto reporter_helper = test_helper_.GetReporterHelper(
+        /*reporting_enabled=*/false,
+        /*should_report_user=*/false);
+
+    auto reporter = LoginLogoutReporter::CreateForTest(
+        std::move(reporter_helper),
+        std::make_unique<LoginLogoutReporterTestDelegate>(),
+        &managed_session_service, &test_clock);
+    base::RunLoop().RunUntilIdle();
+
+    managed_session_service.OnKioskProfileLoadFailed();
+
+    ASSERT_THAT(test_helper_.GetReportCount(), Eq(0));
+  }
+
+  // Next session after kiosk login failure session.
+  {
+    base::SimpleTestClock test_clock;
+    test_clock.SetNow(failure_time + base::Hours(10));
+    policy::ManagedSessionService managed_session_service;
+    // Only |reporting_enabled| value at the time of kiosk login failure matter.
+    auto reporter_helper = test_helper_.GetReporterHelper(
+        /*reporting_enabled=*/true,
+        /*should_report_user=*/false);
+
+    auto reporter = LoginLogoutReporter::CreateForTest(
+        std::move(reporter_helper),
+        std::make_unique<LoginLogoutReporterTestDelegate>(),
+        &managed_session_service, &test_clock);
+    base::RunLoop().RunUntilIdle();
+
+    ASSERT_THAT(test_helper_.GetReportCount(), Eq(0));
+  }
+}
+
+TEST_F(LoginFailureReporterTest,
+       ReportKioskLoginFailure_KioskLoginLogoutReportingDisabled) {
+  test_helper_.DisableKioskAndGuestLoginLogoutReporting();
+
+  const base::Time failure_time = base::Time::Now();
+  // Kiosk login failure session.
+  {
+    base::SimpleTestClock test_clock;
+    test_clock.SetNow(failure_time);
+    policy::ManagedSessionService managed_session_service;
+    auto reporter_helper = test_helper_.GetReporterHelper(
+        /*reporting_enabled=*/true,
+        /*should_report_user=*/false);
+
+    auto reporter = LoginLogoutReporter::CreateForTest(
+        std::move(reporter_helper),
+        std::make_unique<LoginLogoutReporterTestDelegate>(),
+        &managed_session_service, &test_clock);
+    base::RunLoop().RunUntilIdle();
+
+    managed_session_service.OnKioskProfileLoadFailed();
+
+    ASSERT_THAT(test_helper_.GetReportCount(), Eq(0));
+  }
+
+  // Next session after kiosk login failure session.
+  {
+    base::SimpleTestClock test_clock;
+    test_clock.SetNow(failure_time + base::Hours(10));
+    policy::ManagedSessionService managed_session_service;
+    auto reporter_helper = test_helper_.GetReporterHelper(
+        /*reporting_enabled=*/true,
+        /*should_report_user=*/false);
+
+    auto reporter = LoginLogoutReporter::CreateForTest(
+        std::move(reporter_helper),
+        std::make_unique<LoginLogoutReporterTestDelegate>(),
+        &managed_session_service, &test_clock);
+    base::RunLoop().RunUntilIdle();
+
+    ASSERT_THAT(test_helper_.GetReportCount(), Eq(0));
+  }
+}
+
 TEST_P(LoginFailureReporterTest,
        ReportUnaffiliatedLoginFailure_AuthenticationError) {
   policy::ManagedSessionService managed_session_service;
@@ -628,7 +879,7 @@
   EXPECT_FALSE(record.has_affiliated_user());
   ASSERT_TRUE(record.has_session_type());
   EXPECT_THAT(record.session_type(),
-              testing::Eq(LoginLogoutSessionType::REGULAR_USER_SESSION));
+              Eq(LoginLogoutSessionType::REGULAR_USER_SESSION));
   ASSERT_TRUE(record.has_login_event());
   ASSERT_TRUE(record.login_event().has_failure());
   ASSERT_THAT(record.login_event().failure().reason(),
@@ -660,7 +911,7 @@
   EXPECT_FALSE(record.has_affiliated_user());
   ASSERT_TRUE(record.has_session_type());
   EXPECT_THAT(record.session_type(),
-              testing::Eq(LoginLogoutSessionType::PUBLIC_ACCOUNT_SESSION));
+              Eq(LoginLogoutSessionType::PUBLIC_ACCOUNT_SESSION));
   ASSERT_TRUE(record.has_login_event());
   ASSERT_TRUE(record.login_event().has_failure());
   ASSERT_THAT(record.login_event().failure().reason(),
@@ -688,8 +939,7 @@
   EXPECT_FALSE(record.has_logout_event());
   EXPECT_FALSE(record.has_affiliated_user());
   ASSERT_TRUE(record.has_session_type());
-  EXPECT_THAT(record.session_type(),
-              testing::Eq(LoginLogoutSessionType::GUEST_SESSION));
+  EXPECT_THAT(record.session_type(), Eq(LoginLogoutSessionType::GUEST_SESSION));
   ASSERT_TRUE(record.has_login_event());
   ASSERT_TRUE(record.login_event().has_failure());
   ASSERT_THAT(record.login_event().failure().reason(),
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 254086e1..0daa4ee5 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -325,6 +325,7 @@
 #include "chrome/browser/ash/login/quick_unlock/fingerprint_storage.h"
 #include "chrome/browser/ash/login/quick_unlock/pin_storage_prefs.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h"
+#include "chrome/browser/ash/login/reporting/login_logout_reporter.h"
 #include "chrome/browser/ash/login/saml/saml_profile_prefs.h"
 #include "chrome/browser/ash/login/screens/enable_adb_sideloading_screen.h"
 #include "chrome/browser/ash/login/screens/reset_screen.h"
@@ -1075,6 +1076,7 @@
   chromeos::local_search_service::SearchMetricsReporter::
       RegisterLocalStatePrefs(registry);
   ash::login::SecurityTokenSessionController::RegisterLocalStatePrefs(registry);
+  ash::reporting::LoginLogoutReporter::RegisterPrefs(registry);
   ash::MultiProfileUserController::RegisterPrefs(registry);
   chromeos::NetworkMetadataStore::RegisterPrefs(registry);
   ash::NetworkThrottlingObserver::RegisterPrefs(registry);