blob: 005aa208fdd7df54c9286977739203804af4d5bc [file] [log] [blame]
Sophie Chang647ee3a2023-06-06 15:43:431// Copyright 2023 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/page_image_service/image_service_consent_helper.h"
6
Rushan Suleymanovb11a2972023-09-29 17:45:357#include "base/metrics/histogram_functions.h"
Sophie Changaae45dfc2023-09-11 18:42:218#include "components/page_image_service/metrics_util.h"
Sophie Chang647ee3a2023-06-06 15:43:439#include "components/sync/service/sync_service.h"
Sophie Chang6045e222024-02-29 21:02:0910#include "components/sync/service/sync_service_utils.h"
Sophie Chang647ee3a2023-06-06 15:43:4311
12namespace page_image_service {
13
14namespace {
15
Rushan Suleymanovb11a2972023-09-29 17:45:3516PageImageServiceConsentStatus ConsentStatusToUmaStatus(
Arthur Sonzognic571efb2024-01-26 20:26:1817 std::optional<bool> consent_status) {
Rushan Suleymanovb11a2972023-09-29 17:45:3518 if (!consent_status) {
19 return PageImageServiceConsentStatus::kTimedOut;
20 }
21 return consent_status.value() ? PageImageServiceConsentStatus::kSuccess
22 : PageImageServiceConsentStatus::kFailure;
23}
24
Sophie Chang647ee3a2023-06-06 15:43:4325} // namespace
26
27ImageServiceConsentHelper::ImageServiceConsentHelper(
28 syncer::SyncService* sync_service,
29 syncer::ModelType model_type)
Sophie Changdce8d9412023-09-29 05:33:3730 : sync_service_(sync_service),
31 model_type_(model_type),
Marc Treib0872cf72024-06-26 19:39:3032 timeout_duration_(base::Seconds(10)) {
Ankush Singh53678e32024-07-09 17:36:2033 // `sync_service` can be null, for example when disabled via flags.
34 if (sync_service) {
35 sync_service_observer_.Observe(sync_service);
36 }
Sophie Chang647ee3a2023-06-06 15:43:4337}
38
39ImageServiceConsentHelper::~ImageServiceConsentHelper() = default;
40
41void ImageServiceConsentHelper::EnqueueRequest(
Rushan Suleymanove978a87d2023-10-12 16:39:0942 base::OnceCallback<void(PageImageServiceConsentStatus)> callback,
43 mojom::ClientId client_id) {
Rushan Suleymanovb11a2972023-09-29 17:45:3544 base::UmaHistogramBoolean("PageImageService.ConsentStatusRequestCount", true);
Sophie Chang647ee3a2023-06-06 15:43:4345
Arthur Sonzognic571efb2024-01-26 20:26:1846 std::optional<bool> consent_status = GetConsentStatus();
Sophie Chang647ee3a2023-06-06 15:43:4347 if (consent_status.has_value()) {
Sophie Changaae45dfc2023-09-11 18:42:2148 std::move(callback).Run(*consent_status
49 ? PageImageServiceConsentStatus::kSuccess
50 : PageImageServiceConsentStatus::kFailure);
Sophie Chang647ee3a2023-06-06 15:43:4351 return;
52 }
53
Rushan Suleymanove978a87d2023-10-12 16:39:0954 enqueued_request_callbacks_.emplace_back(std::move(callback), client_id);
Sophie Chang647ee3a2023-06-06 15:43:4355 if (!request_processing_timer_.IsRunning()) {
56 request_processing_timer_.Start(
Sophie Changdce8d9412023-09-29 05:33:3757 FROM_HERE, timeout_duration_,
Sophie Chang9fabf702023-08-11 22:19:0158 base::BindOnce(&ImageServiceConsentHelper::OnTimeoutExpired,
59 weak_ptr_factory_.GetWeakPtr()));
Sophie Chang647ee3a2023-06-06 15:43:4360 }
61}
62
63void ImageServiceConsentHelper::OnStateChanged(
64 syncer::SyncService* sync_service) {
65 CHECK_EQ(sync_service_, sync_service);
Sophie Chang647ee3a2023-06-06 15:43:4366
Arthur Sonzognic571efb2024-01-26 20:26:1867 std::optional<bool> consent_status = GetConsentStatus();
Sophie Chang647ee3a2023-06-06 15:43:4368 if (!consent_status.has_value()) {
69 return;
70 }
71
Sophie Changeee5afeff2023-12-18 20:23:0472 request_processing_timer_.Stop();
73
74 // The request callbacks can modify the vector while running. Swap the vector
75 // onto the stack to prevent crashing. https://crbug.com/1472360.
76 std::vector<std::pair<base::OnceCallback<void(PageImageServiceConsentStatus)>,
77 mojom::ClientId>>
78 callbacks;
79 std::swap(callbacks, enqueued_request_callbacks_);
80 for (auto& request_callback_with_client_id : callbacks) {
Rushan Suleymanove978a87d2023-10-12 16:39:0981 std::move(request_callback_with_client_id.first)
Sophie Changaae45dfc2023-09-11 18:42:2182 .Run(*consent_status ? PageImageServiceConsentStatus::kSuccess
83 : PageImageServiceConsentStatus::kFailure);
Sophie Chang647ee3a2023-06-06 15:43:4384 }
Sophie Chang647ee3a2023-06-06 15:43:4385}
86
87void ImageServiceConsentHelper::OnSyncShutdown(
88 syncer::SyncService* sync_service) {
89 CHECK_EQ(sync_service_, sync_service);
Sophie Chang647ee3a2023-06-06 15:43:4390
91 sync_service_observer_.Reset();
Sophie Changfba279122023-12-12 21:22:2192 sync_service_ = nullptr;
Sophie Chang647ee3a2023-06-06 15:43:4393}
94
Arthur Sonzognic571efb2024-01-26 20:26:1895std::optional<bool> ImageServiceConsentHelper::GetConsentStatus() {
Sophie Changfba279122023-12-12 21:22:2196 if (!sync_service_) {
97 return false;
98 }
99
Sophie Chang6045e222024-02-29 21:02:09100 // If upload of the given ModelType is disabled (or inactive due to an
101 // error), then consent must be assumed to be NOT given.
102 // Note that the "INITIALIZING" state is good enough: It means the data
103 // type is enabled in principle, Sync just hasn't fully finished
104 // initializing yet. This case is handled by the DownloadStatus check
105 // below.
106 if (syncer::GetUploadToGoogleState(sync_service_, model_type_) ==
107 syncer::UploadState::NOT_ACTIVE) {
108 return false;
109 }
110
111 // Ensure Sync has downloaded all relevant updates (i.e. any deletions from
112 // other devices are known).
Sophie Chang647ee3a2023-06-06 15:43:43113 syncer::SyncService::ModelTypeDownloadStatus download_status =
114 sync_service_->GetDownloadStatusFor(model_type_);
115 switch (download_status) {
116 case syncer::SyncService::ModelTypeDownloadStatus::kWaitingForUpdates:
Arthur Sonzognic571efb2024-01-26 20:26:18117 return std::nullopt;
Sophie Chang647ee3a2023-06-06 15:43:43118 case syncer::SyncService::ModelTypeDownloadStatus::kUpToDate:
119 return true;
120 case syncer::SyncService::ModelTypeDownloadStatus::kError:
121 return false;
122 }
123}
124