blob: 0ec73e8b62af7d85b8691cf5f7193fe0a59064b5 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bootsplash/bootsplash_daemon.h"
#include <csignal>
#include <sysexits.h>
#include <base/logging.h>
#include <base/time/time.h>
#include <brillo/dbus/dbus_signal_handler.h>
#include <brillo/errors/error.h>
#include <metrics/bootstat.h>
#include "bootsplash/session_manager_client.h"
#include "bootsplash/utils.h"
namespace bootsplash {
static BootSplashDaemon* g_bootsplash_daemon = nullptr;
constexpr int kFramesPerSecond = 30;
constexpr int64_t kBootLogoAnimationIntervalMilliseconds =
base::Time::kMillisecondsPerSecond / kFramesPerSecond;
namespace internal {
/* static */
BootSplashDaemon* Get() {
CHECK(g_bootsplash_daemon) << "BootSplashDaemon::Get() called before ctor()";
return g_bootsplash_daemon;
}
/* static */
void SignalHandler(int sig) {
CHECK_EQ(sig, SIGUSR1);
Get()->DBusDaemonInit();
}
} // namespace internal
BootSplashDaemon::BootSplashDaemon(bool feature_simon_enabled)
: feature_simon_enabled_(feature_simon_enabled) {
g_bootsplash_daemon = this;
num_frames_ = utils::GetMaxBootSplashFrameNumber(feature_simon_enabled_);
signal(SIGUSR1, &internal::SignalHandler);
}
void BootSplashDaemon::DBusDaemonInit() {
int return_code = brillo::DBusDaemon::OnInit();
if (return_code != EX_OK) {
LOG(ERROR) << "Failed to init brillo::DBusDaemon: " << return_code;
return;
}
CHECK(bus_) << "Failed to connect to dBus";
// Must be after DBusDaemon::OnInit(), so |bus_| is initialized.
session_manager_client_ = SessionManagerClient::Create(bus_);
CHECK(session_manager_client_) << "Failed to initialize SessionManagerClient";
session_manager_client_->AddObserver(this);
LOG(INFO) << "DBus initialized.";
}
int BootSplashDaemon::InitBootSplash() {
frecon->UpdateBootLogoDisplay(0);
StartBootLogoAnimationAlarm();
// Drop DRM master so Chrome can show the login screen as soon as it's ready.
frecon->DropDrmMaster();
return EX_OK;
}
int BootSplashDaemon::OnInit() {
frecon = Frecon::Create(feature_simon_enabled_);
if (!frecon) {
LOG(ERROR) << "Failed to create Frecon object.";
return -EX_SOFTWARE;
}
int status;
status = InitBootSplash();
if (status) {
return status;
}
bootstat::BootStat().LogEvent("splash-screen-visible");
return EX_OK;
}
void BootSplashDaemon::ShutdownBootSplash() {
boot_logo_animation_alarm_->Stop();
}
void BootSplashDaemon::OnShutdown(int* return_code) {
LOG(INFO) << "Shutting down.";
*return_code = EX_OK;
brillo::DBusDaemon::OnShutdown(return_code);
ShutdownBootSplash();
}
void BootSplashDaemon::SessionManagerLoginPromptVisibleEventReceived() {
LOG(INFO) << "LoginPromptVisible dbus signal received";
Quit();
}
void BootSplashDaemon::StartBootLogoAnimationAlarm() {
boot_logo_animation_alarm_->Start(
FROM_HERE, base::Milliseconds(kBootLogoAnimationIntervalMilliseconds),
base::BindRepeating(&BootSplashDaemon::OnBootLogoAnimationAlarmFired,
base::Unretained(this)));
}
void BootSplashDaemon::OnBootLogoAnimationAlarmFired() {
static int current_frame = 0;
frecon->UpdateBootLogoDisplay(current_frame);
/* Display all of the images once, and then stop animating. */
if (current_frame >= num_frames_) {
return;
}
++current_frame;
boot_logo_animation_alarm_->Reset();
}
} // namespace bootsplash