chromium/chrome/browser/chromeos/extensions/printing_metrics/printing_metrics_service.cc

// Copyright 2022 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/chromeos/extensions/printing_metrics/printing_metrics_service.h"

#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/printing_metrics.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_event_histogram_value.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/crosapi/crosapi_ash.h"
#include "chrome/browser/ash/crosapi/crosapi_manager.h"
#include "chrome/browser/ash/crosapi/printing_metrics_ash.h"
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/lacros/lacros_service.h"
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

namespace {

#if BUILDFLAG(IS_CHROMEOS_LACROS)

// Only main profile should be allowed to access the API.
bool IsContextForMainProfile(content::BrowserContext* context) {
  return Profile::FromBrowserContext(context)->IsMainProfile();
}

crosapi::mojom::PrintingMetrics* GetPrintingMetrics() {
  auto* service = chromeos::LacrosService::Get();
  if (!service->IsRegistered<crosapi::mojom::PrintingMetrics>() ||
      !service->IsAvailable<crosapi::mojom::PrintingMetrics>()) {
    LOG(ERROR) << "chrome.printingMetrics is not available in Lacros";
    return nullptr;
  }
  return service->GetRemote<crosapi::mojom::PrintingMetrics>().get();
}

#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

}  // namespace

namespace extensions {

// static
BrowserContextKeyedAPIFactory<PrintingMetricsService>*
PrintingMetricsService::GetFactoryInstance() {
  static base::NoDestructor<
      BrowserContextKeyedAPIFactory<PrintingMetricsService>>
      instance;
  return instance.get();
}

// static
PrintingMetricsService* PrintingMetricsService::Get(
    content::BrowserContext* context) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
  if (!IsContextForMainProfile(context) || !GetPrintingMetrics()) {
    return nullptr;
  }
#endif  // BUIDLFLAG(IS_CHROMEOS_LACROS)
  return BrowserContextKeyedAPIFactory<PrintingMetricsService>::Get(context);
}

PrintingMetricsService::PrintingMetricsService(content::BrowserContext* context)
    : context_(context) {
  EventRouter::Get(context_)->RegisterObserver(
      this, api::printing_metrics::OnPrintJobFinished::kEventName);
}

PrintingMetricsService::~PrintingMetricsService() = default;

void PrintingMetricsService::Shutdown() {
  EventRouter::Get(context_)->UnregisterObserver(this);
}

void PrintingMetricsService::OnListenerAdded(const EventListenerInfo&) {
  // Ensures that the two-way crosapi connection is initialized for the profile,
  // so that incoming onPrintJobFinished events can be dispatched to the
  // extension.
  EnsureInit();
}

void PrintingMetricsService::GetPrintJobs(
    crosapi::mojom::PrintingMetricsForProfile::GetPrintJobsCallback callback) {
  EnsureInit();
#if BUILDFLAG(IS_CHROMEOS_LACROS)
  // We might need to call the older version if Ash version is not up-to-date.
  if (chromeos::LacrosService::Get()
          ->GetInterfaceVersion<crosapi::mojom::PrintingMetricsForProfile>() <
      static_cast<int>(
          crosapi::mojom::PrintingMetricsForProfile::kGetPrintJobsMinVersion)) {
    remote_->DeprecatedGetPrintJobs(
        base::BindOnce([](std::vector<base::Value> print_jobs) {
          base::Value::List jobs;
          for (auto& print_job : print_jobs) {
            jobs.Append(std::move(print_job));
          }
          return jobs;
        }).Then(std::move(callback)));
    return;
  }
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

  remote_->GetPrintJobs(std::move(callback));
}

void PrintingMetricsService::OnPrintJobFinished(base::Value print_job) {
  std::optional<api::printing_metrics::PrintJobInfo> print_job_info =
      api::printing_metrics::PrintJobInfo::FromValue(std::move(print_job));
  DCHECK(print_job_info.has_value());

  auto event = std::make_unique<Event>(
      events::PRINTING_METRICS_ON_PRINT_JOB_FINISHED,
      api::printing_metrics::OnPrintJobFinished::kEventName,
      api::printing_metrics::OnPrintJobFinished::Create(
          std::move(print_job_info).value()));

  EventRouter::Get(context_)->BroadcastEvent(std::move(event));
}

void PrintingMetricsService::EnsureInit() {
  if (initialized_) {
    return;
  }
  initialized_ = true;

#if BUILDFLAG(IS_CHROMEOS_ASH)
  crosapi::PrintingMetricsAsh* printing_metrics_ash =
      crosapi::CrosapiManager::Get()->crosapi_ash()->printing_metrics_ash();

  printing_metrics_ash->RegisterForProfile(
      Profile::FromBrowserContext(context_),
      remote_.BindNewPipeAndPassReceiver(),
      receiver_.BindNewPipeAndPassRemote());
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(IS_CHROMEOS_LACROS)
  GetPrintingMetrics()->RegisterForMainProfile(
      remote_.BindNewPipeAndPassReceiver(),
      receiver_.BindNewPipeAndPassRemote());
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
}

}  // namespace extensions