| // Copyright 2021 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef COMPONENTS_REPORTING_CLIENT_REPORT_QUEUE_PROVIDER_H_ | |
| #define COMPONENTS_REPORTING_CLIENT_REPORT_QUEUE_PROVIDER_H_ | |
| #include <memory> | |
| #include <queue> | |
| #include <utility> | |
| #include "base/feature_list.h" | |
| #include "base/functional/callback.h" | |
| #include "base/memory/scoped_refptr.h" | |
| #include "base/memory/weak_ptr.h" | |
| #include "base/sequence_checker.h" | |
| #include "base/task/sequenced_task_runner.h" | |
| #include "components/reporting/client/report_queue.h" | |
| #include "components/reporting/client/report_queue_configuration.h" | |
| #include "components/reporting/proto/synced/record_constants.pb.h" | |
| #include "components/reporting/storage/storage_module_interface.h" | |
| #include "components/reporting/util/status.h" | |
| #include "components/reporting/util/status_macros.h" | |
| #include "components/reporting/util/statusor.h" | |
| namespace reporting { | |
| BASE_DECLARE_FEATURE(kEncryptedReportingPipeline); | |
| // ReportQueueProvider acts a single point for instantiating | |
| // |reporting::ReportQueue|s. By performing initialization atomically it ensures | |
| // that all ReportQueues are created with the same global settings. | |
| // | |
| // In order to utilize the ReportQueueProvider the EncryptedReportingPipeline | |
| // feature must be turned on using --enable-features=EncryptedReportingPipeline. | |
| // | |
| // `ReportQueueProvider` must be created for a specific configuration - Chrome | |
| // (for ChromeOS and for other OSes), other ChromeOS executables. It is then | |
| // registered and can be accessed through static method | |
| // `ReportQueueProvider::GetInstance()`. | |
| // | |
| // Example Usage: | |
| // void SendMessage(google::protobuf::ImportantMessage important_message, | |
| // reporting::ReportQueue::EnqueueCallback done_cb) { | |
| // // Create configuration. | |
| // StatusOr<reporting::ReportQueueConfiguration> config_result = | |
| // reporting::ReportQueueConfiguration::Create({...}).Set...().Build(); | |
| // // Bail out if configuration failed to create. | |
| // if (!config_result.has_value()) { | |
| // std::move(done_cb).Run(config_result.error()); | |
| // return; | |
| // } | |
| // // Asynchronously create ReportingQueue. | |
| // base::ThreadPool::PostTask( | |
| // FROM_HERE, | |
| // base::BindOnce( | |
| // [](google::protobuf::ImportantMessage important_message, | |
| // reporting::ReportQueue::EnqueueCallback done_cb, | |
| // std::unique_ptr<reporting::ReportQueueConfiguration> config) { | |
| // // Asynchronously create ReportingQueue. | |
| // reporting::ReportQueueProvider::CreateQueue( | |
| // std::move(config), | |
| // base::BindOnce( | |
| // [](std::string_view data, | |
| // reporting::ReportQueue::EnqueueCallback | |
| // done_cb, reporting::StatusOr<std::unique_ptr< | |
| // reporting::ReportQueue>> | |
| // report_queue_result) { | |
| // // Bail out if queue failed to create. | |
| // if (!report_queue_result.has_value()) { | |
| // std::move(done_cb).Run(report_queue_result.error()); | |
| // return; | |
| // } | |
| // // Queue created successfully, enqueue the message. | |
| // report_queue_result.value()->Enqueue( | |
| // important_message, std::move(done_cb)); | |
| // }, | |
| // important_message, std::move(done_cb))); | |
| // }, | |
| // important_message, std::move(done_cb), | |
| // std::move(config_result.value()))) | |
| // } | |
| class ReportQueueProvider { | |
| public: | |
| // `ReportQueueProvider` and its descendants need to be destructed on | |
| // sequenced task runners; to facilitate that the following flavor of smart | |
| // pointer is declared. | |
| template <typename T> | |
| using SmartPtr = std::unique_ptr<T, base::OnTaskRunnerDeleter>; | |
| using CreateReportQueueResponse = StatusOr<std::unique_ptr<ReportQueue>>; | |
| // The response will come back utilizing the ReportQueueProvider's thread. It | |
| // is likely that within Chromium you will want to the response to come back | |
| // on your own thread. The simplest way to achieve that is to pass a | |
| // base::BindPostTask rather than a base::OnceCallback. Another way to achieve | |
| // the same result is to utilize base::OnceCallback, and capture the response | |
| // and forward it to your own thread. We maintain base::OnceCallback here for | |
| // use in ChromiumOS. | |
| using CreateReportQueueCallback = | |
| base::OnceCallback<void(CreateReportQueueResponse)>; | |
| using OnStorageModuleCreatedCallback = | |
| base::OnceCallback<void(StatusOr<scoped_refptr<StorageModuleInterface>>)>; | |
| using StorageModuleCreateCallback = | |
| base::RepeatingCallback<void(OnStorageModuleCreatedCallback)>; | |
| // Callback triggered with updated report queue config after it has been | |
| // configured with appropriate DM tokens after it is retrieved. Typically, | |
| // this is when we go ahead and create the report queue. | |
| using ReportQueueConfiguredCallback = base::OnceCallback<void( | |
| StatusOr<std::unique_ptr<ReportQueueConfiguration>>)>; | |
| ReportQueueProvider(const ReportQueueProvider& other) = delete; | |
| ReportQueueProvider& operator=(const ReportQueueProvider& other) = delete; | |
| virtual ~ReportQueueProvider(); | |
| // Asynchronously creates a queue based on the configuration. In the process | |
| // `ReportQueueProvider` is expected to exist and could still be initializing | |
| // (if initialization fails, `CreateQueue` will return with error, but next | |
| // attempt may succeed). | |
| // Returns with the callback handing ownership to the caller (unless there is | |
| // an error, and then it gets the error status). | |
| static void CreateQueue(std::unique_ptr<ReportQueueConfiguration> config, | |
| CreateReportQueueCallback queue_cb); | |
| // Synchronously creates a speculative queue based on the configuration. | |
| // Returns result as a smart pointer to ReportQueue with the on-thread | |
| // deleter. | |
| static StatusOr<std::unique_ptr<ReportQueue, base::OnTaskRunnerDeleter>> | |
| CreateSpeculativeQueue(std::unique_ptr<ReportQueueConfiguration> config); | |
| // Retrieves current `ReportQueueProvider` instance (created before and | |
| // referring to `StorageModuleInterface` and optional `Uploader`). | |
| static ReportQueueProvider* GetInstance(); | |
| static bool IsEncryptedReportingPipelineEnabled(); | |
| // Accessors. | |
| base::WeakPtr<ReportQueueProvider> GetWeakPtr(); | |
| scoped_refptr<StorageModuleInterface> storage() const; | |
| scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner() const; | |
| // Storage module creator (can be substituted for testing purposes). | |
| StorageModuleCreateCallback storage_create_cb_; | |
| protected: | |
| ReportQueueProvider(StorageModuleCreateCallback storage_create_cb, | |
| scoped_refptr<base::SequencedTaskRunner> seq_task_runner); | |
| private: | |
| // Holds the creation request for a ReportQueue. | |
| class CreateReportQueueRequest; | |
| // Finalizes provider, if the initialization process succeeded. | |
| // May to be overridden by subclass to make more updates to the provider. | |
| virtual void OnInitCompleted(); | |
| // Creates and initializes queue implementation. Returns status in case of | |
| // error. | |
| virtual void CreateNewQueue(std::unique_ptr<ReportQueueConfiguration> config, | |
| CreateReportQueueCallback cb); | |
| virtual StatusOr<std::unique_ptr<ReportQueue, base::OnTaskRunnerDeleter>> | |
| CreateNewSpeculativeQueue( | |
| const ReportQueue::SpeculativeConfigSettings& config_settings); | |
| // Configures a given report queue config with appropriate DM tokens after its | |
| // retrieval so it can be used for downstream processing while building a | |
| // report queue, and triggers the corresponding completion callback with the | |
| // updated config. | |
| virtual void ConfigureReportQueue( | |
| std::unique_ptr<ReportQueueConfiguration> report_queue_config, | |
| ReportQueueConfiguredCallback completion_cb) = 0; | |
| // Checks whether the provider has been initialized, and if so, processes all | |
| // pending queue creation requests. | |
| void CheckInitializationState(); | |
| // Processes storage or error returned by async call to `storage_create_cb_`. | |
| void OnStorageModuleConfigured( | |
| StatusOr<scoped_refptr<StorageModuleInterface>> storage_result); | |
| // Task runner used for guarding the provider elements. | |
| scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_; | |
| SEQUENCE_CHECKER(sequence_checker_); | |
| // Queue for storing creation requests while the provider is | |
| // initializing. | |
| std::queue<std::unique_ptr<CreateReportQueueRequest>> create_request_queue_ | |
| GUARDED_BY_CONTEXT(sequence_checker_); | |
| // Storage module associated with the provider. It serves all queues created | |
| // by it. `storage_` is null initially and when it becomes non-null, the | |
| // provider is ready to create actual queues (speculative queues can be | |
| // created before that as well). | |
| scoped_refptr<StorageModuleInterface> storage_ | |
| GUARDED_BY_CONTEXT(sequence_checker_); | |
| // Weak pointer factory. | |
| base::WeakPtrFactory<ReportQueueProvider> weak_ptr_factory_{this}; | |
| }; | |
| } // namespace reporting | |
| #endif // COMPONENTS_REPORTING_CLIENT_REPORT_QUEUE_PROVIDER_H_ |