blob: 4929e0506036d687785ffd176d289d125f23863f [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,
Mikel Astiz25049132024-08-07 15:06:5929 syncer::DataType data_type)
Sophie Changdce8d9412023-09-29 05:33:3730 : sync_service_(sync_service),
Mikel Astiz25049132024-08-07 15:06:5931 data_type_(data_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
Victor Hugo Vianna Silva2bdd62612024-08-08 09:46:45100 // If upload of the given DataType is disabled (or inactive due to an
Sophie Chang6045e222024-02-29 21:02:09101 // 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.
Mikel Astiz25049132024-08-07 15:06:59106 if (syncer::GetUploadToGoogleState(sync_service_, data_type_) ==
Sophie Chang6045e222024-02-29 21:02:09107 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).
Mikel Astiz25049132024-08-07 15:06:59113 syncer::SyncService::DataTypeDownloadStatus download_status =
114 sync_service_->GetDownloadStatusFor(data_type_);
Sophie Chang647ee3a2023-06-06 15:43:43115 switch (download_status) {
Mikel Astiz25049132024-08-07 15:06:59116 case syncer::SyncService::DataTypeDownloadStatus::kWaitingForUpdates:
Arthur Sonzognic571efb2024-01-26 20:26:18117 return std::nullopt;
Mikel Astiz25049132024-08-07 15:06:59118 case syncer::SyncService::DataTypeDownloadStatus::kUpToDate:
Sophie Chang647ee3a2023-06-06 15:43:43119 return true;
Mikel Astiz25049132024-08-07 15:06:59120 case syncer::SyncService::DataTypeDownloadStatus::kError:
Sophie Chang647ee3a2023-06-06 15:43:43121 return false;
122 }
123}
124
125void ImageServiceConsentHelper::OnTimeoutExpired() {
Sophie Changeee5afeff2023-12-18 20:23:04126 // The request callbacks can modify the vector while running. Swap the vector
127 // onto the stack to prevent crashing. https://crbug.com/1472360.
128 std::vector<std::pair<base::OnceCallback<void(PageImageServiceConsentStatus)>,
129 mojom::ClientId>>
130 callbacks;
131 std::swap(callbacks, enqueued_request_callbacks_);
132 for (auto& request_callback_with_client_id : callbacks) {
Rushan Suleymanovb11a2972023-09-29 17:45:35133 // Report consent status on timeout for each request to compare against the
134 // number of all requests.
Sophie Changfba279122023-12-12 21:22:21135 PageImageServiceConsentStatus consent_status =
136 ConsentStatusToUmaStatus(GetConsentStatus());
Rushan Suleymanovb11a2972023-09-29 17:45:35137 base::UmaHistogramEnumeration("PageImageService.ConsentStatusOnTimeout",
Sophie Changfba279122023-12-12 21:22:21138 consent_status);
Sophie Changfba279122023-12-12 21:22:21139 std::move(request_callback_with_client_id.first).Run(consent_status);
Sophie Chang647ee3a2023-06-06 15:43:43140 }
Sophie Chang647ee3a2023-06-06 15:43:43141}
142
143} // namespace page_image_service