| // 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_widget_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_ |