910e62b5创建于 1月15日历史提交
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/browser/api/printer_provider/printer_provider_api.h"

#include <stddef.h>

#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "base/functional/bind.h"
#include "base/i18n/rtl.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/device_event_log/device_event_log.h"
#include "extensions/browser/api/printer_provider/printer_provider_internal_api.h"
#include "extensions/browser/api/printer_provider/printer_provider_internal_api_observer.h"
#include "extensions/browser/api/printer_provider/printer_provider_print_job.h"
#include "extensions/browser/api/usb/usb_device_manager.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/api/printer_provider.h"
#include "extensions/common/api/printer_provider_internal.h"
#include "extensions/common/api/usb.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/mojom/context_type.mojom.h"
#include "extensions/common/mojom/event_dispatcher.mojom-forward.h"

namespace extensions {

namespace {

// The separator between extension id and the extension's internal printer id
// used when generating a printer id unique across extensions.
const char kPrinterIdSeparator = ':';

// Given an extension ID and an ID of a printer reported by the extension, it
// generates a ID for the printer unique across extensions (assuming that the
// printer id is unique in the extension's space).
std::string GeneratePrinterId(const ExtensionId& extension_id,
                              const std::string& internal_printer_id) {
  std::string result = extension_id;
  result.append(1, kPrinterIdSeparator);
  result.append(internal_printer_id);
  return result;
}

// Parses an ID created using |GeneratePrinterId| to it's components:
// the extension ID and the printer ID internal to the extension.
// Returns whenter the ID was succesfully parsed.
bool ParsePrinterId(const std::string& printer_id,
                    std::string* extension_id,
                    std::string* internal_printer_id) {
  size_t separator = printer_id.find_first_of(kPrinterIdSeparator);
  if (separator == std::string::npos)
    return false;
  *extension_id = printer_id.substr(0, separator);
  *internal_printer_id = printer_id.substr(separator + 1);
  return true;
}

void UpdatePrinterWithExtensionInfo(base::Value::Dict* printer,
                                    const Extension* extension) {
  std::string* internal_printer_id = printer->FindString("id");
  CHECK(internal_printer_id);
  printer->Set("id", GeneratePrinterId(extension->id(), *internal_printer_id));
  printer->Set("extensionId", extension->id());
  printer->Set("extensionName", extension->name());

  std::string* printer_name = printer->FindString("name");
  if (printer_name) {
    std::u16string u16_printer_name = base::UTF8ToUTF16(*printer_name);
    if (base::i18n::AdjustStringForLocaleDirection(&u16_printer_name))
      printer->Set("name", u16_printer_name);
  }

  std::string* printer_description = printer->FindString("description");
  if (printer_description) {
    std::u16string u16_printer_description =
        base::UTF8ToUTF16(*printer_description);
    if (base::i18n::AdjustStringForLocaleDirection(&u16_printer_description))
      printer->Set("description", u16_printer_description);
  }
}

// Holds information about a pending onGetPrintersRequested request;
// in particular, the list of extensions to which the event was dispatched but
// which haven't yet responded, and the |GetPrinters| callback associated with
// the event.
class GetPrintersRequest {
 public:
  explicit GetPrintersRequest(
      const PrinterProviderAPI::GetPrintersCallback& callback);
  ~GetPrintersRequest();

  // Adds an extension id to the list of the extensions that need to respond
  // to the event.
  void AddSource(const ExtensionId& extension_id);

  // Whether all extensions have responded to the event.
  bool IsDone() const;

  // Runs the callback for an extension and removes the extension from the
  // list of extensions that still have to respond to the event.
  void ReportForExtension(const ExtensionId& extension_id,
                          base::Value::List printers);

 private:
  // Callback reporting event result for an extension. Called once for each
  // extension.
  PrinterProviderAPI::GetPrintersCallback callback_;

  // The list of extensions that still have to respond to the event.
  std::set<std::string> extensions_;
};

// Keeps track of pending chrome.printerProvider.onGetPrintersRequested
// requests.
class PendingGetPrintersRequests {
 public:
  PendingGetPrintersRequests();
  PendingGetPrintersRequests(const PendingGetPrintersRequests&) = delete;
  PendingGetPrintersRequests& operator=(const PendingGetPrintersRequests&) =
      delete;
  ~PendingGetPrintersRequests();

  // Adds a new request to the set of pending requests. Returns the id
  // assigned to the request.
  int Add(const PrinterProviderAPI::GetPrintersCallback& callback);

  // Completes a request for an extension. It runs the request callback with
  // values reported by the extension.
  bool CompleteForExtension(const ExtensionId& extension_id,
                            int request_id,
                            base::Value::List result);

  // Runs callbacks for the extension for all requests that are waiting for a
  // response from the extension with the provided extension id. Callbacks are
  // called as if the extension reported empty set of printers.
  void FailAllForExtension(const ExtensionId& extension_id);

  // Adds an extension id to the list of the extensions that need to respond to
  // the event.
  bool AddSource(int request_id, const ExtensionId& extension_id);

 private:
  int last_request_id_;
  std::map<int, GetPrintersRequest> pending_requests_;
};

// Keeps track of pending chrome.printerProvider.onGetCapabilityRequested
// requests for an extension.
class PendingGetCapabilityRequests {
 public:
  static constexpr base::TimeDelta kGetCapabilityTimeout = base::Seconds(20);

  PendingGetCapabilityRequests();
  ~PendingGetCapabilityRequests();

  // Adds a new request to the set. Only information needed is the callback
  // associated with the request. Returns the id assigned to the request.
  int Add(PrinterProviderAPI::GetCapabilityCallback callback);

  // Completes the request with the provided request id. It runs the request
  // callback and removes the request from the set.
  void Complete(int request_id, base::Value::Dict result);

  // Runs all pending callbacks with empty capability value and clears the
  // set of pending requests.
  void FailAll();

 private:
  int last_request_id_;
  std::map<int, PrinterProviderAPI::GetCapabilityCallback> pending_requests_;
  base::WeakPtrFactory<PendingGetCapabilityRequests> weak_factory_{this};
};

constexpr base::TimeDelta PendingGetCapabilityRequests::kGetCapabilityTimeout;

// Keeps track of pending chrome.printerProvider.onPrintRequested requests
// for an extension.
class PendingPrintRequests {
 public:
  PendingPrintRequests();
  ~PendingPrintRequests();

  // Adds a new request to the set. Only information needed is the callback
  // associated with the request. Returns the id assigned to the request.
  int Add(PrinterProviderPrintJob job,
          PrinterProviderAPI::PrintCallback callback);

  // Gets print job associated with a request.
  const PrinterProviderPrintJob* GetPrintJob(int request_id) const;

  // Completes the request with the provided request id. It runs the request
  // callback and removes the request from the set.
  bool Complete(int request_id,
                api::printer_provider_internal::PrintError error);

  // Runs all pending callbacks with ERROR_FAILED and clears the set of
  // pending requests.
  void FailAll();

 private:
  struct PrintRequest {
    PrinterProviderAPI::PrintCallback callback;
    PrinterProviderPrintJob job;
  };

  int last_request_id_;
  std::map<int, PrintRequest> pending_requests_;
};

// Keeps track of pending chrome.printerProvider.onGetUsbPrinterInfoRequested
// requests for an extension.
class PendingUsbPrinterInfoRequests {
 public:
  PendingUsbPrinterInfoRequests();
  ~PendingUsbPrinterInfoRequests();

  // Adds a new request to the set. Only information needed is the callback
  // associated with the request. Returns the id assigned to the request.
  int Add(PrinterProviderAPI::GetPrinterInfoCallback callback);

  // Completes the request with the provided request id. It runs the request
  // callback and removes the request from the set.
  void Complete(int request_id, base::Value::Dict printer_info);

  // Runs all pending callbacks with empty capability value and clears the
  // set of pending requests.
  void FailAll();

 private:
  int last_request_id_ = 0;
  std::map<int, PrinterProviderAPI::GetPrinterInfoCallback> pending_requests_;
};

// Implements chrome.printerProvider API events.
class PrinterProviderAPIImpl : public PrinterProviderAPI,
                               public PrinterProviderInternalAPIObserver,
                               public ExtensionRegistryObserver {
 public:
  explicit PrinterProviderAPIImpl(content::BrowserContext* browser_context);
  PrinterProviderAPIImpl(const PrinterProviderAPIImpl&) = delete;
  PrinterProviderAPIImpl& operator=(const PrinterProviderAPIImpl&) = delete;
  ~PrinterProviderAPIImpl() override;

 private:
  // PrinterProviderAPI implementation:
  void DispatchGetPrintersRequested(
      const GetPrintersCallback& callback) override;
  void DispatchGetCapabilityRequested(const std::string& printer_id,
                                      GetCapabilityCallback callback) override;
  void DispatchPrintRequested(PrinterProviderPrintJob job,
                              PrintCallback callback) override;
  const PrinterProviderPrintJob* GetPrintJob(const Extension* extension,
                                             int request_id) const override;
  void DispatchGetUsbPrinterInfoRequested(
      const ExtensionId& extension_id,
      const device::mojom::UsbDeviceInfo& device,
      GetPrinterInfoCallback callback) override;

  // PrinterProviderInternalAPIObserver implementation:
  void OnGetPrintersResult(
      const Extension* extension,
      int request_id,
      const PrinterProviderInternalAPIObserver::PrinterInfoVector& result)
      override;
  void OnGetCapabilityResult(const Extension* extension,
                             int request_id,
                             base::Value::Dict result) override;
  void OnPrintResult(const Extension* extension,
                     int request_id,
                     api::printer_provider_internal::PrintError error) override;
  void OnGetUsbPrinterInfoResult(
      const Extension* extension,
      int request_id,
      const api::printer_provider::PrinterInfo* printer_info) override;

  // ExtensionRegistryObserver implementation:
  void OnExtensionUnloaded(content::BrowserContext* browser_context,
                           const Extension* extension,
                           UnloadedExtensionReason reason) override;

  // Called before chrome.printerProvider.onGetPrintersRequested event is
  // dispatched to an extension. It returns whether the extension is interested
  // in the event. If the extension listens to the event, it's added to the set
  // of |request| sources. |request| is |GetPrintersRequest| object associated
  // with the event.
  bool WillRequestPrinters(
      int request_id,
      content::BrowserContext* browser_context,
      mojom::ContextType target_context,
      const Extension* extension,
      const base::Value::Dict* listener_filter,
      std::optional<base::Value::List>& event_args_out,
      mojom::EventFilteringInfoPtr& event_filtering_info_out,
      bool* dispatch_separate_event_out);

  raw_ptr<content::BrowserContext> browser_context_;

  PendingGetPrintersRequests pending_get_printers_requests_;

  std::map<std::string, PendingPrintRequests> pending_print_requests_;

  std::map<std::string, PendingGetCapabilityRequests>
      pending_capability_requests_;

  std::map<std::string, PendingUsbPrinterInfoRequests>
      pending_usb_printer_info_requests_;

  base::ScopedObservation<PrinterProviderInternalAPI,
                          PrinterProviderInternalAPIObserver>
      internal_api_observation_{this};

  base::ScopedObservation<ExtensionRegistry, ExtensionRegistryObserver>
      extension_registry_observation_{this};
};

GetPrintersRequest::GetPrintersRequest(
    const PrinterProviderAPI::GetPrintersCallback& callback)
    : callback_(callback) {
}

GetPrintersRequest::~GetPrintersRequest() {
}

void GetPrintersRequest::AddSource(const ExtensionId& extension_id) {
  extensions_.insert(extension_id);
}

bool GetPrintersRequest::IsDone() const {
  return extensions_.empty();
}

void GetPrintersRequest::ReportForExtension(const ExtensionId& extension_id,
                                            base::Value::List printers) {
  if (extensions_.erase(extension_id) > 0)
    callback_.Run(std::move(printers), IsDone());
}

PendingGetPrintersRequests::PendingGetPrintersRequests() : last_request_id_(0) {
}

PendingGetPrintersRequests::~PendingGetPrintersRequests() {
}

int PendingGetPrintersRequests::Add(
    const PrinterProviderAPI::GetPrintersCallback& callback) {
  pending_requests_.insert(
      std::make_pair(++last_request_id_, GetPrintersRequest(callback)));
  return last_request_id_;
}

bool PendingGetPrintersRequests::CompleteForExtension(
    const ExtensionId& extension_id,
    int request_id,
    base::Value::List result) {
  auto it = pending_requests_.find(request_id);
  if (it == pending_requests_.end())
    return false;

  it->second.ReportForExtension(extension_id, std::move(result));
  if (it->second.IsDone()) {
    pending_requests_.erase(it);
  }
  return true;
}

void PendingGetPrintersRequests::FailAllForExtension(
    const ExtensionId& extension_id) {
  auto it = pending_requests_.begin();
  while (it != pending_requests_.end()) {
    int request_id = it->first;
    // |it| may get deleted during |CompleteForExtension|, so progress it to the
    // next item before calling the method.
    ++it;
    CompleteForExtension(extension_id, request_id, base::Value::List());
  }
}

bool PendingGetPrintersRequests::AddSource(int request_id,
                                           const ExtensionId& extension_id) {
  auto it = pending_requests_.find(request_id);
  if (it == pending_requests_.end())
    return false;

  it->second.AddSource(extension_id);
  return true;
}

PendingGetCapabilityRequests::PendingGetCapabilityRequests()
    : last_request_id_(0) {
}

PendingGetCapabilityRequests::~PendingGetCapabilityRequests() {
}

int PendingGetCapabilityRequests::Add(
    PrinterProviderAPI::GetCapabilityCallback callback) {
  pending_requests_[++last_request_id_] = std::move(callback);
  // Abort the request after the timeout is exceeded.
  base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(&PendingGetCapabilityRequests::Complete,
                     weak_factory_.GetWeakPtr(), last_request_id_,
                     base::Value::Dict()),
      kGetCapabilityTimeout);
  return last_request_id_;
}

void PendingGetCapabilityRequests::Complete(int request_id,
                                            base::Value::Dict response) {
  auto it = pending_requests_.find(request_id);
  if (it == pending_requests_.end())
    return;

  PrinterProviderAPI::GetCapabilityCallback callback = std::move(it->second);
  pending_requests_.erase(it);

  std::move(callback).Run(std::move(response));
}

void PendingGetCapabilityRequests::FailAll() {
  for (auto& request : pending_requests_)
    std::move(request.second).Run(base::Value::Dict());
  pending_requests_.clear();
}

PendingPrintRequests::PendingPrintRequests() : last_request_id_(0) {
}

PendingPrintRequests::~PendingPrintRequests() {
}

int PendingPrintRequests::Add(PrinterProviderPrintJob job,
                              PrinterProviderAPI::PrintCallback callback) {
  PrintRequest request;
  request.callback = std::move(callback);
  request.job = std::move(job);
  pending_requests_[++last_request_id_] = std::move(request);
  return last_request_id_;
}

bool PendingPrintRequests::Complete(
    int request_id,
    api::printer_provider_internal::PrintError error) {
  auto it = pending_requests_.find(request_id);
  if (it == pending_requests_.end())
    return false;

  PrinterProviderAPI::PrintCallback callback = std::move(it->second.callback);
  pending_requests_.erase(it);

  base::Value error_value;
  if (error != api::printer_provider_internal::PrintError::kOk) {
    const std::string error_str =
        error == api::printer_provider_internal::PrintError::kNone
            ? PrinterProviderAPI::GetDefaultPrintError()
            : api::printer_provider_internal::ToString(error);
    error_value = base::Value(error_str);
  }
  std::move(callback).Run(error_value);
  return true;
}

const PrinterProviderPrintJob* PendingPrintRequests::GetPrintJob(
    int request_id) const {
  auto it = pending_requests_.find(request_id);
  if (it == pending_requests_.end())
    return nullptr;

  return &it->second.job;
}

void PendingPrintRequests::FailAll() {
  for (auto& request : pending_requests_) {
    std::move(request.second.callback)
        .Run(base::Value(PrinterProviderAPI::GetDefaultPrintError()));
  }
  pending_requests_.clear();
}

PendingUsbPrinterInfoRequests::PendingUsbPrinterInfoRequests() {
}

PendingUsbPrinterInfoRequests::~PendingUsbPrinterInfoRequests() {
}

int PendingUsbPrinterInfoRequests::Add(
    PrinterProviderAPI::GetPrinterInfoCallback callback) {
  pending_requests_[++last_request_id_] = std::move(callback);
  return last_request_id_;
}

void PendingUsbPrinterInfoRequests::Complete(int request_id,
                                             base::Value::Dict printer_info) {
  auto it = pending_requests_.find(request_id);
  if (it == pending_requests_.end())
    return;

  PrinterProviderAPI::GetPrinterInfoCallback callback = std::move(it->second);
  pending_requests_.erase(it);

  std::move(callback).Run(std::move(printer_info));
}

void PendingUsbPrinterInfoRequests::FailAll() {
  for (auto& request : pending_requests_) {
    std::move(request.second).Run(base::Value::Dict());
  }
  pending_requests_.clear();
}

PrinterProviderAPIImpl::PrinterProviderAPIImpl(
    content::BrowserContext* browser_context)
    : browser_context_(browser_context) {
  internal_api_observation_.Observe(
      PrinterProviderInternalAPI::GetFactoryInstance()->Get(browser_context));
  extension_registry_observation_.Observe(
      ExtensionRegistry::Get(browser_context));
}

PrinterProviderAPIImpl::~PrinterProviderAPIImpl() {
}

void PrinterProviderAPIImpl::DispatchGetPrintersRequested(
    const GetPrintersCallback& callback) {
  EventRouter* event_router = EventRouter::Get(browser_context_);
  if (!event_router->HasEventListener(
          api::printer_provider::OnGetPrintersRequested::kEventName)) {
    callback.Run(base::Value::List(), /*done=*/true);
    return;
  }

  // |pending_get_printers_requests_| take ownership of |request| which gets
  // NULLed out. Save the pointer before passing it to the requests, as it will
  // be needed later on.
  int request_id = pending_get_printers_requests_.Add(callback);

  base::Value::List internal_args;
  // Request id is not part of the public API, but it will be massaged out in
  // custom bindings.
  internal_args.Append(request_id);

  auto event = std::make_unique<Event>(
      events::PRINTER_PROVIDER_ON_GET_PRINTERS_REQUESTED,
      api::printer_provider::OnGetPrintersRequested::kEventName,
      std::move(internal_args));
  // This callback is called synchronously during |BroadcastEvent|, so
  // Unretained is safe.
  event->will_dispatch_callback =
      base::BindRepeating(&PrinterProviderAPIImpl::WillRequestPrinters,
                          base::Unretained(this), request_id);

  event_router->BroadcastEvent(std::move(event));
}

void PrinterProviderAPIImpl::DispatchGetCapabilityRequested(
    const std::string& printer_id,
    GetCapabilityCallback callback) {
  ExtensionId extension_id;
  std::string internal_printer_id;
  if (!ParsePrinterId(printer_id, &extension_id, &internal_printer_id)) {
    std::move(callback).Run(base::Value::Dict());
    return;
  }

  EventRouter* event_router = EventRouter::Get(browser_context_);
  if (!event_router->ExtensionHasEventListener(
          extension_id,
          api::printer_provider::OnGetCapabilityRequested::kEventName)) {
    std::move(callback).Run(base::Value::Dict());
    return;
  }

  int request_id =
      pending_capability_requests_[extension_id].Add(std::move(callback));

  base::Value::List internal_args;
  // Request id is not part of the public API, but it will be massaged out in
  // custom bindings.
  internal_args.Append(request_id);
  internal_args.Append(internal_printer_id);

  std::unique_ptr<Event> event(
      new Event(events::PRINTER_PROVIDER_ON_GET_CAPABILITY_REQUESTED,
                api::printer_provider::OnGetCapabilityRequested::kEventName,
                std::move(internal_args)));

  event_router->DispatchEventToExtension(extension_id, std::move(event));
}

void PrinterProviderAPIImpl::DispatchPrintRequested(PrinterProviderPrintJob job,
                                                    PrintCallback callback) {
  ExtensionId extension_id;
  std::string internal_printer_id;
  if (!ParsePrinterId(job.printer_id, &extension_id, &internal_printer_id)) {
    std::move(callback).Run(base::Value(GetDefaultPrintError()));
    return;
  }

  EventRouter* event_router = EventRouter::Get(browser_context_);
  if (!event_router->ExtensionHasEventListener(
          extension_id, api::printer_provider::OnPrintRequested::kEventName)) {
    std::move(callback).Run(base::Value(GetDefaultPrintError()));
    return;
  }

  api::printer_provider::PrintJob print_job;
  print_job.printer_id = internal_printer_id;

  if (auto ticket =
          api::printer_provider::PrintJob::Ticket::FromValue(job.ticket);
      !ticket) {
    std::move(callback).Run(base::Value(api::printer_provider::ToString(
        api::printer_provider::PrintError::kInvalidTicket)));
    return;
  } else {
    print_job.ticket = std::move(ticket).value();
  }

  print_job.content_type = job.content_type;
  print_job.title = base::UTF16ToUTF8(job.job_title);
  int request_id = pending_print_requests_[extension_id].Add(
      std::move(job), std::move(callback));

  base::Value::List internal_args;
  // Request id is not part of the public API and it will be massaged out in
  // custom bindings.
  internal_args.Append(request_id);
  internal_args.Append(print_job.ToValue());
  auto event = std::make_unique<Event>(
      events::PRINTER_PROVIDER_ON_PRINT_REQUESTED,
      api::printer_provider::OnPrintRequested::kEventName,
      std::move(internal_args));
  event_router->DispatchEventToExtension(extension_id, std::move(event));
}

const PrinterProviderPrintJob* PrinterProviderAPIImpl::GetPrintJob(
    const Extension* extension,
    int request_id) const {
  auto it = pending_print_requests_.find(extension->id());
  if (it == pending_print_requests_.end())
    return nullptr;
  return it->second.GetPrintJob(request_id);
}

void PrinterProviderAPIImpl::DispatchGetUsbPrinterInfoRequested(
    const ExtensionId& extension_id,
    const device::mojom::UsbDeviceInfo& device,
    GetPrinterInfoCallback callback) {
  EventRouter* event_router = EventRouter::Get(browser_context_);
  if (!event_router->ExtensionHasEventListener(
          extension_id,
          api::printer_provider::OnGetUsbPrinterInfoRequested::kEventName)) {
    std::move(callback).Run(base::Value::Dict());
    return;
  }

  int request_id =
      pending_usb_printer_info_requests_[extension_id].Add(std::move(callback));
  api::usb::Device api_device;
  UsbDeviceManager::Get(browser_context_)->GetApiDevice(device, &api_device);

  base::Value::List internal_args;
  // Request id is not part of the public API and it will be massaged out in
  // custom bindings.
  internal_args.Append(request_id);
  internal_args.Append(api_device.ToValue());
  auto event = std::make_unique<Event>(
      events::PRINTER_PROVIDER_ON_GET_USB_PRINTER_INFO_REQUESTED,
      api::printer_provider::OnGetUsbPrinterInfoRequested::kEventName,
      std::move(internal_args));
  event_router->DispatchEventToExtension(extension_id, std::move(event));
}

void PrinterProviderAPIImpl::OnGetPrintersResult(
    const Extension* extension,
    int request_id,
    const PrinterProviderInternalAPIObserver::PrinterInfoVector& result) {
  base::Value::List printer_list;

  // Update some printer description properties to better identify the extension
  // managing the printer.
  for (const api::printer_provider::PrinterInfo& p : result) {
    base::Value::Dict printer(p.ToValue());
    UpdatePrinterWithExtensionInfo(&printer, extension);
    printer_list.Append(std::move(printer));
  }

  PRINTER_LOG(DEBUG) << "Notifying extensionID=" << extension->id()
                     << " of OnGetPrinters request=" << request_id
                     << " completed with printers=" << printer_list;

  pending_get_printers_requests_.CompleteForExtension(
      extension->id(), request_id, std::move(printer_list));
}

void PrinterProviderAPIImpl::OnGetCapabilityResult(const Extension* extension,
                                                   int request_id,
                                                   base::Value::Dict result) {
  PRINTER_LOG(DEBUG) << "Notifying extensionID=" << extension->id()
                     << " that OnGetCapabilility request id=" << request_id
                     << " completed with capabilities=" << result;
  pending_capability_requests_[extension->id()].Complete(request_id,
                                                         std::move(result));
}

void PrinterProviderAPIImpl::OnPrintResult(
    const Extension* extension,
    int request_id,
    api::printer_provider_internal::PrintError error) {
  PRINTER_LOG(DEBUG) << "Notifying extensionID=" << extension->id()
                     << " that OnPrint request id=" << request_id
                     << " has completed with status="
                     << api::printer_provider_internal::ToString(error);
  pending_print_requests_[extension->id()].Complete(request_id, error);
}

void PrinterProviderAPIImpl::OnGetUsbPrinterInfoResult(
    const Extension* extension,
    int request_id,
    const api::printer_provider::PrinterInfo* result) {
  if (result) {
    base::Value::Dict printer(result->ToValue());
    UpdatePrinterWithExtensionInfo(&printer, extension);
    PRINTER_LOG(DEBUG) << "Notifying extensionID=" << extension->id()
                       << " from request=" << request_id << " that "
                       << result->name << " is a USB connected printer";
    pending_usb_printer_info_requests_[extension->id()].Complete(
        request_id, std::move(printer));
  } else {
    PRINTER_LOG(DEBUG) << "Notifying extensionID=" << extension->id()
                       << " from request=" << request_id
                       << " that there are no USB connected printers";
    pending_usb_printer_info_requests_[extension->id()].Complete(
        request_id, base::Value::Dict());
  }
}

void PrinterProviderAPIImpl::OnExtensionUnloaded(
    content::BrowserContext* browser_context,
    const Extension* extension,
    UnloadedExtensionReason reason) {
  PRINTER_LOG(DEBUG) << "Unloading Extension: Name=" << extension->name()
                     << " Version=" << extension->VersionString()
                     << " extensionID=" << extension->id()
                     << " for reason=" << base::ToString(reason);
  pending_get_printers_requests_.FailAllForExtension(extension->id());

  auto print_it = pending_print_requests_.find(extension->id());
  if (print_it != pending_print_requests_.end()) {
    print_it->second.FailAll();
    pending_print_requests_.erase(print_it);
  }

  auto capability_it = pending_capability_requests_.find(extension->id());
  if (capability_it != pending_capability_requests_.end()) {
    capability_it->second.FailAll();
    pending_capability_requests_.erase(capability_it);
  }

  auto usb_it = pending_usb_printer_info_requests_.find(extension->id());
  if (usb_it != pending_usb_printer_info_requests_.end()) {
    usb_it->second.FailAll();
    pending_usb_printer_info_requests_.erase(usb_it);
  }
}

bool PrinterProviderAPIImpl::WillRequestPrinters(
    int request_id,
    content::BrowserContext* browser_context,
    mojom::ContextType target_context,
    const Extension* extension,
    const base::Value::Dict* listener_filter,
    std::optional<base::Value::List>& event_args_out,
    mojom::EventFilteringInfoPtr& event_filtering_info_out,
    bool* dispatch_separate_event_out) {
  if (!extension)
    return false;
  EventRouter* event_router = EventRouter::Get(browser_context_);
  if (!event_router->ExtensionHasEventListener(
          extension->id(),
          api::printer_provider::OnGetPrintersRequested::kEventName)) {
    return false;
  }

  return pending_get_printers_requests_.AddSource(request_id, extension->id());
}

}  // namespace

// static
std::unique_ptr<PrinterProviderAPI> PrinterProviderAPI::Create(
    content::BrowserContext* context) {
  return std::make_unique<PrinterProviderAPIImpl>(context);
}

// static
std::string PrinterProviderAPI::GetDefaultPrintError() {
  return api::printer_provider_internal::ToString(
      api::printer_provider_internal::PrintError::kFailed);
}

}  // namespace extensions