| // Copyright 2020 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef CHROME_BROWSER_PRINTING_PRINT_BACKEND_SERVICE_MANAGER_H_ | 
 | #define CHROME_BROWSER_PRINTING_PRINT_BACKEND_SERVICE_MANAGER_H_ | 
 |  | 
 | #include <memory> | 
 | #include <optional> | 
 | #include <string> | 
 | #include <string_view> | 
 | #include <type_traits> | 
 | #include <variant> | 
 |  | 
 | #include "base/containers/flat_map.h" | 
 | #include "base/containers/flat_set.h" | 
 | #include "base/gtest_prod_util.h" | 
 | #include "base/memory/raw_ptr.h" | 
 | #include "base/memory/raw_ref.h" | 
 | #include "base/no_destructor.h" | 
 | #include "base/types/expected.h" | 
 | #include "base/types/strong_alias.h" | 
 | #include "base/unguessable_token.h" | 
 | #include "base/values.h" | 
 | #include "build/build_config.h" | 
 | #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h" | 
 | #include "mojo/public/cpp/bindings/remote.h" | 
 | #include "mojo/public/cpp/bindings/remote_set.h" | 
 | #include "printing/buildflags/buildflags.h" | 
 |  | 
 | #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG) | 
 | #include "ui/gfx/native_ui_types.h" | 
 | #endif | 
 |  | 
 | #if !BUILDFLAG(ENABLE_OOP_PRINTING) | 
 | #error "Out-of-process printing must be enabled." | 
 | #endif | 
 |  | 
 | namespace crash_keys { | 
 | class ScopedPrinterInfo; | 
 | } | 
 |  | 
 | namespace printing { | 
 |  | 
 | #if BUILDFLAG(IS_WIN) | 
 | class PrinterXmlParserImpl; | 
 | #endif  // BUILDFLAG(IS_WIN) | 
 |  | 
 | class PrintedPage; | 
 |  | 
 | class PrintBackendServiceManager { | 
 |  public: | 
 |   // A RemoteId is used to identify a particular PrintBackendService that | 
 |   // will be servicing queries and printing of a document.  This abstraction | 
 |   // allows for identifying the service desired to be used, without relying | 
 |   // upon a printer name (which sometimes is not available, such as when | 
 |   // doing general queries). | 
 |   using RemoteId = base::StrongAlias<class RemoteIdTag, uint32_t>; | 
 |  | 
 |   // A ClientId represents a printing action that is being performed by a | 
 |   // browser tab.  There can be different ClientIds depending upon the | 
 |   // action that is being performed: | 
 |   // - During Print Preview, the tab will have a ClientId for the related | 
 |   //   queries.  This ClientId might make use of multiple different RemoteIds, | 
 |   //   depending upon the destinations selected during the preview. | 
 |   // - If a user initiates system print, then a different ClientId is used to | 
 |   //   manage the actions of the system dialog. | 
 |   // - Once it is time to print a document, a different ClientId is used for | 
 |   //   managing the printing sequence. | 
 |   // For system print dialog and document printing, using the same RemoteId | 
 |   // between the two different clients is important to be able to maintain the | 
 |   // same device context in the PrintBackendService. | 
 |   using ClientId = base::StrongAlias<class ClientIdTag, uint32_t>; | 
 |  | 
 |   // A ContextId is an abstraction of a printing context which resides in the | 
 |   // PrintBackendService.  There can be multiple ContextIds associated with a | 
 |   // RemoteId, since a service could be supporting a system print dialog as | 
 |   // well as multiple documents being printed.  A ContextId is only ever | 
 |   // associated with a single RemoteId. | 
 |   // For system print dialogs, the ContextId used to get the settings will | 
 |   // be shared with another ClientId for printing the document, so that the | 
 |   // same device context settings are used at printing time. | 
 |   using ContextId = base::StrongAlias<class ContextIdTag, uint32_t>; | 
 |  | 
 |   // Contains set of client IDs. | 
 |   using ClientsSet = base::flat_set<ClientId>; | 
 |  | 
 |   // Mapping of the RemoteId | 
 |   using QueryWithUiClientsMap = base::flat_map<ClientId, RemoteId>; | 
 |  | 
 |   // Mapping of clients to each remote ID that is for printing. | 
 |   using PrintClientsMap = base::flat_map<RemoteId, ClientsSet>; | 
 |  | 
 |   // Amount of idle time to wait before resetting the connection to the service. | 
 |   static constexpr base::TimeDelta kNoClientsRegisteredResetOnIdleTimeout = | 
 |       base::Seconds(10); | 
 |   static constexpr base::TimeDelta kClientsRegisteredResetOnIdleTimeout = | 
 |       base::Seconds(120); | 
 |  | 
 |   PrintBackendServiceManager(const PrintBackendServiceManager&) = delete; | 
 |   PrintBackendServiceManager& operator=(const PrintBackendServiceManager&) = | 
 |       delete; | 
 |  | 
 |   // Launch a service that is intended to persist indefinitely and can be used | 
 |   // by all further clients. | 
 |   static void LaunchPersistentService(); | 
 |  | 
 |   // Client registration routines.  These act as a signal of impending activity | 
 |   // enabling possible optimizations within the manager.  They return an ID | 
 |   // which the callers are to use with `UnregisterClient()` once they have | 
 |   // completed their printing activity. | 
 |  | 
 |   // Register as a client of PrintBackendServiceManager for print queries. | 
 |   ClientId RegisterQueryClient(); | 
 |  | 
 |   // Register as a client of PrintBackendServiceManager for print queries which | 
 |   // require a system print dialog UI.  If a platform cannot support concurrent | 
 |   // queries of this type then this will return `std::nullopt` if another | 
 |   // client is already registered. | 
 |   std::optional<ClientId> RegisterQueryWithUiClient(); | 
 |  | 
 |   // Register as a client of PrintBackendServiceManager for printing a document | 
 |   // to a specific printer. | 
 |   ClientId RegisterPrintDocumentClient(const std::string& printer_name); | 
 |  | 
 |   // Register as a client of PrintBackendServiceManager for printing a document | 
 |   // to a specific printer.  Use the same `RemoteId` for this new printing | 
 |   // client as has been used by the indicated query with UI client.  This method | 
 |   // will DCHECK if the client ID provided is not for a query with UI client. | 
 |   // Call can return nullopt if the service has terminated by the time this call | 
 |   // is made and the remote used by client `id` no longer exists. | 
 |   std::optional<ClientId> RegisterPrintDocumentClientReusingClientRemote( | 
 |       ClientId id); | 
 |  | 
 |   // Notify the manager that this client is no longer needing print backend | 
 |   // services.  This signal might alter the manager's internal optimizations. | 
 |   void UnregisterClient(ClientId id); | 
 |  | 
 |   // Wrappers around mojom::PrintBackendService call. | 
 |   void EnumeratePrinters( | 
 |       mojom::PrintBackendService::EnumeratePrintersCallback callback); | 
 |   void FetchCapabilities( | 
 |       const std::string& printer_name, | 
 |       mojom::PrintBackendService::FetchCapabilitiesCallback callback); | 
 |   void GetDefaultPrinterName( | 
 |       mojom::PrintBackendService::GetDefaultPrinterNameCallback callback); | 
 | #if BUILDFLAG(IS_CHROMEOS) | 
 |   void GetPrinterSemanticCapsAndDefaults( | 
 |       const std::string& printer_name, | 
 |       mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsCallback | 
 |           callback); | 
 | #endif | 
 | #if BUILDFLAG(IS_WIN) | 
 |   void GetPaperPrintableArea( | 
 |       const std::string& printer_name, | 
 |       const PrintSettings::RequestedMedia& media, | 
 |       mojom::PrintBackendService::GetPaperPrintableAreaCallback callback); | 
 | #endif | 
 |   ContextId EstablishPrintingContext(ClientId client_id, | 
 |                                      const std::string& printer_name | 
 | #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG) | 
 |                                      , | 
 |                                      gfx::NativeView parent_view | 
 | #endif | 
 |   ); | 
 |   void UseDefaultSettings( | 
 |       ClientId client_id, | 
 |       ContextId context_id, | 
 |       mojom::PrintBackendService::UseDefaultSettingsCallback callback); | 
 | #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG) | 
 |   void AskUserForSettings( | 
 |       ClientId client_id, | 
 |       ContextId context_id, | 
 |       int max_pages, | 
 |       bool has_selection, | 
 |       bool is_scripted, | 
 |       mojom::PrintBackendService::AskUserForSettingsCallback callback); | 
 | #endif | 
 |   // `UpdatePrintSettings()` can be used prior to initiating a system print | 
 |   // dialog or right before starting to print a document.  The first requires a | 
 |   // `client_id` of `kQueryWithUi` type, while the latter requires a the ID to | 
 |   // be of type `kPrintDocument`. | 
 |   // The destination printer is still unknown when initiating a system print | 
 |   // dialog, so `printer_name` will be empty in this case.  The destination | 
 |   // must be known when starting to print a document.  `UpdatePrintSettings()` | 
 |   // uses this insight to know what kind of client type is to be expected for | 
 |   // the provided `client_id`.  The function will CHECK if the `client_id` | 
 |   // is not registered for the expected type. | 
 |   void UpdatePrintSettings( | 
 |       ClientId client_id, | 
 |       const std::string& printer_name, | 
 |       ContextId context_id, | 
 |       base::Value::Dict job_settings, | 
 |       mojom::PrintBackendService::UpdatePrintSettingsCallback callback); | 
 |   // `StartPrinting()` initiates the printing of a document.  The optional | 
 |   // `settings` is used in the case where a system print dialog is invoked | 
 |   // from in the browser, and this provides those settings for printing. | 
 |   void StartPrinting( | 
 |       ClientId client_id, | 
 |       const std::string& printer_name, | 
 |       ContextId context_id, | 
 |       int document_cookie, | 
 |       const std::u16string& document_name, | 
 | #if !BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG) | 
 |       std::optional<PrintSettings> settings, | 
 | #endif | 
 |       mojom::PrintBackendService::StartPrintingCallback callback); | 
 | #if BUILDFLAG(IS_WIN) | 
 |   void RenderPrintedPage( | 
 |       ClientId client_id, | 
 |       const std::string& printer_name, | 
 |       int document_cookie, | 
 |       const PrintedPage& page, | 
 |       mojom::MetafileDataType page_data_type, | 
 |       base::ReadOnlySharedMemoryRegion serialized_page_data, | 
 |       mojom::PrintBackendService::RenderPrintedPageCallback callback); | 
 | #endif | 
 |   void RenderPrintedDocument( | 
 |       ClientId client_id, | 
 |       const std::string& printer_name, | 
 |       int document_cookie, | 
 |       uint32_t page_count, | 
 |       mojom::MetafileDataType data_type, | 
 |       base::ReadOnlySharedMemoryRegion serialized_data, | 
 |       mojom::PrintBackendService::RenderPrintedDocumentCallback callback); | 
 |   void DocumentDone(ClientId client_id, | 
 |                     const std::string& printer_name, | 
 |                     int document_cookie, | 
 |                     mojom::PrintBackendService::DocumentDoneCallback callback); | 
 |   void Cancel(ClientId client_id, | 
 |               const std::string& printer_name, | 
 |               int document_cookie, | 
 |               mojom::PrintBackendService::CancelCallback callback); | 
 |  | 
 |   // Query if printer driver has been found to require elevated privilege in | 
 |   // order to have print queries/commands succeed. | 
 |   bool PrinterDriverFoundToRequireElevatedPrivilege( | 
 |       const std::string& printer_name) const; | 
 |  | 
 |   // Make note that `printer_name` has been detected as requiring elevated | 
 |   // privileges in order to operate. | 
 |   void SetPrinterDriverFoundToRequireElevatedPrivilege( | 
 |       const std::string& printer_name); | 
 |  | 
 |   // Overrides the print backend service for testing.  Caller retains ownership | 
 |   // of `remote`.  Can be reset by passing in nullptr. | 
 |   void SetServiceForTesting(mojo::Remote<mojom::PrintBackendService>* remote); | 
 |  | 
 |   // Overrides the print backend service for testing when an alternate service | 
 |   // is required for fallback processing after an access denied error.  Caller | 
 |   // retains ownership of `remote`.  Can be reset by passing in nullptr. | 
 |   void SetServiceForFallbackTesting( | 
 |       mojo::Remote<mojom::PrintBackendService>* remote); | 
 |  | 
 |   // There is to be at most one instance of this at a time. | 
 |   static PrintBackendServiceManager& GetInstance(); | 
 |  | 
 |   // Test support to revert to a fresh instance. | 
 |   static void ResetForTesting(); | 
 |  | 
 |  private: | 
 |   friend base::NoDestructor<PrintBackendServiceManager>; | 
 |   friend class SystemAccessProcessPrintBrowserTestBase; | 
 |   FRIEND_TEST_ALL_PREFIXES(PrintBackendServiceManagerTest, | 
 |                            IsIdleTimeoutUpdateNeededForRegisteredClient); | 
 |   FRIEND_TEST_ALL_PREFIXES(PrintBackendServiceManagerTest, | 
 |                            IsIdleTimeoutUpdateNeededForUnregisteredClient); | 
 |  | 
 |   enum class ClientType { | 
 |     // Print Preview scenario, where printer might not be known.  Only performs | 
 |     // queries, none of which would invoke a system dialog. | 
 |     kQuery, | 
 |     // System print scenario, where printer is not known. Only performs queries, | 
 |     // and can require a window-modal system dialog be displayed to satisfy | 
 |     // those queries. | 
 |     kQueryWithUi, | 
 |     // Printer is known, and printing of a document will be performed.  System | 
 |     // dialogs might be required to complete printing (e.g., if driver saves to | 
 |     // a file). | 
 |     kPrintDocument, | 
 |   }; | 
 |  | 
 |   // Type that maps to the return of all settings calls. | 
 |   using PrintSettingsResult = base::expected<PrintSettings, mojom::ResultCode>; | 
 |  | 
 |   // Types to track saved callbacks associated with currently executing mojom | 
 |   // service calls.  These will be run either after a Mojom call finishes | 
 |   // executing or if the service should disconnect before the mojom service | 
 |   // calls complete. | 
 |   // These need to be able to be found as a group for a particular remote that | 
 |   // might become disconnected, and so a map-per-remote is used as a container. | 
 |   // Use of a map allows for an ID key to be used to easily find any individual | 
 |   // callback that can be discarded once a service call succeeds normally. | 
 |  | 
 |   // Key is a callback ID. | 
 |   template <class... T> | 
 |   using SavedCallbacks = | 
 |       base::flat_map<base::UnguessableToken, base::OnceCallback<void(T...)>>; | 
 |  | 
 |   // Key is the remote ID that enables finding the correct remote.  Note that | 
 |   // the remote ID does not necessarily mean the printer name. | 
 |   template <class... T> | 
 |   using RemoteSavedCallbacks = base::flat_map<RemoteId, SavedCallbacks<T...>>; | 
 |  | 
 |   // Note: these follow the signature of the generated mojo callbacks after | 
 |   // typemapping, as seen in the generated print_backend_service.mojom.h. | 
 |   using RemoteSavedEnumeratePrintersCallbacks = | 
 |       RemoteSavedCallbacks<mojom::PrintBackendService::EnumeratePrintersResult>; | 
 |   using RemoteSavedFetchCapabilitiesCallbacks = | 
 |       RemoteSavedCallbacks<mojom::PrintBackendService::FetchCapabilitiesResult>; | 
 |   using RemoteSavedGetDefaultPrinterNameCallbacks = RemoteSavedCallbacks< | 
 |       mojom::PrintBackendService::GetDefaultPrinterNameResult>; | 
 | #if BUILDFLAG(IS_CHROMEOS) | 
 |   using RemoteSavedGetPrinterSemanticCapsAndDefaultsCallbacks = | 
 |       RemoteSavedCallbacks< | 
 |           mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsResult>; | 
 | #endif | 
 | #if BUILDFLAG(IS_WIN) | 
 |   using RemoteSavedGetPaperPrintableAreaCallbacks = | 
 |       RemoteSavedCallbacks<const gfx::Rect&>; | 
 | #endif | 
 |   using RemoteSavedUseDefaultSettingsCallbacks = | 
 |       RemoteSavedCallbacks<PrintSettingsResult>; | 
 | #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG) | 
 |   using RemoteSavedAskUserForSettingsCallbacks = | 
 |       RemoteSavedCallbacks<PrintSettingsResult>; | 
 | #endif | 
 |   using RemoteSavedUpdatePrintSettingsCallbacks = | 
 |       RemoteSavedCallbacks<PrintSettingsResult>; | 
 |   using RemoteSavedStartPrintingCallbacks = | 
 |       RemoteSavedCallbacks<mojom::ResultCode, int /*job_id*/>; | 
 | #if BUILDFLAG(IS_WIN) | 
 |   using RemoteSavedRenderPrintedPageCallbacks = | 
 |       RemoteSavedCallbacks<mojom::ResultCode>; | 
 | #endif | 
 |   using RemoteSavedRenderPrintedDocumentCallbacks = | 
 |       RemoteSavedCallbacks<mojom::ResultCode>; | 
 |   using RemoteSavedDocumentDoneCallbacks = | 
 |       RemoteSavedCallbacks<mojom::ResultCode>; | 
 |   using RemoteSavedCancelCallbacks = RemoteSavedCallbacks<>; | 
 |  | 
 |   // Bundle of the `PrintBackendService` and its sandboxed/unsandboxed host | 
 |   // remotes. | 
 |   template <class T> | 
 |   struct RemotesBundle { | 
 |     RemotesBundle() = default; | 
 |     ~RemotesBundle() = default; | 
 |     mojo::Remote<mojom::PrintBackendService> service; | 
 |     mojo::Remote<T> host; | 
 |   }; | 
 |  | 
 |   template <class T> | 
 |   using RemotesBundleMap = | 
 |       base::flat_map<RemoteId, std::unique_ptr<RemotesBundle<T>>>; | 
 |  | 
 |   // PrintBackendServiceManager needs to be able to run a callback either after | 
 |   // a successful return from the service or after the remote was disconnected. | 
 |   // This structure is used to save the callback's context. | 
 |   struct CallbackContext { | 
 |     CallbackContext(); | 
 |     CallbackContext(CallbackContext&& other) noexcept; | 
 |     ~CallbackContext(); | 
 |  | 
 |     bool is_sandboxed; | 
 |     RemoteId remote_id; | 
 |     base::UnguessableToken saved_callback_id; | 
 |   }; | 
 |  | 
 |   struct ServiceAndCallbackContext { | 
 |     ServiceAndCallbackContext( | 
 |         CallbackContext callback_context, | 
 |         const mojo::Remote<mojom::PrintBackendService>& backend_service); | 
 |     ServiceAndCallbackContext(ServiceAndCallbackContext&& other) = delete; | 
 |     ~ServiceAndCallbackContext(); | 
 |     CallbackContext context; | 
 |     const raw_ref<const mojo::Remote<mojom::PrintBackendService>> service; | 
 |   }; | 
 |  | 
 |   PrintBackendServiceManager(); | 
 |   ~PrintBackendServiceManager(); | 
 |  | 
 |   static std::string ClientTypeToString(ClientType client_type); | 
 |  | 
 |   static void LogCallToRemote(std::string_view name, | 
 |                               const CallbackContext& context); | 
 |   static void LogCallbackFromRemote(std::string_view name, | 
 |                                     const CallbackContext& context); | 
 |  | 
 |   void SetCrashKeys(const std::string& printer_name); | 
 |  | 
 |   // Determine the remote ID that is used for the specified `printer_name`. | 
 |   // Could generate a new RemoteId if one has not been previously created | 
 |   // for the indicated printer. | 
 |   RemoteId GetRemoteIdForPrinterName(const std::string& printer_name); | 
 |  | 
 |   // Determine the remote ID that is used for the specified `client_id` of a | 
 |   // query with UI client.  Will crash if no such client is found. | 
 |   RemoteId GetRemoteIdForQueryWithUiClientId(ClientId client_id) const; | 
 |  | 
 |   // Determine the remote ID that is used for the specified `client_id` of a | 
 |   // print document client.  Will crash if no such client is found. | 
 |   RemoteId GetRemoteIdForPrintDocumentClientId(ClientId client_id) const; | 
 |  | 
 |   // Common helper for registering clients.  The `destination` parameter can be | 
 |   // either a `std::string` for a printer name or a `RemoteId` which was | 
 |   // generated from a prior registration.  This method will DCHECK if the | 
 |   // `destination` is a `RemoteId` and the registration requires launching | 
 |   // another service instance. | 
 |   std::optional<ClientId> RegisterClient( | 
 |       ClientType client_type, | 
 |       std::variant<std::string, RemoteId> destination); | 
 |  | 
 |   // Get the total number of clients registered. | 
 |   size_t GetClientsRegisteredCount() const; | 
 |  | 
 | #if BUILDFLAG(IS_WIN) | 
 |   // Query if printer driver has known reasons for requiring elevated | 
 |   // privileges in order to operate.  In these cases relying upon fallback | 
 |   // after an access-denied error is not preferable.  Any such reasons are | 
 |   // platform specific. | 
 |   bool PrinterDriverKnownToRequireElevatedPrivilege( | 
 |       const std::string& printer_name, | 
 |       ClientType client_type) const; | 
 | #endif | 
 |  | 
 |   // Determines if a service should be sandboxed when launched. | 
 |   bool ShouldServiceBeSandboxed(const std::string& printer_name, | 
 |                                 ClientType client_type) const; | 
 |  | 
 |   // Acquires a remote handle to the Print Backend Service instance, launching a | 
 |   // process to host the service if necessary. | 
 |   const mojo::Remote<mojom::PrintBackendService>& | 
 |   GetService(const RemoteId& remote_id, ClientType client_type, bool sandboxed); | 
 |  | 
 |   // Helper to `GetService` for a particular remotes bundle type. | 
 |   template <class T> | 
 |   mojo::Remote<mojom::PrintBackendService>& GetServiceFromBundle( | 
 |       const RemoteId& remote_id, | 
 |       ClientType client_type, | 
 |       bool sandboxed, | 
 |       RemotesBundleMap<T>& bundle_map); | 
 |  | 
 |   // Get the idle timeout value to user for a particular client type. | 
 |   constexpr base::TimeDelta GetClientTypeIdleTimeout( | 
 |       ClientType client_type) const; | 
 |  | 
 |   // Whether any clients are queries with UI to `remote_id`. | 
 |   bool HasQueryWithUiClientForRemoteId(const RemoteId& remote_id) const; | 
 |  | 
 |   // Whether any clients are printing documents to `remote_id`. | 
 |   bool HasPrintDocumentClientForRemoteId(const RemoteId& remote_id) const; | 
 |  | 
 |   // Get the number of clients printing documents to `remote_id`. | 
 |   size_t GetPrintDocumentClientsCountForRemoteId( | 
 |       const RemoteId& remote_id) const; | 
 |  | 
 |   // Determine if idle timeout should be modified based upon there having been | 
 |   // a new client registered for `registered_client_type`. | 
 |   std::optional<base::TimeDelta> DetermineIdleTimeoutUpdateOnRegisteredClient( | 
 |       ClientType registered_client_type, | 
 |       const RemoteId& remote_id) const; | 
 |  | 
 |   // Determine if idle timeout should be modified after a client of type | 
 |   // `unregistered_client_type` has been unregistered. | 
 |   std::optional<base::TimeDelta> DetermineIdleTimeoutUpdateOnUnregisteredClient( | 
 |       ClientType unregistered_client_type, | 
 |       const RemoteId& remote_id) const; | 
 |  | 
 |   // Helper functions to adjust service idle timeout duration. | 
 |   void SetServiceIdleHandler( | 
 |       mojo::Remote<printing::mojom::PrintBackendService>& service, | 
 |       bool sandboxed, | 
 |       const RemoteId& remote_id, | 
 |       const base::TimeDelta& timeout); | 
 |   void UpdateServiceIdleTimeoutByRemoteId(const RemoteId& remote_id, | 
 |                                           const base::TimeDelta& timeout); | 
 |  | 
 |   // Callback when predetermined idle timeout occurs indicating no in-flight | 
 |   // messages for a short period of time.  `sandboxed` is used to distinguish | 
 |   // which mapping of remotes the timeout applies to. | 
 |   void OnIdleTimeout(bool sandboxed, const RemoteId& remote_id); | 
 |  | 
 |   // Callback when service has disconnected (e.g., process crashes). | 
 |   // `sandboxed` is used to distinguish which mapping of remotes the | 
 |   // disconnection applies to. | 
 |   void OnRemoteDisconnected(bool sandboxed, const RemoteId& remote_id); | 
 |  | 
 |   // Helper function to choose correct saved callbacks mapping. | 
 |   RemoteSavedEnumeratePrintersCallbacks& | 
 |   GetRemoteSavedEnumeratePrintersCallbacks(bool sandboxed); | 
 |   RemoteSavedFetchCapabilitiesCallbacks& | 
 |   GetRemoteSavedFetchCapabilitiesCallbacks(bool sandboxed); | 
 |   RemoteSavedGetDefaultPrinterNameCallbacks& | 
 |   GetRemoteSavedGetDefaultPrinterNameCallbacks(bool sandboxed); | 
 | #if BUILDFLAG(IS_CHROMEOS) | 
 |   RemoteSavedGetPrinterSemanticCapsAndDefaultsCallbacks& | 
 |   GetRemoteSavedGetPrinterSemanticCapsAndDefaultsCallbacks(bool sandboxed); | 
 | #endif | 
 | #if BUILDFLAG(IS_WIN) | 
 |   RemoteSavedGetPaperPrintableAreaCallbacks& | 
 |   GetRemoteSavedGetPaperPrintableAreaCallbacks(bool sandboxed); | 
 | #endif | 
 |   RemoteSavedUseDefaultSettingsCallbacks& | 
 |   GetRemoteSavedUseDefaultSettingsCallbacks(bool sandboxed); | 
 | #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG) | 
 |   RemoteSavedAskUserForSettingsCallbacks& | 
 |   GetRemoteSavedAskUserForSettingsCallbacks(bool sandboxed); | 
 | #endif | 
 |   RemoteSavedUpdatePrintSettingsCallbacks& | 
 |   GetRemoteSavedUpdatePrintSettingsCallbacks(bool sandboxed); | 
 |   RemoteSavedStartPrintingCallbacks& GetRemoteSavedStartPrintingCallbacks( | 
 |       bool sandboxed); | 
 | #if BUILDFLAG(IS_WIN) | 
 |   RemoteSavedRenderPrintedPageCallbacks& | 
 |   GetRemoteSavedRenderPrintedPageCallbacks(bool sandboxed); | 
 | #endif | 
 |   RemoteSavedRenderPrintedDocumentCallbacks& | 
 |   GetRemoteSavedRenderPrintedDocumentCallbacks(bool sandboxed); | 
 |   RemoteSavedDocumentDoneCallbacks& GetRemoteSavedDocumentDoneCallbacks( | 
 |       bool sandboxed); | 
 |   RemoteSavedCancelCallbacks& GetRemoteSavedCancelCallbacks(bool sandboxed); | 
 |  | 
 |   // Helper function to get the service and initialize a `context` for a given | 
 |   // `printer_name`.  This is used for calls supporting Print Preview, where | 
 |   // the client type is `kQuery`. | 
 |   ServiceAndCallbackContext GetServiceAndCallbackContextForQuery( | 
 |       const std::string& printer_name); | 
 |  | 
 |   // Helper function to get the service and initialize a `context` for a given | 
 |   // query with UI `client_id`.  Use `printer_name` for extra sandbox behavior | 
 |   // handling.  This is used for calls supporting system print dialogs and | 
 |   // printing of a document. | 
 |   ServiceAndCallbackContext GetServiceAndCallbackContextForQueryWithUiClient( | 
 |       ClientId client_id, | 
 |       const std::string& printer_name); | 
 |  | 
 |   // Helper function to get the service and initialize a `context` for a given | 
 |   // print document `client_id`.  Use `printer_name` for extra sandbox behavior | 
 |   // handling.  This is used for calls supporting system print dialogs and | 
 |   // printing of a document. | 
 |   ServiceAndCallbackContext GetServiceAndCallbackContextForPrintDocumentClient( | 
 |       ClientId client_id, | 
 |       const std::string& printer_name); | 
 |  | 
 |   // Helper functions to save outstanding callbacks. | 
 |   template <class... T, class... X> | 
 |   void SaveCallback(RemoteSavedCallbacks<T...>& saved_callbacks, | 
 |                     const RemoteId& remote_id, | 
 |                     const base::UnguessableToken& saved_callback_id, | 
 |                     base::OnceCallback<void(X...)> callback); | 
 |  | 
 |   // Helper functions for local callback wrappers for mojom calls. | 
 |   template <class... T, class... X> | 
 |   void ServiceCallbackDone(RemoteSavedCallbacks<T...>& saved_callbacks, | 
 |                            const RemoteId& remote_id, | 
 |                            const base::UnguessableToken& saved_callback_id, | 
 |                            X... data); | 
 |  | 
 |   // Local callback wrappers for mojom calls. | 
 |   void OnDidEnumeratePrinters( | 
 |       const CallbackContext& context, | 
 |       mojom::PrintBackendService::EnumeratePrintersResult printer_list); | 
 |   void OnDidFetchCapabilities( | 
 |       const CallbackContext& context, | 
 |       mojom::PrintBackendService::FetchCapabilitiesResult | 
 |           printer_caps_and_info); | 
 |   void OnDidGetDefaultPrinterName( | 
 |       const CallbackContext& context, | 
 |       mojom::PrintBackendService::GetDefaultPrinterNameResult printer_name); | 
 | #if BUILDFLAG(IS_CHROMEOS) | 
 |   void OnDidGetPrinterSemanticCapsAndDefaults( | 
 |       const CallbackContext& context, | 
 |       mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsResult | 
 |           printer_caps); | 
 | #endif | 
 | #if BUILDFLAG(IS_WIN) | 
 |   void OnDidGetPaperPrintableArea(const CallbackContext& context, | 
 |                                   const gfx::Rect& printable_area_um); | 
 | #endif | 
 |   void OnDidUseDefaultSettings(const CallbackContext& context, | 
 |                                PrintSettingsResult settings); | 
 | #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG) | 
 |   void OnDidAskUserForSettings(const CallbackContext& context, | 
 |                                PrintSettingsResult settings); | 
 | #endif | 
 |   void OnDidUpdatePrintSettings(const CallbackContext& context, | 
 |                                 PrintSettingsResult printer_caps); | 
 |   void OnDidStartPrinting(const CallbackContext& context, | 
 |                           mojom::ResultCode result, | 
 |                           int job_id); | 
 | #if BUILDFLAG(IS_WIN) | 
 |   void OnDidRenderPrintedPage(const CallbackContext& context, | 
 |                               mojom::ResultCode result); | 
 | #endif | 
 |   void OnDidRenderPrintedDocument(const CallbackContext& context, | 
 |                                   mojom::ResultCode result); | 
 |   void OnDidDocumentDone(const CallbackContext& context, | 
 |                          mojom::ResultCode result); | 
 |   void OnDidCancel(const CallbackContext& context); | 
 |  | 
 |   // Helper functions to run outstanding callbacks when a remote has become | 
 |   // disconnected. | 
 |   template <class... T> | 
 |   void RunSavedCallbacks(RemoteSavedCallbacks<T...>& saved_callbacks, | 
 |                          const RemoteId& remote_id, | 
 |                          typename std::remove_reference<T>::type... result); | 
 |   template <class... T> | 
 |   void RunSavedResultCallbacks( | 
 |       RemoteSavedCallbacks<T...>& saved_callbacks, | 
 |       const RemoteId& remote_id, | 
 |       typename std::remove_reference<T>::type... result); | 
 |  | 
 |   // Test support for client ID management. | 
 |   static void SetClientsForTesting( | 
 |       const ClientsSet& query_clients, | 
 |       const QueryWithUiClientsMap& query_with_ui_clients, | 
 |       const PrintClientsMap& print_document_clients); | 
 |  | 
 | #if BUILDFLAG(IS_WIN) | 
 |   // Printer XML Parser implementation used to allow Print Backend Service to | 
 |   // send XML parse requests to the browser process. | 
 |   std::unique_ptr<PrinterXmlParserImpl> xml_parser_; | 
 | #endif  // BUILDFLAG(IS_WIN) | 
 |  | 
 |   // Bundles of remotes for the Print Backend Service and their corresponding | 
 |   // wrapping hosts, to manage these sets until they disconnect.  The sandboxed | 
 |   // and unsandboxed services are kept separate. | 
 |   RemotesBundleMap<mojom::SandboxedPrintBackendHost> sandboxed_remotes_bundles_; | 
 |   RemotesBundleMap<mojom::UnsandboxedPrintBackendHost> | 
 |       unsandboxed_remotes_bundles_; | 
 |  | 
 |   // Members tracking active clients to aid retention of a service process. | 
 |  | 
 |   // Set of IDs for clients actively engaged in printing queries.  This could | 
 |   // include any tab which has triggered Print Preview. | 
 |   ClientsSet query_clients_; | 
 |  | 
 |   // Set of IDs for clients actively engaged in a printing query which requires | 
 |   // the use of a UI.  Such a UI corresponds to a modal system dialog.  For | 
 |   // Linux there can be multiple of these, but for other platforms there can be | 
 |   // at most one such client.  Track the `RemoteId` which is associated with | 
 |   // each such client. | 
 |   QueryWithUiClientsMap query_with_ui_clients_; | 
 |  | 
 |   // Map of remote ID to the set of clients printing documents to it. | 
 |   PrintClientsMap print_document_clients_; | 
 |  | 
 |   // Simple counter for incrementing ClientId.  All ClientId objects are used | 
 |   // only within the browser process, so no need for this to be a more | 
 |   // complicated token. | 
 |   uint32_t last_client_id_ = 0; | 
 |  | 
 |   // Simple counter for incrementing ContextId.  ContextId objects are passed | 
 |   // as parameters to the service but are never provided back, so no need for | 
 |   // this to be a more complicated token. | 
 |   uint32_t last_context_id_ = 0; | 
 |  | 
 |   // Track the saved callbacks for each remote. | 
 |   RemoteSavedEnumeratePrintersCallbacks | 
 |       sandboxed_saved_enumerate_printers_callbacks_; | 
 |   RemoteSavedEnumeratePrintersCallbacks | 
 |       unsandboxed_saved_enumerate_printers_callbacks_; | 
 |   RemoteSavedFetchCapabilitiesCallbacks | 
 |       sandboxed_saved_fetch_capabilities_callbacks_; | 
 |   RemoteSavedFetchCapabilitiesCallbacks | 
 |       unsandboxed_saved_fetch_capabilities_callbacks_; | 
 |   RemoteSavedGetDefaultPrinterNameCallbacks | 
 |       sandboxed_saved_get_default_printer_name_callbacks_; | 
 |   RemoteSavedGetDefaultPrinterNameCallbacks | 
 |       unsandboxed_saved_get_default_printer_name_callbacks_; | 
 | #if BUILDFLAG(IS_CHROMEOS) | 
 |   RemoteSavedGetPrinterSemanticCapsAndDefaultsCallbacks | 
 |       sandboxed_saved_get_printer_semantic_caps_and_defaults_callbacks_; | 
 |   RemoteSavedGetPrinterSemanticCapsAndDefaultsCallbacks | 
 |       unsandboxed_saved_get_printer_semantic_caps_and_defaults_callbacks_; | 
 | #endif | 
 | #if BUILDFLAG(IS_WIN) | 
 |   RemoteSavedGetPaperPrintableAreaCallbacks | 
 |       sandboxed_saved_get_paper_printable_area_callbacks_; | 
 |   RemoteSavedGetPaperPrintableAreaCallbacks | 
 |       unsandboxed_saved_get_paper_printable_area_callbacks_; | 
 | #endif | 
 |   RemoteSavedUseDefaultSettingsCallbacks | 
 |       sandboxed_saved_use_default_settings_callbacks_; | 
 |   RemoteSavedUseDefaultSettingsCallbacks | 
 |       unsandboxed_saved_use_default_settings_callbacks_; | 
 | #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG) | 
 |   RemoteSavedAskUserForSettingsCallbacks | 
 |       sandboxed_saved_ask_user_for_settings_callbacks_; | 
 |   RemoteSavedAskUserForSettingsCallbacks | 
 |       unsandboxed_saved_ask_user_for_settings_callbacks_; | 
 | #endif | 
 |   RemoteSavedUpdatePrintSettingsCallbacks | 
 |       sandboxed_saved_update_print_settings_callbacks_; | 
 |   RemoteSavedUpdatePrintSettingsCallbacks | 
 |       unsandboxed_saved_update_print_settings_callbacks_; | 
 |   RemoteSavedStartPrintingCallbacks sandboxed_saved_start_printing_callbacks_; | 
 |   RemoteSavedStartPrintingCallbacks unsandboxed_saved_start_printing_callbacks_; | 
 | #if BUILDFLAG(IS_WIN) | 
 |   RemoteSavedRenderPrintedPageCallbacks | 
 |       sandboxed_saved_render_printed_page_callbacks_; | 
 |   RemoteSavedRenderPrintedPageCallbacks | 
 |       unsandboxed_saved_render_printed_page_callbacks_; | 
 | #endif | 
 |   RemoteSavedRenderPrintedDocumentCallbacks | 
 |       sandboxed_saved_render_printed_document_callbacks_; | 
 |   RemoteSavedRenderPrintedDocumentCallbacks | 
 |       unsandboxed_saved_render_printed_document_callbacks_; | 
 |   RemoteSavedDocumentDoneCallbacks sandboxed_saved_document_done_callbacks_; | 
 |   RemoteSavedDocumentDoneCallbacks unsandboxed_saved_document_done_callbacks_; | 
 |   RemoteSavedCancelCallbacks sandboxed_saved_cancel_callbacks_; | 
 |   RemoteSavedCancelCallbacks unsandboxed_saved_cancel_callbacks_; | 
 |  | 
 |   // Set of printer drivers which require elevated permissions to operate. | 
 |   // It is expected that most print drivers will succeed with the preconfigured | 
 |   // sandbox permissions.  Should any drivers be discovered to require more than | 
 |   // that (and thus fail with access denied errors) then we need to fallback to | 
 |   // performing the operation with modified restrictions. | 
 |   base::flat_set<std::string> drivers_requiring_elevated_privilege_; | 
 |  | 
 | #if BUILDFLAG(IS_WIN) | 
 |   // Support for process model where there can be multiple PrintBackendService | 
 |   // instances.  This is necessary because Windows printer drivers are not | 
 |   // thread safe.  Map key is a printer name. | 
 |   base::flat_map<std::string, RemoteId> remote_id_map_; | 
 | #endif | 
 |  | 
 |   // Used as base for generating `RemoteId` values.  Only used internally | 
 |   // within browser process management code, so a simple incrementating | 
 |   // sequence is sufficient. | 
 |   uint32_t remote_id_sequence_ = 0; | 
 |  | 
 |   // Set when launched services are intended to persist indefinitely, rather | 
 |   // than being disconnected after a finite idle timeout expires. | 
 |   bool persistent_service_ = false; | 
 |  | 
 |   // Crash key is kept at class level so that we can obtain printer driver | 
 |   // information for a prior call should the process be terminated due to Mojo | 
 |   // message response validation. | 
 |   std::unique_ptr<crash_keys::ScopedPrinterInfo> crash_keys_; | 
 |  | 
 |   // Override of service to use for testing. | 
 |   raw_ptr<mojo::Remote<mojom::PrintBackendService>> | 
 |       sandboxed_service_remote_for_test_ = nullptr; | 
 |   raw_ptr<mojo::Remote<mojom::PrintBackendService>> | 
 |       unsandboxed_service_remote_for_test_ = nullptr; | 
 | }; | 
 |  | 
 | }  // namespace printing | 
 |  | 
 | #endif  // CHROME_BROWSER_PRINTING_PRINT_BACKEND_SERVICE_MANAGER_H_ |