chromium/chrome/browser/screen_ai/screen_ai_downloader_chromeos.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/screen_ai/screen_ai_downloader_chromeos.h"

#include "base/no_destructor.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/screen_ai/pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/screen_ai/screen_ai_dlc_installer.h"
#elif BUILDFLAG(IS_CHROMEOS_LACROS)
#include "base/files/file_path.h"
#include "chromeos/lacros/lacros_service.h"
#endif

namespace {

#if BUILDFLAG(IS_CHROMEOS_LACROS)
void SetScreenAIComponentPath(
    bool set_failed_state_if_not_available,
    const std::optional<base::FilePath>& component_path) {
  auto* install_state = screen_ai::ScreenAIInstallState::GetInstance();
  if (component_path) {
    install_state->SetComponentFolder(*component_path);
  } else if (set_failed_state_if_not_available) {
    install_state->SetState(
        screen_ai::ScreenAIInstallState::State::kDownloadFailed);
  }
}
#else
void SetLastUsageTimeToNow() {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  g_browser_process->local_state()->SetTime(
      prefs::kScreenAILastUsedTimePrefName, base::Time::Now());
}
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

}  // namespace

namespace screen_ai {

// static
std::unique_ptr<ScreenAIInstallState> ScreenAIInstallState::Create() {
  return std::make_unique<ScreenAIDownloaderChromeOS>();
}

// static
ScreenAIInstallState* ScreenAIInstallState::CreateForTesting() {
  static base::NoDestructor<ScreenAIDownloaderChromeOS> install_state;
  return install_state.get();
}

ScreenAIDownloaderChromeOS::ScreenAIDownloaderChromeOS() {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
  // If component is already downloaded in Ash, update Lacros state.
  // Ash may download the component in the startup steps as it was used in
  // previous sessions, but that can be a bit after Lacros is created. Therefor
  // we wait for 3 seconds to ask. This is a best effort, and if it does not get
  // the state now, it will be done later on the first time that Lacros needs
  // the library.
  base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(
          &ScreenAIDownloaderChromeOS::MaybeGetComponentFolderFromAsh,
          weak_ptr_factory_.GetWeakPtr(),
          /*download_if_needed=*/false),
      base::Seconds(3));
#endif
}

ScreenAIDownloaderChromeOS::~ScreenAIDownloaderChromeOS() = default;

void ScreenAIDownloaderChromeOS::DownloadComponentInternal() {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

#if BUILDFLAG(IS_CHROMEOS_ASH)
  screen_ai::dlc_installer::Install();
#elif BUILDFLAG(IS_CHROMEOS_LACROS)
  MaybeGetComponentFolderFromAsh(/*download_if_needed=*/true);
#endif
}

void ScreenAIDownloaderChromeOS::SetLastUsageTime() {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
  // The last usage time should be sent to Ash as well for keeping track of the
  // library usage, and either keeping it updated or deleting it when it is not
  // used for a period of time.
  MaybeSetLastUsageTimeInAsh();
#else
  if (::content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
    SetLastUsageTimeToNow();
  } else {
    content::GetUIThreadTaskRunner()->PostTask(
        FROM_HERE, base::BindOnce(&SetLastUsageTimeToNow));
  }
#endif
}

#if BUILDFLAG(IS_CHROMEOS_LACROS)

void ScreenAIDownloaderChromeOS::MaybeGetComponentFolderFromAsh(
    bool download_if_needed) {
  chromeos::LacrosService* impl = chromeos::LacrosService::Get();
  if (!impl || !impl->IsAvailable<crosapi::mojom::ScreenAIDownloader>()) {
    VLOG(0) << "ScreenAIDownloaderChromeOS is not available.";
    ScreenAIInstallState::GetInstance()->SetState(
        ScreenAIInstallState::State::kDownloadFailed);
    return;
  }

  if (download_if_needed) {
    ScreenAIInstallState::GetInstance()->SetState(
        ScreenAIInstallState::State::kDownloading);
  }

  if (static_cast<uint32_t>(
          impl->GetInterfaceVersion<crosapi::mojom::ScreenAIDownloader>()) <
      crosapi::mojom::ScreenAIDownloader::kGetComponentFolderMinVersion) {
    // Getting component folder without asking for download is not supported
    // yet.
    if (!download_if_needed) {
      return;
    }

    impl->GetRemote<crosapi::mojom::ScreenAIDownloader>()
        ->DownloadComponentDeprecated(
            base::BindOnce(&SetScreenAIComponentPath,
                           /*set_failed_state_if_not_available=*/true));

  } else {
    impl->GetRemote<crosapi::mojom::ScreenAIDownloader>()->GetComponentFolder(
        download_if_needed,
        base::BindOnce(
            &SetScreenAIComponentPath,
            /*set_failed_state_if_not_available=*/download_if_needed));
  }
}

void ScreenAIDownloaderChromeOS::MaybeSetLastUsageTimeInAsh() {
  chromeos::LacrosService* impl = chromeos::LacrosService::Get();
  if (!impl || !impl->IsAvailable<crosapi::mojom::ScreenAIDownloader>()) {
    VLOG(0) << "ScreenAIDownloaderChromeOS is not available.";
    return;
  }

  impl->GetRemote<crosapi::mojom::ScreenAIDownloader>()->SetLastUsageTime();
}

#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

}  // namespace screen_ai