0

Remove user_annotations component

It is no longer used. The metrics deletions are intentional. Since this
feature was never launched, we do not want to obsolete the metrics -
they should just be deleted.

Bug: 395040395
Change-Id: I1a59181eca10758939439dd7ff94829a91712de8
No-Presubmit: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6308728
Reviewed-by: Devlin Cronin <rdevlin.cronin@chromium.org>
Reviewed-by: Colin Blundell <blundell@chromium.org>
Reviewed-by: Sophie Chang <sophiechang@chromium.org>
Reviewed-by: Sylvain Defresne <sdefresne@chromium.org>
Reviewed-by: Martin Šrámek <msramek@chromium.org>
Commit-Queue: Jan Keitel <jkeitel@google.com>
Reviewed-by: Alexei Svitkine <asvitkine@chromium.org>
Reviewed-by: Christoph Schwering <schwering@google.com>
Cr-Commit-Position: refs/heads/main@{#1427119}
This commit is contained in:
Jan Keitel
2025-03-03 07:28:32 -08:00
committed by Chromium LUCI CQ
parent eb3610c473
commit 485f65af53
68 changed files with 71 additions and 3558 deletions
chrome
components
extensions
ios/chrome/browser
browsing_data
settings
ui_bundled
tools/metrics/histograms

@ -2392,7 +2392,6 @@ static_library("browser") {
"//components/url_formatter/spoof_checks/top_domains:top_bucket_domains",
"//components/url_formatter/spoof_checks/top_domains:top_bucket_domains_header",
"//components/url_matcher",
"//components/user_annotations",
"//components/user_manager",
"//components/user_prefs",
"//components/variations",
@ -4324,7 +4323,6 @@ static_library("browser") {
"//chrome/browser/ui/webui/whats_new",
"//chrome/browser/ui/webui/whats_new:impl",
"//chrome/browser/upgrade_detector:build_state_observer",
"//chrome/browser/user_annotations",
"//chrome/browser/web_applications",
"//chrome/browser/web_applications:features",
"//chrome/browser/web_applications:web_applications_metrics",
@ -4407,9 +4405,6 @@ static_library("browser") {
# TODO(crbug.com/366172297): Remove circular dependencies.
"//chrome/browser/autofill_ai:util",
# TODO(crbug.com/366172297): Remove circular dependencies.
"//chrome/browser/user_annotations",
# TODO(b/220386256): Remove circular dependency from the browser.
"//chrome/browser/media/router/discovery/access_code:access_code_sink_service",
"//chrome/browser/media/router:mojo_impl",

@ -399,7 +399,6 @@ include_rules = [
"+components/upload_list",
"+components/url_matcher",
"+components/url_pattern_index/proto",
"+components/user_annotations",
"+components/user_education",
"+components/user_manager",
"+components/user_prefs",

@ -14,7 +14,6 @@
#include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/autofill/core/browser/data_manager/autofill_ai/entity_data_manager.h"
@ -35,7 +34,6 @@
#include "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/user_annotations/test_user_annotations_service.h"
#include "content/public/browser/browser_context.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
@ -52,11 +50,6 @@ std::unique_ptr<KeyedService> CreateOptimizationGuideKeyedService(
return std::make_unique<NiceMock<MockOptimizationGuideKeyedService>>();
}
std::unique_ptr<KeyedService> CreateUserAnnotationsServiceFactory(
content::BrowserContext* context) {
return std::make_unique<user_annotations::TestUserAnnotationsService>();
}
std::unique_ptr<KeyedService> CreateTestPersonalDataManager(
content::BrowserContext* context) {
return std::make_unique<autofill::TestPersonalDataManager>();
@ -92,9 +85,6 @@ class ChromeAutofillAiClientTest : public ChromeRenderViewHostTestHarness {
return {TestingProfile::TestingFactory{
OptimizationGuideKeyedServiceFactory::GetInstance(),
base::BindRepeating(&CreateOptimizationGuideKeyedService)},
TestingProfile::TestingFactory{
UserAnnotationsServiceFactory::GetInstance(),
base::BindRepeating(&CreateUserAnnotationsServiceFactory)},
TestingProfile::TestingFactory{
autofill::PersonalDataManagerFactory::GetInstance(),
base::BindRepeating(&CreateTestPersonalDataManager)},

@ -185,14 +185,12 @@
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/new_tab_page/microsoft_auth/microsoft_auth_service.h"
#include "chrome/browser/new_tab_page/microsoft_auth/microsoft_auth_service_factory.h"
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
#include "chrome/browser/user_education/browser_user_education_storage_service.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_command_scheduler.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "components/user_annotations/user_annotations_service.h"
#include "content/public/browser/isolated_web_apps_policy.h"
#include "content/public/browser/storage_partition_config.h"
#endif // !BUILDFLAG(IS_ANDROID)
@ -1104,13 +1102,6 @@ void ChromeBrowsingDataRemoverDelegate::RemoveEmbedderData(
FROM_HERE, base::DoNothing(),
CreateTaskCompletionClosure(TracingDataType::kAutofillData));
}
#if !BUILDFLAG(IS_ANDROID)
if (auto* user_annotations_service =
UserAnnotationsServiceFactory::GetForProfile(profile_)) {
user_annotations_service->RemoveAnnotationsInRange(delete_begin_,
delete_end_);
}
#endif
}
//////////////////////////////////////////////////////////////////////////////

@ -83,7 +83,6 @@
#include "chrome/browser/tpcd/metadata/manager_factory.h"
#include "chrome/browser/translate/chrome_translate_client.h"
#include "chrome/browser/trusted_vault/trusted_vault_service_factory.h"
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
#include "chrome/browser/webdata_services/web_data_service_factory.h"
#include "chrome/browser/webid/federated_identity_permission_context.h"
#include "chrome/common/chrome_constants.h"
@ -166,7 +165,6 @@
#include "components/tpcd/metadata/browser/prefs.h"
#include "components/tpcd/metadata/browser/test_support.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/user_annotations/test_user_annotations_service.h"
#include "content/public/browser/background_tracing_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@ -2526,51 +2524,6 @@ TEST_F(ChromeBrowsingDataRemoverDelegateTest,
ASSERT_FALSE(tester.HasProfileAndCard());
}
#if !BUILDFLAG(IS_ANDROID)
class ChromeBrowsingDataRemoverDelegateUserAnnotationsTest
: public ChromeBrowsingDataRemoverDelegateTest {
public:
static std::unique_ptr<KeyedService> CreateUserAnnotationsServiceFactory(
content::BrowserContext* context) {
return std::make_unique<user_annotations::TestUserAnnotationsService>();
}
void SetUp() override { ChromeBrowsingDataRemoverDelegateTest::SetUp(); }
TestingProfile::TestingFactories GetTestingFactories() override {
TestingProfile::TestingFactories factories =
ChromeBrowsingDataRemoverDelegateTest::GetTestingFactories();
factories.emplace_back(
UserAnnotationsServiceFactory::GetInstance(),
base::BindRepeating(&CreateUserAnnotationsServiceFactory));
return factories;
}
user_annotations::TestUserAnnotationsService* service() {
// Overridden in GetTestingFactories().
return static_cast<user_annotations::TestUserAnnotationsService*>(
UserAnnotationsServiceFactory::GetForProfile(GetProfile()));
}
};
TEST_F(ChromeBrowsingDataRemoverDelegateUserAnnotationsTest,
UserAnnotationsOnAutofillRemoveRange) {
auto time_now = base::Time::Now();
BlockUntilBrowsingDataRemoved(time_now, time_now + base::Hours(1),
constants::DATA_TYPE_FORM_DATA, false);
// UserAnnotations should be empty when DATA_TYPE_FORM_DATA browsing data
// gets deleted.
EXPECT_EQ(constants::DATA_TYPE_FORM_DATA, GetRemovalMask());
EXPECT_EQ(content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
GetOriginTypeMask());
EXPECT_THAT(service()->last_received_remove_annotations_in_range(),
testing::Pair(testing::Eq(time_now),
testing::Eq(time_now + base::Hours(1))));
}
#endif
TEST_F(ChromeBrowsingDataRemoverDelegateTest, ZeroSuggestPrefsBasedCacheClear) {
// Disable in-memory ZPS caching.
base::test::ScopedFeatureList features;

@ -21,7 +21,6 @@
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
#include "chrome/browser/webdata_services/web_data_service_factory.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/autofill/core/browser/autofill_type.h"
@ -37,9 +36,6 @@
#include "components/browsing_data/core/browsing_data_utils.h"
#include "components/browsing_data/core/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/user_annotations/test_user_annotations_service.h"
#include "components/user_annotations/user_annotations_service.h"
#include "components/user_annotations/user_annotations_types.h"
#include "content/public/test/browser_test.h"
namespace {
@ -63,8 +59,6 @@ class AutofillCounterTest : public InProcessBrowserTest {
browser()->profile());
web_data_service_ = WebDataServiceFactory::GetAutofillWebDataForProfile(
browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS);
user_annotations_service_ =
std::make_unique<user_annotations::TestUserAnnotationsService>();
SetAutofillDeletionPref(true);
SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME);
@ -148,12 +142,6 @@ class AutofillCounterTest : public InProcessBrowserTest {
address_ids_.pop_back();
}
// User annotations ----------------------------------------------------------
void SetUserAnnotations(user_annotations::UserAnnotationsEntries entries) {
user_annotations_service_->ReplaceAllEntries(std::move(entries));
}
// Other autofill utils ------------------------------------------------------
void ClearCreditCardsAndAddresses() {
@ -185,11 +173,6 @@ class AutofillCounterTest : public InProcessBrowserTest {
return web_data_service_;
}
raw_ptr<user_annotations::TestUserAnnotationsService>
GetUserAnnotationsService() {
return user_annotations_service_.get();
}
// Result retrieval ---------------------------------------------
browsing_data::BrowsingDataCounter::ResultInt GetNumSuggestions() {
@ -204,10 +187,6 @@ class AutofillCounterTest : public InProcessBrowserTest {
return num_addresses_;
}
browsing_data::BrowsingDataCounter::ResultInt GetNumUserAnnotations() {
return num_user_annotations_;
}
browsing_data::AutofillCounter::ResultInt GetCounterValue() {
return counter_value_;
}
@ -225,7 +204,6 @@ class AutofillCounterTest : public InProcessBrowserTest {
counter_value_ = autofill_result->Value();
num_credit_cards_ = autofill_result->num_credit_cards();
num_addresses_ = autofill_result->num_addresses();
num_user_annotations_ = autofill_result->num_user_annotation_entries();
}
protected:
@ -240,22 +218,18 @@ class AutofillCounterTest : public InProcessBrowserTest {
raw_ptr<autofill::PersonalDataManager> personal_data_manager_;
scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
std::unique_ptr<user_annotations::TestUserAnnotationsService>
user_annotations_service_;
browsing_data::BrowsingDataCounter::ResultInt counter_value_;
browsing_data::BrowsingDataCounter::ResultInt num_suggestions_;
browsing_data::BrowsingDataCounter::ResultInt num_credit_cards_;
browsing_data::BrowsingDataCounter::ResultInt num_addresses_;
browsing_data::BrowsingDataCounter::ResultInt num_user_annotations_;
};
// Tests that we count the correct number of autocomplete suggestions.
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, AutocompleteSuggestions) {
Profile* profile = browser()->profile();
browsing_data::AutofillCounter counter(
GetPersonalDataManager(), GetWebDataService(),
/*user_annotations_service=*/nullptr, /*sync_service=*/nullptr);
GetPersonalDataManager(), GetWebDataService(), /*sync_service=*/nullptr);
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
@ -294,8 +268,7 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, AutocompleteSuggestions) {
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, CreditCards) {
Profile* profile = browser()->profile();
browsing_data::AutofillCounter counter(
GetPersonalDataManager(), GetWebDataService(),
/*user_annotations_service=*/nullptr, /*sync_service=*/nullptr);
GetPersonalDataManager(), GetWebDataService(), /*sync_service=*/nullptr);
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
@ -340,8 +313,7 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, CreditCards) {
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, Addresses) {
Profile* profile = browser()->profile();
browsing_data::AutofillCounter counter(
GetPersonalDataManager(), GetWebDataService(),
/*user_annotations_service=*/nullptr, /*sync_service=*/nullptr);
GetPersonalDataManager(), GetWebDataService(), /*sync_service=*/nullptr);
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
@ -382,26 +354,6 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, Addresses) {
EXPECT_EQ(0, GetNumAddresses());
}
// Tests that we count the correct number of user annotations.
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, UserAnnotations) {
Profile* profile = browser()->profile();
browsing_data::AutofillCounter counter(
GetPersonalDataManager(), GetWebDataService(),
GetUserAnnotationsService(), /*sync_service=*/nullptr);
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
future.GetRepeatingCallback());
counter.Restart();
WaitForResult();
EXPECT_EQ(0, GetNumUserAnnotations());
SetUserAnnotations(
std::vector(10, optimization_guide::proto::UserAnnotationsEntry{}));
counter.Restart();
WaitForResult();
EXPECT_EQ(10, GetNumUserAnnotations());
}
// Tests that we return the correct complex result when counting more than
// one type of items.
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, ComplexResult) {
@ -420,8 +372,7 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, ComplexResult) {
Profile* profile = browser()->profile();
browsing_data::AutofillCounter counter(
GetPersonalDataManager(), GetWebDataService(),
/*user_annotations_service=*/nullptr, /*sync_service=*/nullptr);
GetPersonalDataManager(), GetWebDataService(), /*sync_service=*/nullptr);
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
@ -466,20 +417,17 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, TimeRanges) {
const browsing_data::BrowsingDataCounter::ResultInt
expected_num_credit_cards;
const browsing_data::BrowsingDataCounter::ResultInt expected_num_addresses;
const browsing_data::BrowsingDataCounter::ResultInt
expected_num_user_annotations;
};
auto test_cases = std::to_array<TestCase>({
{base::Time(), 2, 3, 3, 0},
{kTime1, 2, 3, 3, 0},
{kTime2, 1, 2, 2, 0},
{kTime3, 1, 1, 0, 0},
{base::Time(), 2, 3, 3},
{kTime1, 2, 3, 3},
{kTime2, 1, 2, 2},
{kTime3, 1, 1, 0},
});
Profile* profile = browser()->profile();
browsing_data::AutofillCounter counter(
GetPersonalDataManager(), GetWebDataService(),
/*user_annotations_service=*/nullptr, /*sync_service=*/nullptr);
GetPersonalDataManager(), GetWebDataService(), /*sync_service=*/nullptr);
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,
@ -496,7 +444,6 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, TimeRanges) {
EXPECT_EQ(test_case.expected_num_suggestions, GetCounterValue());
EXPECT_EQ(test_case.expected_num_credit_cards, GetNumCreditCards());
EXPECT_EQ(test_case.expected_num_addresses, GetNumAddresses());
EXPECT_EQ(test_case.expected_num_user_annotations, GetNumUserAnnotations());
future.Clear();
}
@ -509,7 +456,6 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, TimeRanges) {
EXPECT_EQ(1, GetCounterValue());
EXPECT_EQ(1, GetNumCreditCards());
EXPECT_EQ(1, GetNumAddresses());
EXPECT_EQ(0, GetNumUserAnnotations());
counter.SetPeriodEndForTesting(kTime3);
counter.Restart();
@ -519,7 +465,6 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, TimeRanges) {
EXPECT_EQ(1, GetCounterValue());
EXPECT_EQ(2, GetNumCreditCards());
EXPECT_EQ(3, GetNumAddresses());
EXPECT_EQ(0, GetNumUserAnnotations());
}
} // namespace

@ -39,7 +39,6 @@
#endif
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
#include "content/public/browser/host_zoom_map.h"
#else
#include "chrome/browser/browsing_data/counters/tabs_counter.h"
@ -109,11 +108,6 @@ BrowsingDataCounterFactory::GetForProfileAndPref(Profile* profile,
autofill::PersonalDataManagerFactory::GetForBrowserContext(profile),
WebDataServiceFactory::GetAutofillWebDataForProfile(
profile, ServiceAccessType::EXPLICIT_ACCESS),
#if !BUILDFLAG(IS_ANDROID)
UserAnnotationsServiceFactory::GetForProfile(profile),
#else
/*user_annotations_service=*/nullptr,
#endif
SyncServiceFactory::GetForProfile(profile));
}

@ -113,7 +113,7 @@ IN_PROC_BROWSER_TEST_F(SyncAwareCounterTest, AutofillCounter) {
autofill::PersonalDataManagerFactory::GetForBrowserContext(profile),
WebDataServiceFactory::GetAutofillWebDataForProfile(
profile, ServiceAccessType::IMPLICIT_ACCESS),
/*user_annotations_service=*/nullptr, sync_service);
sync_service);
counter.Init(profile->GetPrefs(),
browsing_data::ClearBrowsingDataTab::ADVANCED,

@ -33,7 +33,6 @@ source_set("autofill_private") {
"//chrome/browser/search_engines:search_engines",
"//chrome/browser/sync:sync",
"//chrome/browser/ui/user_education",
"//chrome/browser/user_annotations",
"//chrome/common/extensions/api:api",
"//components/autofill/content/browser",
"//components/autofill/core/browser",
@ -44,7 +43,6 @@ source_set("autofill_private") {
"//components/strings:components_branded_strings_grit",
"//components/strings:components_strings_grit",
"//components/sync/service:service",
"//components/user_annotations",
"//extensions/browser:browser",
"//skia",
"//third_party/libaddressinput:util",

@ -6,7 +6,6 @@
#define CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_API_H_
#include "components/prefs/pref_service.h"
#include "components/user_annotations/user_annotations_types.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_function_histogram_value.h"

@ -122,7 +122,6 @@ source_set("profile_util") {
"//components/enterprise/common/proto:upload_request_response",
"//components/keyed_service/core",
"//components/password_manager/core/browser/password_store:password_store_interface",
"//components/user_annotations:user_annotations",
"//device/fido:fido",
"//mojo/public/cpp/bindings",
"//services/preferences/public/mojom",
@ -195,10 +194,7 @@ source_set("profile_util_impl") {
]
if (!is_android) {
deps += [
"//chrome/browser/ui:browser_list",
"//chrome/browser/user_annotations:user_annotations",
]
deps += [ "//chrome/browser/ui:browser_list" ]
}
if (is_chromeos) {
@ -316,7 +312,6 @@ source_set("profiles_extra_parts_impl") {
"//chrome/browser/ui/views/side_panel",
"//chrome/browser/ui/webui/signin",
"//chrome/browser/ui/webui/signin:login",
"//chrome/browser/user_annotations",
]
}

@ -221,7 +221,6 @@
#include "chrome/browser/unified_consent/unified_consent_service_factory.h"
#include "chrome/browser/updates/announcement_notification/announcement_notification_service_factory.h"
#include "chrome/browser/usb/usb_chooser_context_factory.h"
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
#include "chrome/browser/visited_url_ranking/visited_url_ranking_service_factory.h"
#include "chrome/browser/webauthn/enclave_manager_factory.h"
#include "chrome/browser/webdata_services/web_data_service_factory.h"
@ -1339,7 +1338,6 @@ void ChromeBrowserMainExtraPartsProfiles::
UsbChooserContextFactory::GetInstance();
#if !BUILDFLAG(IS_ANDROID)
UsbConnectionTrackerFactory::GetInstance();
UserAnnotationsServiceFactory::GetInstance();
UserEducationServiceFactory::GetInstance();
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)

@ -16,7 +16,6 @@ ProfileStatistics::ProfileStatistics(
scoped_refptr<password_manager::PasswordStoreInterface>
profile_password_store,
PrefService* pref_service,
user_annotations::UserAnnotationsService* user_annotations_service,
std::unique_ptr<device::fido::PlatformCredentialStore>
platform_credential_store)
: autofill_web_data_service_(std::move(autofill_web_data_service)),
@ -25,7 +24,6 @@ ProfileStatistics::ProfileStatistics(
history_service_(history_service),
profile_password_store_(profile_password_store),
pref_service_(pref_service),
user_annotations_service_(user_annotations_service),
platform_credential_store_(std::move(platform_credential_store)),
aggregator_(nullptr) {}
@ -37,7 +35,7 @@ void ProfileStatistics::GatherStatistics(
aggregator_ = std::make_unique<ProfileStatisticsAggregator>(
autofill_web_data_service_, personal_data_manager_, bookmark_model_,
history_service_, profile_password_store_, pref_service_,
user_annotations_service_, std::move(platform_credential_store_),
std::move(platform_credential_store_),
base::BindOnce(&ProfileStatistics::DeregisterAggregator,
weak_ptr_factory_.GetWeakPtr()));
}

@ -13,7 +13,6 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/password_manager/core/browser/password_store/password_store_interface.h"
#include "components/user_annotations/user_annotations_service.h"
#include "device/fido/platform_credential_store.h"
class PrefService;
@ -45,7 +44,6 @@ class ProfileStatistics : public KeyedService {
scoped_refptr<password_manager::PasswordStoreInterface>
profile_password_store,
PrefService* pref_service,
user_annotations::UserAnnotationsService* user_annotations_service,
std::unique_ptr<device::fido::PlatformCredentialStore>
platform_credential_store);
~ProfileStatistics() override;
@ -69,8 +67,6 @@ class ProfileStatistics : public KeyedService {
const scoped_refptr<password_manager::PasswordStoreInterface>
profile_password_store_;
const raw_ptr<PrefService> pref_service_;
const raw_ptr<user_annotations::UserAnnotationsService>
user_annotations_service_;
std::unique_ptr<device::fido::PlatformCredentialStore>
platform_credential_store_;

@ -26,7 +26,6 @@ ProfileStatisticsAggregator::ProfileStatisticsAggregator(
scoped_refptr<password_manager::PasswordStoreInterface>
profile_password_store,
PrefService* pref_service,
user_annotations::UserAnnotationsService* user_annotations_service,
std::unique_ptr<device::fido::PlatformCredentialStore>
platform_credential_store,
base::OnceClosure done_callback)
@ -36,7 +35,6 @@ ProfileStatisticsAggregator::ProfileStatisticsAggregator(
history_service_(history_service),
profile_password_store_(profile_password_store),
pref_service_(pref_service),
user_annotations_service_(user_annotations_service),
platform_credential_store_(std::move(platform_credential_store)),
done_callback_(std::move(done_callback)) {}
@ -84,7 +82,6 @@ void ProfileStatisticsAggregator::StartAggregator() {
// Initiate autofill counting.
AddCounter(std::make_unique<browsing_data::AutofillCounter>(
personal_data_manager_, autofill_web_data_service_,
user_annotations_service_,
/*sync_service=*/nullptr));
}

@ -14,7 +14,6 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/browsing_data/core/counters/browsing_data_counter.h"
#include "components/password_manager/core/browser/password_store/password_store_interface.h"
#include "components/user_annotations/user_annotations_service.h"
#include "device/fido/platform_credential_store.h"
class PrefService;
@ -47,7 +46,6 @@ class ProfileStatisticsAggregator {
scoped_refptr<password_manager::PasswordStoreInterface>
profile_password_store,
PrefService* pref_service,
user_annotations::UserAnnotationsService* user_annotations_service,
std::unique_ptr<device::fido::PlatformCredentialStore>
platform_credential_store,
base::OnceClosure done_callback);
@ -83,8 +81,6 @@ class ProfileStatisticsAggregator {
const scoped_refptr<password_manager::PasswordStoreInterface>
profile_password_store_;
const raw_ptr<PrefService> pref_service_;
const raw_ptr<user_annotations::UserAnnotationsService>
user_annotations_service_;
std::unique_ptr<device::fido::PlatformCredentialStore>
platform_credential_store_;

@ -81,7 +81,6 @@ class ProfileStatisticsAggregatorTest : public testing::Test {
return std::make_unique<ProfileStatisticsAggregator>(
autofill_web_data_service_, &personal_data_manager_, &bookmark_model_,
&history_service_, profile_password_store_, &pref_service_,
/*user_annotations_service=*/nullptr,
/*platform_credential_store=*/nullptr, std::move(done_callback));
}

@ -11,7 +11,6 @@
#include "chrome/browser/password_manager/profile_password_store_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_statistics.h"
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
#include "chrome/browser/webauthn/chrome_web_authentication_delegate.h"
#include "chrome/browser/webdata_services/web_data_service_factory.h"
#include "components/keyed_service/core/service_access_type.h"
@ -25,10 +24,6 @@
#include "device/fido/cros/credential_store.h"
#endif
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
#endif
// static
ProfileStatistics* ProfileStatisticsFactory::GetForProfile(Profile* profile) {
return static_cast<ProfileStatistics*>(
@ -83,10 +78,5 @@ ProfileStatisticsFactory::BuildServiceInstanceForBrowserContext(
ProfilePasswordStoreFactory::GetForProfile(
profile, ServiceAccessType::EXPLICIT_ACCESS),
profile->GetPrefs(),
#if !BUILDFLAG(IS_ANDROID)
UserAnnotationsServiceFactory::GetForProfile(profile),
#else
/*user_annotations_service=*/nullptr,
#endif
std::move(credential_store));
}

@ -1777,7 +1777,6 @@ static_library("ui") {
"//chrome/browser/ui/webui/whats_new:impl",
"//chrome/browser/ui/window_sizer",
"//chrome/browser/ui/window_sizer:impl",
"//chrome/browser/user_annotations",
"//chrome/browser/web_applications",
"//chrome/browser/web_applications:features",
"//chrome/common:buildflags",

@ -41,7 +41,6 @@ source_set("autofill") {
"//components/keyed_service/core",
"//components/optimization_guide/proto:optimization_guide_proto",
"//components/signin/public/identity_manager",
"//components/user_annotations:types",
"//components/zoom",
"//content/public/browser",
"//ui/gfx",

@ -12,7 +12,6 @@
#include "base/types/optional_ref.h"
#include "components/autofill/core/browser/integrators/autofill_ai_delegate.h"
#include "components/autofill_ai/core/browser/autofill_ai_client.h"
#include "components/user_annotations/user_annotations_types.h"
#include "content/public/browser/web_contents.h"
namespace autofill {

@ -36,7 +36,6 @@
#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_options.h"
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/user_annotations/user_annotations_types.h"
#include "content/public/browser/visibility.h"
#include "content/public/browser/web_contents_observer.h"

@ -1,68 +0,0 @@
# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/buildflag_header.gni")
import("//build/config/chromeos/ui_mode.gni")
import("//build/config/ui.gni")
import("//chrome/version.gni")
import("//components/optimization_guide/features.gni")
import("//extensions/buildflags/buildflags.gni")
assert(!is_fuchsia, "Fuchsia shouldn't use anything in //chrome")
static_library("user_annotations") {
sources = [
"user_annotations_service_factory.cc",
"user_annotations_service_factory.h",
]
public_deps = [
"//base",
"//chrome/browser:browser_public_dependencies",
"//chrome/browser/profiles:profile",
"//chrome/browser/profiles:profile_util",
"//content/public/browser",
]
deps = [
"//chrome/browser:browser_process",
"//chrome/browser/optimization_guide",
"//chrome/browser/ui/autofill",
"//components/autofill/content/browser:browser",
"//components/compose:buildflags",
"//components/user_annotations",
"//ui/accessibility",
]
if (is_chromeos_ash) {
deps += [ "//chrome/browser/ash/profiles" ]
}
}
if (!is_android) {
source_set("browser_tests") {
testonly = true
defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
sources = [ "user_annotations_service_browsertest.cc" ]
public_deps = [ "//content/test:test_support" ]
deps = [
":user_annotations",
"//chrome/browser/optimization_guide:test_support",
"//chrome/browser/ui",
"//chrome/test:test_support",
"//chrome/test:test_support_ui",
"//components/autofill/core/common",
"//components/autofill_ai/core/browser",
"//components/signin/public/base",
"//components/signin/public/identity_manager",
"//components/user_annotations",
"//content/test:test_support",
]
if (is_chromeos_ash) {
deps += [ "//chrome/browser/ash/login/test:test_support" ]
}
}
}

@ -1 +0,0 @@
file://components/optimization_guide/OWNERS

@ -1,297 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/user_annotations_service.h"
#include <optional>
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "chrome/browser/optimization_guide/browser_test_util.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill_ai/core/browser/autofill_ai_features.h"
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
#include "components/user_annotations/user_annotations_types.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "net/dns/mock_host_resolver.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/login/test/device_state_mixin.h"
#include "chrome/browser/ash/login/test/guest_session_mixin.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#endif
namespace user_annotations {
class UserAnnotationsServiceDisabledBrowserTest : public InProcessBrowserTest {
public:
void SetUp() override {
feature_list_.InitAndDisableFeature(autofill_ai::kAutofillAi);
InProcessBrowserTest::SetUp();
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceDisabledBrowserTest,
ServiceNotCreatedWhenFeatureDisabled) {
ASSERT_FALSE(
UserAnnotationsServiceFactory::GetForProfile(browser()->profile()));
}
class UserAnnotationsServiceKioskModeBrowserTest : public InProcessBrowserTest {
public:
UserAnnotationsServiceKioskModeBrowserTest() {
scoped_feature_list_.InitAndEnableFeature(autofill_ai::kAutofillAi);
}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(::switches::kKioskMode);
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceKioskModeBrowserTest,
DisabledInKioskMode) {
EXPECT_EQ(nullptr,
UserAnnotationsServiceFactory::GetForProfile(browser()->profile()));
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
class UserAnnotationsServiceEphemeralProfileBrowserTest
: public MixinBasedInProcessBrowserTest {
public:
UserAnnotationsServiceEphemeralProfileBrowserTest() {
scoped_feature_list_.InitAndEnableFeature(autofill_ai::kAutofillAi);
}
private:
ash::GuestSessionMixin guest_session_{&mixin_host_};
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceEphemeralProfileBrowserTest,
EphemeralProfileDoesNotInstantiateService) {
EXPECT_EQ(nullptr,
UserAnnotationsServiceFactory::GetForProfile(browser()->profile()));
}
#endif
class UserAnnotationsServiceBrowserTest : public InProcessBrowserTest {
public:
void SetUp() override {
InitializeFeatureList();
InProcessBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
InProcessBrowserTest::SetUpOnMainThread();
browser()->profile()->GetPrefs()->SetBoolean(
autofill::prefs::kAutofillPredictionImprovementsEnabled, true);
identity_test_env_adaptor_ =
std::make_unique<IdentityTestEnvironmentProfileAdaptor>(
browser()->profile());
embedded_test_server()->ServeFilesFromSourceDirectory(
"components/test/data/autofill");
ASSERT_TRUE(embedded_test_server()->Start());
}
void SetUpInProcessBrowserTestFixture() override {
create_services_subscription_ =
BrowserContextDependencyManager::GetInstance()
->RegisterCreateServicesCallbackForTesting(
base::BindRepeating(&UserAnnotationsServiceBrowserTest::
OnWillCreateBrowserContextServices,
base::Unretained(this)));
}
void EnableSignin() {
auto account_info =
identity_test_env_adaptor_->identity_test_env()
->MakePrimaryAccountAvailable("user@gmail.com",
signin::ConsentLevel::kSignin);
AccountCapabilitiesTestMutator mutator(&account_info.capabilities);
mutator.set_can_use_model_execution_features(true);
identity_test_env_adaptor_->identity_test_env()
->UpdateAccountInfoForAccount(account_info);
identity_test_env_adaptor_->identity_test_env()
->SetAutomaticIssueOfAccessTokens(true);
}
testing::AssertionResult SubmitForm(content::RenderFrameHost* rfh) {
return content::ExecJs(rfh, R"(document.forms[0].submit();)");
}
testing::AssertionResult FillForm(content::RenderFrameHost* rfh) {
return content::ExecJs(rfh, R"(
document.getElementsByName("name")[0].value="John Doe";
document.getElementsByName("address")[0].value="123 Main Street";
document.getElementsByName("city")[0].value="Knightdale";
document.getElementsByName("state")[0].selectedIndex=3;
document.getElementsByName("zip")[0].value="27545";
document.getElementsByName("country")[0].value="United States";
document.getElementsByName("email")[0].value="jd@example.com";
document.getElementsByName("phone")[0].value="919-555-5555";
)");
}
protected:
UserAnnotationsService* service() {
return UserAnnotationsServiceFactory::GetForProfile(browser()->profile());
}
content::WebContents* web_contents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
virtual void InitializeFeatureList() {
feature_list_.InitWithFeatures({autofill_ai::kAutofillAi}, {});
}
base::test::ScopedFeatureList feature_list_;
private:
void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
IdentityTestEnvironmentProfileAdaptor::
SetIdentityTestEnvironmentFactoriesOnBrowserContext(context);
}
// Identity test support.
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
identity_test_env_adaptor_;
base::CallbackListSubscription create_services_subscription_;
};
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceBrowserTest, ServiceFactoryWorks) {
EXPECT_TRUE(service());
}
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceBrowserTest,
ServiceNotCreatedForIncognito) {
Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
EXPECT_EQ(nullptr, UserAnnotationsServiceFactory::GetForProfile(
otr_browser->profile()));
}
// TODO(crbug.com/367201367): Re-enable once flakiness is resolved for Windows
// ASAN. Also flaky on Mac.
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceBrowserTest,
DISABLED_FormSubmissionFlow) {
EnableSignin();
base::HistogramTester histogram_tester;
GURL url(
embedded_test_server()->GetURL("a.com", "/autofill_address_form.html"));
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->AddHintForTesting(url, optimization_guide::proto::FORMS_ANNOTATIONS,
std::nullopt);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
ASSERT_TRUE(FillForm(web_contents()->GetPrimaryMainFrame()));
ASSERT_TRUE(SubmitForm(web_contents()->GetPrimaryMainFrame()));
EXPECT_EQ(
1, optimization_guide::RetryForHistogramUntilCountReached(
&histogram_tester, "UserAnnotations.AddFormSubmissionResult", 1));
histogram_tester.ExpectTotalCount("UserAnnotations.AddFormSubmissionResult",
1);
}
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceBrowserTest, NotOnAllowlist) {
EnableSignin();
base::HistogramTester histogram_tester;
GURL url(embedded_test_server()->GetURL("notallowed.com",
"/autofill_address_form.html"));
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
ASSERT_TRUE(FillForm(web_contents()->GetPrimaryMainFrame()));
ASSERT_TRUE(SubmitForm(web_contents()->GetPrimaryMainFrame()));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount("UserAnnotations.AddFormSubmissionResult",
0);
}
// TODO: b/361692317 - Delete below once optimization guide populates list.
class UserAnnotationsServiceExplicitAllowlistBrowserTest
: public UserAnnotationsServiceBrowserTest {
protected:
void InitializeFeatureList() override {
feature_list_.InitWithFeaturesAndParameters(
{{autofill_ai::kAutofillAi,
{{"allowed_hosts_for_form_submissions", "allowed.com"}}}},
{});
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceExplicitAllowlistBrowserTest,
NotOnAllowlist) {
EnableSignin();
base::HistogramTester histogram_tester;
GURL url(embedded_test_server()->GetURL("notallowed.com",
"/autofill_address_form.html"));
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
ASSERT_TRUE(FillForm(web_contents()->GetPrimaryMainFrame()));
ASSERT_TRUE(SubmitForm(web_contents()->GetPrimaryMainFrame()));
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount("UserAnnotations.AddFormSubmissionResult",
0);
}
// TODO(crbug.com/367201367): Re-enable once flakiness is resolved for Windows
// ASAN. Also flaky on Mac.
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceExplicitAllowlistBrowserTest,
DISABLED_OnAllowlist) {
EnableSignin();
base::HistogramTester histogram_tester;
GURL url(embedded_test_server()->GetURL("allowed.com",
"/autofill_address_form.html"));
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
ASSERT_TRUE(FillForm(web_contents()->GetPrimaryMainFrame()));
ASSERT_TRUE(SubmitForm(web_contents()->GetPrimaryMainFrame()));
EXPECT_EQ(
1, optimization_guide::RetryForHistogramUntilCountReached(
&histogram_tester, "UserAnnotations.AddFormSubmissionResult", 1));
histogram_tester.ExpectTotalCount("UserAnnotations.AddFormSubmissionResult",
1);
}
} // namespace user_annotations

@ -1,89 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
#include "chrome/browser/app_mode/app_mode_utils.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/user_annotations/user_annotations_features.h"
#include "components/user_annotations/user_annotations_service.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/profiles/profile_helper.h"
#endif
namespace {
bool IsEphemeralProfile(Profile* profile) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (ash::ProfileHelper::IsEphemeralUserProfile(profile)) {
return true;
}
#endif
// Catch additional logic that may not be caught by the existing Ash check.
ProfileAttributesStorage& storage =
g_browser_process->profile_manager()->GetProfileAttributesStorage();
ProfileAttributesEntry* entry =
storage.GetProfileAttributesWithPath(profile->GetPath());
return entry && entry->IsEphemeral();
}
} // namespace
// static
user_annotations::UserAnnotationsService*
UserAnnotationsServiceFactory::GetForProfile(Profile* profile) {
return static_cast<user_annotations::UserAnnotationsService*>(
GetInstance()->GetServiceForBrowserContext(profile, /*create=*/true));
}
// static
UserAnnotationsServiceFactory* UserAnnotationsServiceFactory::GetInstance() {
static base::NoDestructor<UserAnnotationsServiceFactory> instance;
return instance.get();
}
UserAnnotationsServiceFactory::UserAnnotationsServiceFactory()
: ProfileKeyedServiceFactory(
"UserAnnotationsService",
ProfileSelections::Builder()
.WithRegular(ProfileSelection::kOriginalOnly)
.Build()) {
DependsOn(OptimizationGuideKeyedServiceFactory::GetInstance());
}
UserAnnotationsServiceFactory::~UserAnnotationsServiceFactory() = default;
std::unique_ptr<KeyedService>
UserAnnotationsServiceFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const {
if (!user_annotations::IsUserAnnotationsEnabled()) {
return nullptr;
}
auto* profile = Profile::FromBrowserContext(context);
// This is not useful in kiosk or ephemeral profile mode, so simply never
// construct the service for those users.
if (IsRunningInAppMode() || IsEphemeralProfile(profile)) {
return nullptr;
}
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
if (!ogks) {
return nullptr;
}
return std::make_unique<user_annotations::UserAnnotationsService>(
ogks, ogks->GetModelQualityLogsUploaderService(), profile->GetPath(),
g_browser_process->os_crypt_async(), ogks);
}

@ -1,50 +0,0 @@
// Copyright 2024 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_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_FACTORY_H_
#define CHROME_BROWSER_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_FACTORY_H_
#include "base/no_destructor.h"
#include "chrome/browser/profiles/profile_keyed_service_factory.h"
namespace content {
class BrowserContext;
} // namespace content
namespace user_annotations {
class UserAnnotationsService;
} // namespace user_annotations
class Profile;
// LazyInstance that owns all UserAnnotationsService(s) and associates
// them with Profiles.
class UserAnnotationsServiceFactory : public ProfileKeyedServiceFactory {
public:
// Gets the UserAnnotationsService for the profile.
//
// Returns null if the features that allow for this to provide useful
// information are disabled.
static user_annotations::UserAnnotationsService* GetForProfile(
Profile* profile);
// Gets the LazyInstance that owns all UserAnnotationsService(s).
static UserAnnotationsServiceFactory* GetInstance();
UserAnnotationsServiceFactory(const UserAnnotationsServiceFactory&) = delete;
UserAnnotationsServiceFactory& operator=(
const UserAnnotationsServiceFactory&) = delete;
private:
friend base::NoDestructor<UserAnnotationsServiceFactory>;
UserAnnotationsServiceFactory();
~UserAnnotationsServiceFactory() override;
// BrowserContextKeyedServiceFactory:
std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const override;
};
#endif // CHROME_BROWSER_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_FACTORY_H_

@ -2216,7 +2216,6 @@ if (!is_android) {
"//chrome/browser/ui/webui/top_chrome",
"//chrome/browser/ui/webui/top_chrome:test_support",
"//chrome/browser/ui/webui/whats_new",
"//chrome/browser/user_annotations:browser_tests",
"//chrome/browser/web_applications:browser_tests",
"//chrome/browser/web_applications:features",
"//chrome/browser/web_applications:prevent_close_test_support",
@ -2493,7 +2492,6 @@ if (!is_android) {
"//components/url_formatter/spoof_checks/top_domains:generate_top_domains_test_trie",
"//components/url_formatter/spoof_checks/top_domains:test_top_bucket_domains",
"//components/url_formatter/spoof_checks/top_domains:test_top_bucket_domains_header",
"//components/user_annotations",
"//components/user_education/common",
"//components/user_education/test",
"//components/user_education/webui:webui",
@ -4525,7 +4523,6 @@ if (!is_android) {
# when tests that include chrome_zoom_level_prefs.h get modularized, eg
# tabs_test.cc, app_browsertest.cc, host_zoom_map_browsertest.cc and ats_browsertest.cc.
"//chrome/browser/ui/zoom",
"//chrome/browser/user_annotations:user_annotations",
"//chrome/browser/web_applications/extensions",
"//chrome/common/extensions/api",
"//chrome/services/media_gallery_util/public/cpp:browser_tests",
@ -4538,13 +4535,11 @@ if (!is_android) {
"//components/media_router/browser:test_support",
"//components/media_router/common:test_support",
"//components/optimization_guide/optimization_guide_internals/webui",
"//components/user_annotations:test_support",
"//components/web_package",
# TODO(rockot) bug 505926: The chrome_extensions_browsertests_sources
# target should be deleted and this line removed. See the
# chrome_extensions_browsertests_sources target for more.
"//components/user_annotations:test_support",
"//extensions:chrome_extensions_browsertests_sources",
"//extensions/browser:test_support",
"//extensions/browser/api/storage:settings_namespace",
@ -6796,7 +6791,6 @@ test("unit_tests") {
"//components/url_formatter/spoof_checks/top_domains:generate_top_domains_test_trie",
"//components/url_formatter/spoof_checks/top_domains:test_top_bucket_domains",
"//components/url_formatter/spoof_checks/top_domains:test_top_bucket_domains_header",
"//components/user_annotations:test_support",
"//components/user_education/common",
"//components/user_education/test",
"//components/user_manager",
@ -8124,7 +8118,6 @@ test("unit_tests") {
"//chrome/browser/ui/zoom",
"//chrome/browser/ui/zoom:unit_tests",
"//chrome/browser/upgrade_detector:build_state_observer",
"//chrome/browser/user_annotations",
"//chrome/browser/web_applications:features",
"//chrome/browser/web_applications:web_applications_test_support",
"//chrome/browser/webauthn:test_support",
@ -8176,8 +8169,6 @@ test("unit_tests") {
"//components/soda:constants",
"//components/supervised_user/core/browser",
"//components/sync:test_support",
"//components/user_annotations",
"//components/user_annotations:test_support",
"//components/user_education/common",
"//components/user_education/test",
"//components/webapps/browser",
@ -10845,7 +10836,6 @@ if (!is_android && !is_chromeos_device) {
"//chrome/browser/ui/views/page_action",
"//chrome/browser/ui/views/side_panel",
"//chrome/browser/ui/views/toolbar",
"//chrome/browser/user_annotations:user_annotations",
"//chrome/browser/web_applications:features",
"//chrome/browser/web_applications:interactive_ui_tests",
"//chrome/browser/web_applications:web_applications_test_support",
@ -10919,7 +10909,6 @@ if (!is_android && !is_chromeos_device) {
"//components/translate/content/browser:test_support",
"//components/ukm:test_support",
"//components/ukm:ukm_test_helper",
"//components/user_annotations:user_annotations",
"//components/user_education/common",
"//components/user_education/test",
"//components/webapps/browser:test_support",

@ -366,7 +366,6 @@ test("components_unittests") {
"//components/url_formatter/spoof_checks/top_domains:unit_tests",
"//components/url_matcher:unit_tests",
"//components/url_pattern_index:unit_tests",
"//components/user_annotations:unit_tests",
"//components/variations:unit_tests",
"//components/variations/field_trial_config:unit_tests",
"//components/variations/service:unit_tests",

@ -838,7 +838,6 @@ static_library("browser") {
"//components/strings",
"//components/sync",
"//components/translate/core/common",
"//components/user_annotations:types",
"//components/variations",
"//components/variations/net",
"//components/version_info",
@ -1110,7 +1109,6 @@ static_library("test_support") {
"//components/translate/core/browser:test_support",
"//components/ukm",
"//components/ukm:test_support",
"//components/user_annotations:types",
"//components/variations",
"//components/variations:test_support",
"//components/variations/net",

@ -28,7 +28,6 @@ include_rules = [
"+components/sync_preferences",
"+components/translate/core/browser",
"+components/translate/core/common",
"+components/user_annotations",
"+components/variations",
"+components/version_info",
"+components/webdata/common",

@ -4,7 +4,6 @@ include_rules = [
"+components/optimization_guide/proto",
"+components/prefs",
"+components/strings/grit",
"+components/user_annotations",
"+ui/base",
"+ui/native_theme",
]

@ -41,7 +41,8 @@
#include "testing/gtest/include/gtest/gtest.h"
// TODO(crbug.com/389629573): Refactor this test to handle only the
// implementation under `autofill::features::kAutofillAiWithDataSchema` flag.
// implementation under `autofill::features::kAutofillAiWithDataSchema`
// flag.
namespace autofill_ai {
namespace {

@ -43,7 +43,6 @@ static_library("core") {
"//components/prefs",
"//components/strings",
"//components/sync",
"//components/user_annotations",
"//components/version_info",
"//components/webdata/common",
"//ui/base",

@ -12,7 +12,6 @@ include_rules = [
"+components/sync/service",
"+components/sync/test",
"+components/sync_preferences",
"+components/user_annotations",
"+components/version_info",
"+components/webdata/common",
"+net",

@ -318,18 +318,7 @@ std::u16string GetCounterTextFromResult(
NOTREACHED();
}
AutofillCounter::ResultInt num_user_annotations =
autofill_result->num_user_annotation_entries();
if (num_user_annotations) {
return l10n_util::GetStringFUTF16(
IDS_DEL_AUTOFILL_SYNCABLE_NON_SYNCABLE_COMBINATION,
payment_methods_addresses_autocomplete_entries_part,
l10n_util::GetPluralStringFUTF16(
IDS_DEL_AUTOFILL_COUNTER_USER_ANNOTATION_ENTRIES,
num_user_annotations));
} else {
return payment_methods_addresses_autocomplete_entries_part;
}
return payment_methods_addresses_autocomplete_entries_part;
}
NOTREACHED();

@ -64,8 +64,7 @@ class BrowsingDataUtilsTest : public testing::Test {
TEST_F(BrowsingDataUtilsTest, AutofillCounterResult) {
autofill::TestPersonalDataManager test_personal_data_manager;
AutofillCounter counter(&test_personal_data_manager,
base::MakeRefCounted<FakeWebDataService>(), nullptr,
nullptr);
base::MakeRefCounted<FakeWebDataService>(), nullptr);
// Test all configurations of zero and nonzero partial results for datatypes.
// Test singular and plural for each datatype.
@ -73,34 +72,29 @@ TEST_F(BrowsingDataUtilsTest, AutofillCounterResult) {
int num_credit_cards;
int num_addresses;
int num_suggestions;
int num_user_annotation_entries;
bool sync_enabled;
std::string expected_output;
} kTestCases[] = {
{0, 0, 0, 0, false, "None"},
{0, 0, 0, 0, true, "None"},
{1, 0, 0, 0, false, "1 payment method"},
{0, 5, 0, 0, false, "5 addresses"},
{0, 0, 1, 0, false, "1 suggestion"},
{0, 0, 2, 0, false, "2 suggestions"},
{0, 0, 2, 0, true, "2 suggestions (synced)"},
{4, 7, 0, 0, false, "4 payment methods, 7 addresses"},
{4, 7, 0, 0, true, "4 payment methods, 7 addresses (synced)"},
{3, 0, 9, 0, false, "3 payment methods, 9 other suggestions"},
{0, 1, 1, 0, false, "1 address, 1 other suggestion"},
{9, 6, 3, 0, false, "9 payment methods, 6 addresses, 3 others"},
{4, 2, 1, 0, false, "4 payment methods, 2 addresses, 1 other"},
{4, 2, 1, 0, true, "4 payment methods, 2 addresses, 1 other (synced)"},
{1, 0, 0, 1, false, "1 payment method; 1 suggestion (device only)"},
{1, 1, 0, 2, true,
"1 payment method, 1 address (synced); 2 suggestions (device only)"},
{0, 0, 0, false, "None"},
{0, 0, 0, true, "None"},
{1, 0, 0, false, "1 payment method"},
{0, 5, 0, false, "5 addresses"},
{0, 0, 1, false, "1 suggestion"},
{0, 0, 2, false, "2 suggestions"},
{0, 0, 2, true, "2 suggestions (synced)"},
{4, 7, 0, false, "4 payment methods, 7 addresses"},
{4, 7, 0, true, "4 payment methods, 7 addresses (synced)"},
{3, 0, 9, false, "3 payment methods, 9 other suggestions"},
{0, 1, 1, false, "1 address, 1 other suggestion"},
{9, 6, 3, false, "9 payment methods, 6 addresses, 3 others"},
{4, 2, 1, false, "4 payment methods, 2 addresses, 1 other"},
{4, 2, 1, true, "4 payment methods, 2 addresses, 1 other (synced)"},
};
for (const TestCase& test_case : kTestCases) {
AutofillCounter::AutofillResult result(
&counter, test_case.num_suggestions, test_case.num_credit_cards,
test_case.num_addresses, test_case.num_user_annotation_entries,
test_case.sync_enabled);
test_case.num_addresses, test_case.sync_enabled);
SCOPED_TRACE(
base::StringPrintf("Test params: %d payment method(s), "

@ -34,11 +34,9 @@ namespace browsing_data {
AutofillCounter::AutofillCounter(
autofill::PersonalDataManager* personal_data_manager,
scoped_refptr<autofill::AutofillWebDataService> web_data_service,
user_annotations::UserAnnotationsService* user_annotations_service,
syncer::SyncService* sync_service)
: personal_data_manager_(personal_data_manager),
web_data_service_(web_data_service),
user_annotations_service_(user_annotations_service),
sync_tracker_(this, sync_service),
suggestions_query_(0),
num_suggestions_(0) {}
@ -118,19 +116,6 @@ void AutofillCounter::Count() {
start, end,
base::BindOnce(&AutofillCounter::OnWebDataServiceRequestDone,
weak_ptr_factory_.GetWeakPtr()));
num_user_annotations_.reset();
// Not all platforms support user annotations, for those the service is not
// provided and the value is set to 0 immediately.
if (user_annotations_service_) {
user_annotations_service_->GetCountOfValuesContainedBetween(
start, end,
base::BindOnce(&AutofillCounter::OnUserAnnotationsServiceResponse,
user_annotations_requirest_weak_factory_.GetWeakPtr()));
} else {
num_user_annotations_ = 0;
}
}
void AutofillCounter::OnWebDataServiceRequestDone(
@ -152,42 +137,31 @@ void AutofillCounter::OnWebDataServiceRequestDone(
ReportResultIfReady();
}
void AutofillCounter::OnUserAnnotationsServiceResponse(
int num_user_annotations) {
num_user_annotations_ = num_user_annotations;
ReportResultIfReady();
}
void AutofillCounter::CancelAllRequests() {
if (suggestions_query_)
if (suggestions_query_) {
web_data_service_->CancelRequest(suggestions_query_);
user_annotations_requirest_weak_factory_.InvalidateWeakPtrs();
}
}
void AutofillCounter::ReportResultIfReady() {
if (num_suggestions_.has_value() && num_user_annotations_.has_value()) {
if (num_suggestions_.has_value()) {
auto reported_result = std::make_unique<AutofillResult>(
this, *num_suggestions_, num_credit_cards_, num_addresses_,
*num_user_annotations_, sync_tracker_.IsSyncActive());
sync_tracker_.IsSyncActive());
ReportResult(std::move(reported_result));
}
}
// AutofillCounter::AutofillResult ---------------------------------------------
AutofillCounter::AutofillResult::AutofillResult(
const AutofillCounter* source,
ResultInt num_suggestions,
ResultInt num_credit_cards,
ResultInt num_addresses,
ResultInt num_user_annotation_entries,
bool autofill_sync_enabled_)
AutofillCounter::AutofillResult::AutofillResult(const AutofillCounter* source,
ResultInt num_suggestions,
ResultInt num_credit_cards,
ResultInt num_addresses,
bool autofill_sync_enabled_)
: SyncResult(source, num_suggestions, autofill_sync_enabled_),
num_credit_cards_(num_credit_cards),
num_addresses_(num_addresses),
num_user_annotation_entries_(num_user_annotation_entries) {}
num_addresses_(num_addresses) {}
AutofillCounter::AutofillResult::~AutofillResult() = default;

@ -12,7 +12,6 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/browsing_data/core/counters/browsing_data_counter.h"
#include "components/browsing_data/core/counters/sync_tracker.h"
#include "components/user_annotations/user_annotations_service.h"
namespace autofill {
class AutofillWebDataService;
@ -29,7 +28,6 @@ class AutofillCounter : public browsing_data::BrowsingDataCounter {
ResultInt num_suggestions,
ResultInt num_credit_cards,
ResultInt num_addresses,
ResultInt num_user_annotation_entries,
bool autofill_sync_enabled_);
AutofillResult(const AutofillResult&) = delete;
@ -39,20 +37,15 @@ class AutofillCounter : public browsing_data::BrowsingDataCounter {
ResultInt num_credit_cards() const { return num_credit_cards_; }
ResultInt num_addresses() const { return num_addresses_; }
ResultInt num_user_annotation_entries() const {
return num_user_annotation_entries_;
}
private:
ResultInt num_credit_cards_;
ResultInt num_addresses_;
ResultInt num_user_annotation_entries_;
};
AutofillCounter(
autofill::PersonalDataManager* personal_data_manager,
scoped_refptr<autofill::AutofillWebDataService> web_data_service,
user_annotations::UserAnnotationsService* user_annotations_service,
syncer::SyncService* sync_service);
AutofillCounter(const AutofillCounter&) = delete;
@ -82,40 +75,30 @@ class AutofillCounter : public browsing_data::BrowsingDataCounter {
void OnWebDataServiceRequestDone(WebDataServiceBase::Handle handle,
std::unique_ptr<WDTypedResult> result);
void OnUserAnnotationsServiceResponse(int num_user_annotations);
// Cancel all pending requests to AutofillWebdataService.
void CancelAllRequests();
// This methods checks whether the asynchronous pieces (`num_suggestions_`
// and `num_user_annotations_` for now) are ready, and if they are, creates
// a `AutofillResult` and calls `ReportResult()`. It should be called each
// time the report data readiness may change.
// This methods checks whether the asynchronous pieces (`num_suggestions_` for
// now) are ready, and if they are, creates a `AutofillResult` and calls
// `ReportResult()`. It should be called each time the report data readiness
// may change.
void ReportResultIfReady();
base::ThreadChecker thread_checker_;
raw_ptr<autofill::PersonalDataManager> personal_data_manager_;
scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
raw_ptr<user_annotations::UserAnnotationsService> user_annotations_service_;
SyncTracker sync_tracker_;
WebDataServiceBase::Handle suggestions_query_;
std::optional<ResultInt> num_suggestions_;
std::optional<ResultInt> num_user_annotations_;
ResultInt num_credit_cards_;
ResultInt num_addresses_;
base::Time period_start_for_testing_;
base::Time period_end_for_testing_;
// UserAnnotationsService doesn't provide API for canceling requests. Pointers
// from this factory are used to bind to its request callbacks, which allows
// to cancel them if needed.
base::WeakPtrFactory<AutofillCounter>
user_annotations_requirest_weak_factory_{this};
base::WeakPtrFactory<AutofillCounter> weak_ptr_factory_{this};
};

@ -1,84 +0,0 @@
# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//components/optimization_guide/features.gni")
source_set("types") {
sources = [
"user_annotations_types.cc",
"user_annotations_types.h",
]
public_deps = [
"//base",
"//components/optimization_guide/proto:optimization_guide_proto",
]
}
static_library("user_annotations") {
sources = [
"form_submission_handler.cc",
"form_submission_handler.h",
"user_annotations_database.cc",
"user_annotations_database.h",
"user_annotations_features.cc",
"user_annotations_features.h",
"user_annotations_service.cc",
"user_annotations_service.h",
"user_annotations_switches.cc",
"user_annotations_switches.h",
"user_annotations_types.h",
]
public_deps = [
":types",
"//base",
"//components/autofill/core/browser",
"//components/autofill/core/common",
"//components/keyed_service/core",
"//components/optimization_guide/core",
"//components/optimization_guide/proto:optimization_guide_proto",
]
deps = [
"//components/autofill_ai/core/browser:features",
"//components/os_crypt/async/browser",
"//components/os_crypt/async/common",
"//sql",
"//url",
]
}
static_library("test_support") {
testonly = true
sources = [
"test_user_annotations_service.cc",
"test_user_annotations_service.h",
]
deps = [ ":user_annotations" ]
}
source_set("unit_tests") {
testonly = true
sources = [
"user_annotations_database_unittest.cc",
"user_annotations_features_unittest.cc",
"user_annotations_switches_unittest.cc",
]
if (build_with_model_execution) {
sources += [ "user_annotations_service_unittest.cc" ]
}
deps = [
":test_support",
":user_annotations",
"//base/test:test_support",
"//components/autofill/core/browser:test_support",
"//components/autofill_ai/core/browser:features",
"//components/optimization_guide/core:test_support",
"//components/os_crypt/async/browser:test_support",
"//components/prefs:test_support",
"//testing/gtest",
"//url",
]
}

@ -1,11 +0,0 @@
include_rules = [
"+components/autofill/core/browser",
"+components/autofill/core/common",
"+components/autofill_ai/core/browser",
"+components/keyed_service/core",
"+components/optimization_guide/core",
"+components/optimization_guide/proto",
"+components/os_crypt/async",
"+components/prefs",
"+sql",
];

@ -1 +0,0 @@
mixins: "//components/optimization_guide/COMMON_METADATA"

@ -1 +0,0 @@
file://components/optimization_guide/OWNERS

@ -1,195 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/form_submission_handler.h"
#include <optional>
#include "base/metrics/histogram_functions.h"
#include "components/autofill/core/browser/form_processing/optimization_guide_proto_util.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/optimization_guide/core/model_quality/model_execution_logging_wrappers.h"
#include "components/optimization_guide/core/model_quality/model_quality_log_entry.h"
#include "components/optimization_guide/core/optimization_guide_util.h"
#include "components/optimization_guide/proto/features/forms_annotations.pb.h"
#include "components/user_annotations/user_annotations_features.h"
#include "components/user_annotations/user_annotations_service.h"
namespace user_annotations {
FormSubmissionHandler::FormSubmissionHandler(
UserAnnotationsService* user_annotations_service,
const GURL& url,
const std::string& title,
optimization_guide::proto::AXTreeUpdate ax_tree_update,
std::unique_ptr<autofill::FormStructure> form,
ImportFormCallback callback)
: url_(url),
title_(title),
ax_tree_update_(std::move(ax_tree_update)),
form_(std::move(form)),
callback_(std::move(callback)),
user_annotations_service_(user_annotations_service) {}
FormSubmissionHandler::~FormSubmissionHandler() = default;
void FormSubmissionHandler::Start() {
completion_timer_.Start(
FROM_HERE, GetFormSubmissionCompletionTimeout(),
base::BindOnce(&FormSubmissionHandler::OnCompletionTimeout,
weak_ptr_factory_.GetWeakPtr()));
user_annotations_service_->RetrieveAllEntries(
base::BindOnce(&FormSubmissionHandler::ExecuteModelWithEntries,
weak_ptr_factory_.GetWeakPtr()));
}
void FormSubmissionHandler::OnCompletionTimeout() {
// TODO: 372715386 - Handle the timeout and notify the save prompt UX.
}
void FormSubmissionHandler::ExecuteModelWithEntries(
UserAnnotationsEntries entries) {
// Construct request.
optimization_guide::proto::FormsAnnotationsRequest request;
optimization_guide::proto::PageContext* page_context =
request.mutable_page_context();
page_context->set_url(url_.spec());
page_context->set_title(title_);
*page_context->mutable_ax_tree_data() = std::move(ax_tree_update_);
*request.mutable_form_data() = autofill::ToFormDataProto(*form_);
*request.mutable_entries() = {std::make_move_iterator(entries.begin()),
std::make_move_iterator(entries.end())};
optimization_guide::ModelExecutionCallbackWithLogging<
optimization_guide::proto::FormsAnnotationsLoggingData>
wrapper_callback = base::BindOnce(&FormSubmissionHandler::OnModelExecuted,
weak_ptr_factory_.GetWeakPtr());
optimization_guide::ExecuteModelWithLogging(
user_annotations_service_->model_executor(),
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, request,
std::nullopt, std::move(wrapper_callback));
}
void FormSubmissionHandler::OnModelExecuted(
optimization_guide::OptimizationGuideModelExecutionResult result,
std::unique_ptr<optimization_guide::proto::FormsAnnotationsLoggingData>
logging_data) {
CHECK(logging_data);
auto log_entry = std::make_unique<optimization_guide::ModelQualityLogEntry>(
user_annotations_service_->logs_uploader());
*log_entry->log_ai_data_request()->mutable_forms_annotations() =
*logging_data;
if (!result.response.has_value()) {
SendFormSubmissionResult(
base::unexpected(UserAnnotationsExecutionResult::kResponseError),
std::move(log_entry));
return;
}
std::optional<optimization_guide::proto::FormsAnnotationsResponse>
maybe_response = optimization_guide::ParsedAnyMetadata<
optimization_guide::proto::FormsAnnotationsResponse>(
result.response.value());
if (!maybe_response) {
SendFormSubmissionResult(
base::unexpected(UserAnnotationsExecutionResult::kResponseMalformed),
std::move(log_entry));
return;
}
if (!user_annotations_service_->IsDatabaseReady()) {
SendFormSubmissionResult(
base::unexpected(UserAnnotationsExecutionResult::kCryptNotInitialized),
std::move(log_entry));
return;
}
SendFormSubmissionResult(base::ok(maybe_response.value()),
std::move(log_entry));
}
void FormSubmissionHandler::SendFormSubmissionResult(
FormSubmissionResult result,
std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry) {
base::UmaHistogramEnumeration(
"UserAnnotations.AddFormSubmissionResult",
result.error_or(UserAnnotationsExecutionResult::kSuccess));
if (!result.has_value()) {
CHECK_NE(result.error(), UserAnnotationsExecutionResult::kSuccess);
optimization_guide::ModelQualityLogEntry::Drop(std::move(log_entry));
if (callback_) {
std::move(callback_).Run(
std::move(form_),
/*form_annotation_response=*/nullptr,
/*prompt_acceptance_callback=*/base::DoNothing());
}
NotifyCompletion();
return;
}
if (result->upserted_entries().empty()) {
optimization_guide::ModelQualityLogEntry::Drop(std::move(log_entry));
std::move(callback_).Run(std::move(form_),
/*form_annotation_response=*/nullptr,
/*prompt_acceptance_callback=*/base::DoNothing());
NotifyCompletion();
return;
}
auto form_annotation_response = std::make_unique<FormAnnotationResponse>(
UserAnnotationsEntries(result->upserted_entries().begin(),
result->upserted_entries().end()),
log_entry->model_execution_id());
std::move(callback_).Run(
std::move(form_), std::move(form_annotation_response),
base::BindOnce(&FormSubmissionHandler::OnImportFormConfirmation,
weak_ptr_factory_.GetWeakPtr(), std::move(result),
std::move(log_entry)));
}
void FormSubmissionHandler::OnImportFormConfirmation(
FormSubmissionResult result,
std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry,
PromptAcceptanceResult prompt_acceptance_result) {
if (!prompt_acceptance_result.did_user_interact &&
!prompt_acceptance_result.did_thumbs_down_triggered &&
!prompt_acceptance_result.did_thumbs_up_triggered) {
// Drop the log entry, when the user did no interaction with the save prompt
// bubble.
optimization_guide::ModelQualityLogEntry::Drop(std::move(log_entry));
NotifyCompletion();
return;
}
if (log_entry) {
auto* quality_entry = log_entry->log_ai_data_request()
->mutable_forms_annotations()
->mutable_quality();
if (prompt_acceptance_result.did_thumbs_down_triggered) {
quality_entry->set_user_feedback(
optimization_guide::proto::UserFeedback::USER_FEEDBACK_THUMBS_DOWN);
} else if (prompt_acceptance_result.did_thumbs_up_triggered) {
quality_entry->set_user_feedback(
optimization_guide::proto::UserFeedback::USER_FEEDBACK_THUMBS_UP);
}
quality_entry->set_save_prompt_action(
prompt_acceptance_result.prompt_was_accepted
? optimization_guide::proto::FormsAnnotationsSavePromptAction::
FORMS_ANNOTATIONS_SAVE_PROMPT_ACTION_ACCEPTED
: optimization_guide::proto::FormsAnnotationsSavePromptAction::
FORMS_ANNOTATIONS_SAVE_PROMPT_ACTION_REJECTED);
optimization_guide::ModelQualityLogEntry::Upload(std::move(log_entry));
}
if (!prompt_acceptance_result.prompt_was_accepted) {
NotifyCompletion();
return;
}
user_annotations_service_->SaveEntries(result.value());
NotifyCompletion();
}
void FormSubmissionHandler::NotifyCompletion() {
completion_timer_.Stop();
user_annotations_service_->OnFormSubmissionComplete();
}
} // namespace user_annotations

@ -1,101 +0,0 @@
// Copyright 2024 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_USER_ANNOTATIONS_FORM_SUBMISSION_HANDLER_H_
#define COMPONENTS_USER_ANNOTATIONS_FORM_SUBMISSION_HANDLER_H_
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "base/types/expected.h"
#include "components/optimization_guide/proto/features/forms_annotations.pb.h"
#include "components/user_annotations/user_annotations_service.h"
#include "components/user_annotations/user_annotations_types.h"
namespace autofill {
class FormStructure;
} // namespace autofill
namespace optimization_guide {
class OptimizationGuideDecider;
namespace proto {
class AXTreeUpdate;
} // namespace proto
} // namespace optimization_guide
namespace user_annotations {
// Handles the various stages of one form submission. First, the existing
// annotations are retrieved from database, and sent along with the form entries
// to the form annotations model execution. Then the returned annotations are
// sent for user confirmation, before they are persisted to the database.
class FormSubmissionHandler {
public:
FormSubmissionHandler(UserAnnotationsService* user_annotations_service,
const GURL& url,
const std::string& title,
optimization_guide::proto::AXTreeUpdate ax_tree_update,
std::unique_ptr<autofill::FormStructure> form,
ImportFormCallback callback);
~FormSubmissionHandler();
FormSubmissionHandler(const FormSubmissionHandler&) = delete;
FormSubmissionHandler& operator=(const FormSubmissionHandler&) = delete;
// Starts the form submission process.
void Start();
private:
using FormSubmissionResult =
base::expected<optimization_guide::proto::FormsAnnotationsResponse,
UserAnnotationsExecutionResult>;
void ExecuteModelWithEntries(UserAnnotationsEntries entries);
// Processes model execution response. Invoked when model execution has been
// received.
void OnModelExecuted(
optimization_guide::OptimizationGuideModelExecutionResult result,
std::unique_ptr<optimization_guide::proto::FormsAnnotationsLoggingData>
logging_data);
// Sends the result of form submission.
void SendFormSubmissionResult(
FormSubmissionResult result,
std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry);
// Called when decision has been made whether to import form entries.
// `prompt_was_accepted` is the user decision, and `entries` will be
// persisted to database when true.
void OnImportFormConfirmation(
FormSubmissionResult result,
std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry,
PromptAcceptanceResult prompt_acceptance_result);
// Called when the timeout is triggered.
void OnCompletionTimeout();
// Notifies the service that the form submission stages have been complete.
void NotifyCompletion();
GURL url_;
std::string title_;
optimization_guide::proto::AXTreeUpdate ax_tree_update_;
std::unique_ptr<autofill::FormStructure> form_;
ImportFormCallback callback_;
// Guaranteed to outlive `this`.
raw_ptr<UserAnnotationsService> user_annotations_service_;
// Timer to enforce timeout on the form submission completion.
base::OneShotTimer completion_timer_;
base::WeakPtrFactory<FormSubmissionHandler> weak_ptr_factory_{this};
};
} // namespace user_annotations
#endif // COMPONENTS_USER_ANNOTATIONS_FORM_SUBMISSION_HANDLER_H_

@ -1,107 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/test_user_annotations_service.h"
#include "base/containers/contains.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
#include "components/user_annotations/user_annotations_types.h"
namespace user_annotations {
TestUserAnnotationsService::TestUserAnnotationsService() = default;
TestUserAnnotationsService::~TestUserAnnotationsService() = default;
void TestUserAnnotationsService::ReplaceAllEntries(
UserAnnotationsEntries entries) {
entries_ = std::move(entries);
}
void TestUserAnnotationsService::RemoveEntry(EntryID entry_id,
base::OnceClosure callback) {
size_t count = 0;
for (const optimization_guide::proto::UserAnnotationsEntry& entry :
entries_) {
if (entry_id == entry.entry_id()) {
entries_.erase(entries_.begin() + count);
break;
}
count++;
}
std::move(callback).Run();
}
void TestUserAnnotationsService::RemoveAllEntries(base::OnceClosure callback) {
entries_.clear();
std::move(callback).Run();
}
void TestUserAnnotationsService::AddFormSubmission(
const GURL& url,
const std::string& title,
optimization_guide::proto::AXTreeUpdate ax_tree_update,
std::unique_ptr<autofill::FormStructure> form,
ImportFormCallback callback) {
if (should_import_form_data_) {
int64_t entry_id = 0;
for (const std::unique_ptr<autofill::AutofillField>& field :
form->fields()) {
optimization_guide::proto::UserAnnotationsEntry entry;
entry.set_entry_id(entry_id++);
entry.set_key(base::UTF16ToUTF8(field->label()));
entry.set_value(
base::UTF16ToUTF8(field->value(autofill::ValueSemantics::kCurrent)));
entries_.emplace_back(std::move(entry));
}
std::move(callback).Run(std::move(form),
std::make_unique<FormAnnotationResponse>(
entries_, /*model_execution_id=*/std::string()),
/*prompt_acceptance_callback=*/base::DoNothing());
return;
}
std::move(callback).Run(std::move(form), /*form_annotation_response=*/nullptr,
/*prompt_acceptance_callback=*/base::DoNothing());
}
void TestUserAnnotationsService::RetrieveAllEntries(
base::OnceCallback<void(UserAnnotationsEntries)> callback) {
count_entries_retrieved_++;
std::move(callback).Run(entries_);
}
void TestUserAnnotationsService::AddHostToFormAnnotationsAllowlist(
const std::string& host) {
allowed_forms_annotations_hosts_.insert(host);
}
bool TestUserAnnotationsService::ShouldAddFormSubmissionForURL(
const GURL& url) {
return base::Contains(allowed_forms_annotations_hosts_, url.host());
}
void TestUserAnnotationsService::RemoveAnnotationsInRange(
const base::Time& delete_begin,
const base::Time& delete_end) {
last_received_remove_annotations_in_range_ =
std::make_pair(delete_begin, delete_end);
}
void TestUserAnnotationsService::GetCountOfValuesContainedBetween(
base::Time,
base::Time,
base::OnceCallback<void(int)> callback) {
std::move(callback).Run(entries_.size());
}
void TestUserAnnotationsService::SaveAutofillProfile(
const autofill::AutofillProfile& autofill_profile,
base::OnceCallback<void(UserAnnotationsExecutionResult)> callback) {
std::move(callback).Run(UserAnnotationsExecutionResult::kSuccess);
}
} // namespace user_annotations

@ -1,95 +0,0 @@
// Copyright 2024 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_USER_ANNOTATIONS_TEST_USER_ANNOTATIONS_SERVICE_H_
#define COMPONENTS_USER_ANNOTATIONS_TEST_USER_ANNOTATIONS_SERVICE_H_
#include <set>
#include <vector>
#include "components/user_annotations/user_annotations_service.h"
#include "components/user_annotations/user_annotations_types.h"
namespace autofill {
class FormStructure;
}
namespace optimization_guide::proto {
class UserAnnotationsEntry;
} // namespace optimization_guide::proto
namespace user_annotations {
class TestUserAnnotationsService : public UserAnnotationsService {
public:
TestUserAnnotationsService();
TestUserAnnotationsService(const TestUserAnnotationsService&) = delete;
TestUserAnnotationsService& operator=(const TestUserAnnotationsService&) =
delete;
~TestUserAnnotationsService() override;
// Replaces all entries in the service with `entries`.
void ReplaceAllEntries(UserAnnotationsEntries entries);
// `AddFormSubmission()` will only import form data if
// `should_import_form_data` is set to `true`.
void SetShouldImportFormData(bool should_import_form_data) {
should_import_form_data_ = should_import_form_data;
}
// Adds `host` to set of hosts that forms annotations are allowed on.
void AddHostToFormAnnotationsAllowlist(const std::string& host);
// UserAnnotationsService:
bool ShouldAddFormSubmissionForURL(const GURL& url) override;
void AddFormSubmission(const GURL& url,
const std::string& title,
optimization_guide::proto::AXTreeUpdate ax_tree_update,
std::unique_ptr<autofill::FormStructure> form,
ImportFormCallback callback) override;
void RetrieveAllEntries(
base::OnceCallback<void(UserAnnotationsEntries)> callback) override;
void RemoveEntry(EntryID entry_id, base::OnceClosure callback) override;
void RemoveAllEntries(base::OnceClosure callback) override;
void RemoveAnnotationsInRange(const base::Time& delete_begin,
const base::Time& delete_end) override;
// Returns the number of entries set via `ReplaceAllEntries()` ignoring
// the `begin` and `end` arguments.
void GetCountOfValuesContainedBetween(
base::Time begin,
base::Time end,
base::OnceCallback<void(int)> callback) override;
size_t count_entries_retrieved() const { return count_entries_retrieved_; }
std::pair<base::Time, base::Time> last_received_remove_annotations_in_range()
const {
return last_received_remove_annotations_in_range_;
}
void SaveAutofillProfile(
const autofill::AutofillProfile& autofill_profile,
base::OnceCallback<void(UserAnnotationsExecutionResult)> callback)
override;
private:
// An in-memory representation of the "database" of user annotation entries.
std::vector<optimization_guide::proto::UserAnnotationsEntry> entries_;
// Used in `AddFormSubmission()` to decide if form data should be imported.
bool should_import_form_data_ = true;
// Hosts allowed for forms annotations.
std::set<std::string> allowed_forms_annotations_hosts_;
// Saves the last call for `RemoveAnnotationsInRange`.
std::pair<base::Time, base::Time> last_received_remove_annotations_in_range_;
// The number of times entries have been retrieved.
size_t count_entries_retrieved_ = 0;
};
} // namespace user_annotations
#endif // COMPONENTS_USER_ANNOTATIONS_TEST_USER_ANNOTATIONS_SERVICE_H_

@ -1,237 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/user_annotations_database.h"
#include <utility>
#include "base/files/file_path.h"
#include "base/metrics/histogram_functions.h"
#include "base/sequence_checker.h"
#include "build/build_config.h"
#include "components/os_crypt/async/common/encryptor.h"
#include "components/user_annotations/user_annotations_features.h"
#include "components/user_annotations/user_annotations_service.h"
#include "sql/init_status.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
namespace user_annotations {
inline constexpr base::FilePath::CharType kUserAnnotationsName[] =
FILE_PATH_LITERAL("UserAnnotations");
// These database versions should roll together unless we develop migrations.
constexpr int kLowestSupportedDatabaseVersion = 1;
constexpr int kCurrentDatabaseVersion = 1;
namespace {
[[nodiscard]] bool CreateTable(sql::Database& db) {
static constexpr char kSqlCreateTablePassages[] =
"CREATE TABLE IF NOT EXISTS entries("
// The ID of the entry.
"entry_id INTEGER PRIMARY KEY AUTOINCREMENT,"
// The key of the entry.
"key VARCHAR NOT NULL,"
// An opaque encrypted blob of value.
"value BLOB NOT NULL,"
// The time the entry was created.
"creation_time INTEGER NOT NULL,"
// The time the entry was last modified.
"last_modified_time INTEGER NOT NULL);";
return db.Execute(kSqlCreateTablePassages);
}
} // namespace
UserAnnotationsDatabase::UserAnnotationsDatabase(
const base::FilePath& storage_dir,
os_crypt_async::Encryptor encryptor)
: encryptor_(std::move(encryptor)) {
InitInternal(storage_dir);
// TODO(b:361696651): Record the DB init status.
}
UserAnnotationsDatabase::~UserAnnotationsDatabase() = default;
sql::InitStatus UserAnnotationsDatabase::InitInternal(
const base::FilePath& storage_dir) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::FilePath db_file_path = storage_dir.Append(kUserAnnotationsName);
if (!db_.Open(db_file_path)) {
return sql::InitStatus::INIT_FAILURE;
}
// Raze old incompatible databases.
if (sql::MetaTable::RazeIfIncompatible(&db_, kLowestSupportedDatabaseVersion,
kCurrentDatabaseVersion) ==
sql::RazeIfIncompatibleResult::kFailed) {
return sql::InitStatus::INIT_FAILURE;
}
// Wrap initialization in a transaction to make it atomic.
sql::Transaction transaction(&db_);
if (!transaction.Begin()) {
return sql::InitStatus::INIT_FAILURE;
}
// Initialize the current version meta table. Safest to leave the compatible
// version equal to the current version - unless we know we're making a very
// safe backwards-compatible schema change.
sql::MetaTable meta_table;
if (!meta_table.Init(&db_, kCurrentDatabaseVersion,
/*compatible_version=*/kCurrentDatabaseVersion)) {
return sql::InitStatus::INIT_FAILURE;
}
if (meta_table.GetCompatibleVersionNumber() > kCurrentDatabaseVersion) {
return sql::INIT_TOO_NEW;
}
if (!CreateTable(db_)) {
return sql::INIT_FAILURE;
}
if (!transaction.Commit()) {
return sql::INIT_FAILURE;
}
return sql::InitStatus::INIT_OK;
}
UserAnnotationsExecutionResult UserAnnotationsDatabase::UpdateEntries(
const UserAnnotationsEntries& upserted_entries,
const std::set<EntryID>& deleted_entry_ids) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sql::Transaction transaction(&db_);
if (!transaction.Begin()) {
return UserAnnotationsExecutionResult::kSqlError;
}
auto now_time = base::Time::Now();
for (const auto& entry : upserted_entries) {
auto encrypted_value = encryptor_.EncryptString(entry.value());
if (!encrypted_value) {
return UserAnnotationsExecutionResult::kCryptError;
}
if (entry.entry_id() == 0) {
// New entry.
static constexpr char kSqlInsertEntry[] =
"INSERT INTO entries(key, value, creation_time, "
"last_modified_time) "
"VALUES(?,?,?,?)";
sql::Statement statement(
db_.GetCachedStatement(SQL_FROM_HERE, kSqlInsertEntry));
statement.BindString(0, entry.key());
statement.BindBlob(1, *encrypted_value);
statement.BindTime(2, now_time);
statement.BindTime(3, now_time);
if (!statement.Run()) {
return UserAnnotationsExecutionResult::kSqlError;
}
} else {
static constexpr char kSqlUpdateEntry[] =
"UPDATE entries SET key=?, value=?, last_modified_time=? WHERE "
"entry_id=?";
sql::Statement statement(
db_.GetCachedStatement(SQL_FROM_HERE, kSqlUpdateEntry));
statement.BindString(0, entry.key());
statement.BindBlob(1, *encrypted_value);
statement.BindTime(2, now_time);
statement.BindInt64(3, entry.entry_id());
if (!statement.Run()) {
return UserAnnotationsExecutionResult::kSqlError;
}
}
}
for (const auto& entry_id : deleted_entry_ids) {
static constexpr char kSqlDeleteEntries[] =
"DELETE FROM entries WHERE entry_id = ?";
sql::Statement statement(
db_.GetCachedStatement(SQL_FROM_HERE, kSqlDeleteEntries));
statement.BindInt64(0, entry_id);
if (!statement.Run()) {
return UserAnnotationsExecutionResult::kSqlError;
}
}
if (!transaction.Commit()) {
return UserAnnotationsExecutionResult::kSqlError;
}
return UserAnnotationsExecutionResult::kSuccess;
}
UserAnnotationsEntryRetrievalResult
UserAnnotationsDatabase::RetrieveAllEntries() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UserAnnotationsEntries entries;
static constexpr char kSqlSelectAllEntries[] =
"SELECT entry_id, key, value FROM entries";
sql::Statement statement(
db_.GetCachedStatement(SQL_FROM_HERE, kSqlSelectAllEntries));
while (statement.Step()) {
optimization_guide::proto::UserAnnotationsEntry entry;
entry.set_entry_id(statement.ColumnInt64(0));
entry.set_key(statement.ColumnString(1));
auto decrypted_value = encryptor_.DecryptData(statement.ColumnBlob(2));
if (!decrypted_value) {
return base::unexpected(UserAnnotationsExecutionResult::kCryptError);
}
entry.set_value(*decrypted_value);
entries.push_back(std::move(entry));
}
return entries;
}
bool UserAnnotationsDatabase::RemoveEntry(EntryID entry_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sql::Statement delete_statement(db_.GetCachedStatement(
SQL_FROM_HERE, "DELETE FROM entries WHERE entry_id=?"));
delete_statement.BindInt64(0, entry_id);
return delete_statement.Run();
}
bool UserAnnotationsDatabase::RemoveAllEntries() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sql::Statement delete_statement(
db_.GetCachedStatement(SQL_FROM_HERE, "DELETE FROM entries"));
return delete_statement.Run();
}
void UserAnnotationsDatabase::RemoveAnnotationsInRange(
const base::Time& delete_begin,
const base::Time& delete_end) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sql::Statement delete_statement(
db_.GetCachedStatement(SQL_FROM_HERE,
"DELETE FROM entries WHERE last_modified_time > ? "
"AND last_modified_time < ?"));
delete_statement.BindTime(0, delete_begin);
delete_statement.BindTime(1, delete_end);
delete_statement.Run();
}
int UserAnnotationsDatabase::GetCountOfValuesContainedBetween(base::Time begin,
base::Time end) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sql::Statement s(
db_.GetCachedStatement(SQL_FROM_HERE,
"SELECT COUNT(DISTINCT(entry_id)) FROM entries "
"WHERE last_modified_time > ? "
"AND last_modified_time < ?"));
s.BindTime(0, begin);
s.BindTime(1, end);
if (!s.Step()) {
// This might happen in case of I/O errors. See crbug.com/332263206.
return 0;
}
return s.ColumnInt(0);
}
} // namespace user_annotations

@ -1,76 +0,0 @@
// Copyright 2024 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_USER_ANNOTATIONS_USER_ANNOTATIONS_DATABASE_H_
#define COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_DATABASE_H_
#include "base/files/file_path.h"
#include "base/sequence_checker.h"
#include "base/thread_annotations.h"
#include "base/types/expected.h"
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
#include "components/os_crypt/async/common/encryptor.h"
#include "components/user_annotations/user_annotations_service.h"
#include "components/user_annotations/user_annotations_types.h"
#include "sql/database.h"
#include "sql/init_status.h"
namespace user_annotations {
// Wraps the SQLite database that provides on-disk storage for user annotation
// entries. This class is expected to be created and accessed on a backend
// sequence.
class UserAnnotationsDatabase {
public:
// `storage_dir` will generally be the Profile directory where the DB will be
// opened from, or created if not exists.
UserAnnotationsDatabase(const base::FilePath& storage_dir,
os_crypt_async::Encryptor encryptor);
UserAnnotationsDatabase(const UserAnnotationsDatabase&) = delete;
UserAnnotationsDatabase& operator=(const UserAnnotationsDatabase&) = delete;
~UserAnnotationsDatabase();
// Updates the database and returns whether it succeeded. `upserted_entries`
// contains entries that are new or updated. `deleted_entry_ids` contains the
// entry IDs to be deleted.
UserAnnotationsExecutionResult UpdateEntries(
const UserAnnotationsEntries& upserted_entries,
const std::set<EntryID>& deleted_entry_ids);
// Returns all the annotations from database.
UserAnnotationsEntryRetrievalResult RetrieveAllEntries();
// Remove the user annotation entry with `entry_id` and returns whether the
// operation completed successfully. Returns true even when no entry is found.
bool RemoveEntry(EntryID entry_id);
// Removes all the user annotation entries and returns whether the
// operation completed successfully. Returns true even when there are no
// entries to delete.
bool RemoveAllEntries();
// Removes the user annotation entries that were last modified from
// `delete_begin` to `delete_end`.
void RemoveAnnotationsInRange(const base::Time& delete_begin,
const base::Time& delete_end);
// Returns the number of unique user annotations that were last modified
// between [`begin`, `end`).
int GetCountOfValuesContainedBetween(base::Time begin, base::Time end);
private:
sql::InitStatus InitInternal(const base::FilePath& storage_dir);
// The underlying SQL database.
sql::Database db_ GUARDED_BY_CONTEXT(sequence_checker_) =
sql::Database(sql::DatabaseOptions{}, /*tag=*/"UserAnnotations");
os_crypt_async::Encryptor encryptor_ GUARDED_BY_CONTEXT(sequence_checker_);
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace user_annotations
#endif // COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_DATABASE_H_

@ -1,261 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/user_annotations_database.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/protobuf_matchers.h"
#include "base/test/task_environment.h"
#include "components/os_crypt/async/browser/test_utils.h"
#include "components/user_annotations/user_annotations_features.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace user_annotations {
using ::base::test::EqualsProto;
using ::optimization_guide::proto::UserAnnotationsEntry;
using ::testing::UnorderedElementsAre;
UserAnnotationsEntry CreateUserAnnotationsEntry(const std::string& key,
const std::string& value) {
UserAnnotationsEntry entry;
entry.set_key(key);
entry.set_value(value);
return entry;
}
class UserAnnotationsDatabaseTest : public testing::Test {
public:
void SetUp() override {
CHECK(temp_dir_.CreateUniqueTempDir());
os_crypt_ = os_crypt_async::GetTestOSCryptAsyncForTesting(
/*is_sync_for_unittests=*/true);
CreateDatabase();
}
void TearDown() override {
database_.reset();
CHECK(temp_dir_.Delete());
}
void CreateDatabase() {
base::RunLoop run_loop;
on_database_created_closure_ = run_loop.QuitClosure();
encryptor_ready_subscription_ = os_crypt_->GetInstance(
base::BindOnce(&UserAnnotationsDatabaseTest::CreateDatabaseOnCryptReady,
base::Unretained(this)));
run_loop.Run();
}
protected:
void CreateDatabaseOnCryptReady(os_crypt_async::Encryptor encryptor,
bool success) {
ASSERT_TRUE(success);
database_ = std::make_unique<UserAnnotationsDatabase>(temp_dir_.GetPath(),
std::move(encryptor));
std::move(on_database_created_closure_).Run();
}
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::ScopedTempDir temp_dir_;
std::unique_ptr<os_crypt_async::OSCryptAsync> os_crypt_;
base::CallbackListSubscription encryptor_ready_subscription_;
std::unique_ptr<UserAnnotationsDatabase> database_;
base::OnceClosure on_database_created_closure_;
};
TEST_F(UserAnnotationsDatabaseTest, StoreAndRetrieve) {
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
std::vector<UserAnnotationsEntry> entries;
entries.push_back(CreateUserAnnotationsEntry("foo", "foo_value"));
entries.push_back(CreateUserAnnotationsEntry("bar", "bar_value"));
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries(entries, /*deleted_entry_ids=*/{}));
entries[0].set_entry_id(1);
entries[1].set_entry_id(2);
EXPECT_THAT(
*database_->RetrieveAllEntries(),
UnorderedElementsAre(EqualsProto(entries[0]), EqualsProto(entries[1])));
// Reopen the database, and it should have the entries.
database_.reset();
CreateDatabase();
EXPECT_THAT(
*database_->RetrieveAllEntries(),
UnorderedElementsAre(EqualsProto(entries[0]), EqualsProto(entries[1])));
}
TEST_F(UserAnnotationsDatabaseTest, EntriesNewAndChanged) {
std::vector<UserAnnotationsEntry> entries;
entries.push_back(CreateUserAnnotationsEntry("foo", "foo_value"));
entries.push_back(CreateUserAnnotationsEntry("bar", "bar_value"));
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries(entries, /*deleted_entry_ids=*/{}));
entries[0].set_entry_id(1);
entries[1].set_entry_id(2);
EXPECT_EQ(2U, database_->RetrieveAllEntries()->size());
// Add new entry, and change foo.
auto bazEntry = (CreateUserAnnotationsEntry("baz", "baz_value"));
entries[0].set_value("new_foo_value");
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({entries[0], bazEntry},
/*deleted_entry_ids=*/{}));
bazEntry.set_entry_id(3);
EXPECT_THAT(
*database_->RetrieveAllEntries(),
UnorderedElementsAre(EqualsProto(entries[0]), EqualsProto(entries[1]),
EqualsProto(bazEntry)));
}
TEST_F(UserAnnotationsDatabaseTest, EntriesChangedAndDeleted) {
std::vector<UserAnnotationsEntry> entries;
entries.push_back(CreateUserAnnotationsEntry("foo", "foo_value"));
entries.push_back(CreateUserAnnotationsEntry("bar", "bar_value"));
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries(entries, /*deleted_entry_ids=*/{}));
entries[0].set_entry_id(1);
entries[1].set_entry_id(2);
EXPECT_EQ(2U, database_->RetrieveAllEntries()->size());
// Change foo, and delete bar.
entries[0].set_value("new_foo_value");
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({entries[0]}, /*deleted_entry_ids=*/{2}));
EXPECT_THAT(*database_->RetrieveAllEntries(),
UnorderedElementsAre(EqualsProto(entries[0])));
// Delete foo.
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({}, /*deleted_entry_ids=*/{1}));
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
}
TEST_F(UserAnnotationsDatabaseTest, RemoveEntry) {
std::vector<UserAnnotationsEntry> entries;
entries.push_back(CreateUserAnnotationsEntry("foo", "foo_value"));
entries.push_back(CreateUserAnnotationsEntry("bar", "bar_value"));
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries(entries, /*deleted_entry_ids=*/{}));
entries[0].set_entry_id(1);
entries[1].set_entry_id(2);
auto db_entries = *database_->RetrieveAllEntries();
EXPECT_EQ(2U, db_entries.size());
EXPECT_TRUE(database_->RemoveEntry(db_entries[0].entry_id()));
EXPECT_TRUE(database_->RemoveEntry(db_entries[1].entry_id()));
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
}
TEST_F(UserAnnotationsDatabaseTest, RemoveAllEntries) {
std::vector<UserAnnotationsEntry> entries;
entries.push_back(CreateUserAnnotationsEntry("foo", "foo_value"));
entries.push_back(CreateUserAnnotationsEntry("bar", "bar_value"));
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries(entries, /*deleted_entry_ids=*/{}));
EXPECT_TRUE(database_->RemoveAllEntries());
EXPECT_TRUE(database_->RemoveAllEntries());
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
}
TEST_F(UserAnnotationsDatabaseTest, RemoveAllAnnotationsInRange) {
auto foo_entry = CreateUserAnnotationsEntry("foo", "foo_value");
auto bar_entry = CreateUserAnnotationsEntry("bar", "bar_value");
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({foo_entry}, /*deleted_entry_ids=*/{}));
task_environment_.FastForwardBy(base::Hours(1));
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({bar_entry}, /*deleted_entry_ids=*/{}));
EXPECT_EQ(2u, database_->RetrieveAllEntries()->size());
// Delete all.
database_->RemoveAnnotationsInRange(base::Time::Min(), base::Time::Max());
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
}
TEST_F(UserAnnotationsDatabaseTest, RemoveAnnotationsInRange) {
auto foo_entry = CreateUserAnnotationsEntry("foo", "foo_value");
auto bar_entry = CreateUserAnnotationsEntry("bar", "bar_value");
auto foo_create_time = base::Time::Now();
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({foo_entry}, /*deleted_entry_ids=*/{}));
task_environment_.FastForwardBy(base::Hours(1));
auto bar_create_time = base::Time::Now();
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({bar_entry}, /*deleted_entry_ids=*/{}));
EXPECT_EQ(2u, database_->RetrieveAllEntries()->size());
// Delete foo.
database_->RemoveAnnotationsInRange(foo_create_time - base::Seconds(1),
foo_create_time + base::Seconds(1));
bar_entry.set_entry_id(2);
EXPECT_THAT(*database_->RetrieveAllEntries(),
UnorderedElementsAre(EqualsProto(bar_entry)));
// Delete bar.
database_->RemoveAnnotationsInRange(bar_create_time - base::Seconds(1),
bar_create_time + base::Seconds(1));
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
}
TEST_F(UserAnnotationsDatabaseTest, RemoveAnnotationsInRangeBackward) {
auto foo_entry = CreateUserAnnotationsEntry("foo", "foo_value");
auto bar_entry = CreateUserAnnotationsEntry("bar", "bar_value");
auto foo_create_time = base::Time::Now();
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({foo_entry}, /*deleted_entry_ids=*/{}));
task_environment_.FastForwardBy(base::Hours(1));
auto bar_create_time = base::Time::Now();
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({bar_entry}, /*deleted_entry_ids=*/{}));
EXPECT_EQ(2u, database_->RetrieveAllEntries()->size());
// Delete bar.
database_->RemoveAnnotationsInRange(bar_create_time - base::Seconds(1),
bar_create_time + base::Seconds(1));
foo_entry.set_entry_id(1);
EXPECT_THAT(*database_->RetrieveAllEntries(),
UnorderedElementsAre(EqualsProto(foo_entry)));
// Delete foo.
database_->RemoveAnnotationsInRange(foo_create_time - base::Seconds(1),
foo_create_time + base::Seconds(1));
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
}
TEST_F(UserAnnotationsDatabaseTest, GetCountOfValuesContainedBetween) {
auto foo_entry = CreateUserAnnotationsEntry("foo", "foo_value");
auto bar_entry = CreateUserAnnotationsEntry("bar", "bar_value");
auto foo_create_time = base::Time::Now();
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({foo_entry}, /*deleted_entry_ids=*/{}));
task_environment_.FastForwardBy(base::Hours(1));
auto bar_create_time = base::Time::Now();
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
database_->UpdateEntries({bar_entry}, /*deleted_entry_ids=*/{}));
EXPECT_EQ(2u, database_->RetrieveAllEntries()->size());
// One entry: bar.
int count = database_->GetCountOfValuesContainedBetween(
bar_create_time - base::Seconds(1), bar_create_time + base::Seconds(1));
EXPECT_EQ(1, count);
// One entry: foo.
count = database_->GetCountOfValuesContainedBetween(
foo_create_time - base::Seconds(1), foo_create_time + base::Seconds(1));
EXPECT_EQ(1, count);
// All.
count = database_->GetCountOfValuesContainedBetween(base::Time::Min(),
base::Time::Max());
EXPECT_EQ(2, count);
}
} // namespace user_annotations

@ -1,37 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/user_annotations_features.h"
#include "base/feature_list.h"
#include "base/strings/string_split.h"
#include "components/autofill_ai/core/browser/autofill_ai_features.h"
namespace user_annotations {
bool IsUserAnnotationsEnabled() {
return base::FeatureList::IsEnabled(autofill_ai::kAutofillAi);
}
std::vector<std::string> GetAllowedHostsForFormsAnnotations() {
std::string allowed_hosts_string = base::GetFieldTrialParamValueByFeature(
autofill_ai::kAutofillAi, "allowed_hosts_for_form_submissions");
return base::SplitString(allowed_hosts_string, ",",
base::WhitespaceHandling::TRIM_WHITESPACE,
base::SplitResult::SPLIT_WANT_NONEMPTY);
}
bool ShouldExtractAXTreeForFormsAnnotations() {
return base::GetFieldTrialParamByFeatureAsBool(
autofill_ai::kAutofillAi, "should_extract_ax_tree_for_forms_annotations",
false);
}
base::TimeDelta GetFormSubmissionCompletionTimeout() {
return base::GetFieldTrialParamByFeatureAsTimeDelta(
autofill_ai::kAutofillAi, "form_submission_completion_timeout",
base::Seconds(30));
}
} // namespace user_annotations

@ -1,29 +0,0 @@
// Copyright 2024 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_USER_ANNOTATIONS_USER_ANNOTATIONS_FEATURES_H_
#define COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_FEATURES_H_
#include <string>
#include <vector>
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
namespace user_annotations {
// Whether the user annotations feature is enabled.
bool IsUserAnnotationsEnabled();
// Returns the set of hosts that are allowed for forms annotations.
std::vector<std::string> GetAllowedHostsForFormsAnnotations();
bool ShouldExtractAXTreeForFormsAnnotations();
// Returns the completion timeout for the entirety of forms submission stages.
base::TimeDelta GetFormSubmissionCompletionTimeout();
} // namespace user_annotations
#endif // COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_FEATURES_H_

@ -1,28 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/user_annotations_features.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill_ai/core/browser/autofill_ai_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace user_annotations {
namespace {
using ::testing::UnorderedElementsAre;
TEST(UserAnnotationsFeaturesTest, GetAllowedHostsForFormsAnnotations) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeatureWithParameters(
autofill_ai::kAutofillAi,
{{"allowed_hosts_for_form_submissions", "example.com,otherhost.com"}});
EXPECT_THAT(GetAllowedHostsForFormsAnnotations(),
UnorderedElementsAre("example.com", "otherhost.com"));
}
} // namespace
} // namespace user_annotations

@ -1,346 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/user_annotations_service.h"
#include "base/callback_list.h"
#include "base/containers/contains.h"
#include "base/containers/fixed_flat_map.h"
#include "base/functional/callback.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/types/expected.h"
#include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_processing/optimization_guide_proto_util.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/geo/phone_number_i18n.h"
#include "components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.h"
#include "components/optimization_guide/core/optimization_guide_decider.h"
#include "components/optimization_guide/core/optimization_guide_model_executor.h"
#include "components/optimization_guide/core/optimization_guide_proto_util.h"
#include "components/optimization_guide/core/optimization_guide_util.h"
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
#include "components/optimization_guide/proto/features/forms_annotations.pb.h"
#include "components/os_crypt/async/browser/os_crypt_async.h"
#include "components/os_crypt/async/common/encryptor.h"
#include "components/user_annotations/form_submission_handler.h"
#include "components/user_annotations/user_annotations_database.h"
#include "components/user_annotations/user_annotations_features.h"
#include "components/user_annotations/user_annotations_switches.h"
#include "components/user_annotations/user_annotations_types.h"
namespace user_annotations {
namespace {
base::flat_map<autofill::FieldType, std::string>
GetEntryKeyByAutofillFieldType() {
return {
{autofill::FieldType::NAME_FIRST, "First Name"},
{autofill::FieldType::NAME_MIDDLE, "Middle Name"},
{autofill::FieldType::NAME_LAST, "Last Name"},
{autofill::FieldType::EMAIL_ADDRESS, "Email Address"},
{autofill::FieldType::PHONE_HOME_WHOLE_NUMBER, "Phone Number [mobile]"},
{autofill::FieldType::ADDRESS_HOME_CITY, "Address - City"},
{autofill::FieldType::ADDRESS_HOME_STATE, "Address - State"},
{autofill::FieldType::ADDRESS_HOME_ZIP, "Address - Zip Code"},
{autofill::FieldType::ADDRESS_HOME_COUNTRY, "Address - Country"},
{autofill::FieldType::ADDRESS_HOME_STREET_ADDRESS, "Address - Street"},
};
}
void RecordUserAnnotationsFormImportResult(
UserAnnotationsExecutionResult result) {
base::UmaHistogramEnumeration("UserAnnotations.FormImportResult", result);
}
void RecordMemoryCountEntriesResult(int result) {
base::UmaHistogramCounts1000("UserAnnotations.EntryCount", result);
}
void ProcessEntryRetrieval(
base::OnceCallback<void(UserAnnotationsEntries)> callback,
UserAnnotationsEntryRetrievalResult user_annotations) {
RecordMemoryCountEntriesResult(user_annotations->size());
if (!user_annotations.has_value()) {
std::move(callback).Run({});
return;
}
std::move(callback).Run(std::move(user_annotations).value());
}
void RecordRemoveEntryResult(UserAnnotationsExecutionResult result) {
base::UmaHistogramEnumeration("UserAnnotations.RemoveEntry.Result", result);
}
void RecordRemoveAllEntriesResult(UserAnnotationsExecutionResult result) {
base::UmaHistogramEnumeration("UserAnnotations.RemoveAllEntries.Result",
result);
}
void RecordCountEntriesResult(UserAnnotationsExecutionResult result) {
base::UmaHistogramEnumeration("UserAnnotations.CountEntries.Result", result);
}
std::string GetEntryValueFromAutofillProfile(
const autofill::AutofillProfile& autofill_profile,
autofill::FieldType field_type) {
if (field_type == autofill::FieldType::PHONE_HOME_WHOLE_NUMBER) {
return autofill::i18n::FormatPhoneForDisplay(
base::UTF16ToUTF8(autofill_profile.GetRawInfo(field_type)),
base::UTF16ToUTF8(
autofill_profile.GetRawInfo(autofill::PHONE_HOME_COUNTRY_CODE)));
}
return base::UTF16ToUTF8(autofill_profile.GetRawInfo(field_type));
}
UserAnnotationsEntries ConvertAutofillProfileToEntries(
const autofill::AutofillProfile& autofill_profile) {
static const base::flat_map<autofill::FieldType, std::string>
entry_key_by_autofill_field_type = GetEntryKeyByAutofillFieldType();
UserAnnotationsEntries entries;
for (const auto& [field_type, entry_key] : entry_key_by_autofill_field_type) {
const std::string entry_value =
GetEntryValueFromAutofillProfile(autofill_profile, field_type);
if (entry_value.empty()) {
continue;
}
optimization_guide::proto::UserAnnotationsEntry entry_proto;
entry_proto.set_key(entry_key);
entry_proto.set_value(std::move(entry_value));
entries.emplace_back(std::move(entry_proto));
}
return entries;
}
void NotifyAutofillProfileSaved(
base::OnceCallback<void(UserAnnotationsExecutionResult)> callback,
UserAnnotationsExecutionResult result) {
std::move(callback).Run(result);
}
} // namespace
UserAnnotationsService::UserAnnotationsService(
optimization_guide::OptimizationGuideModelExecutor* model_executor,
optimization_guide::ModelQualityLogsUploaderService* logs_uploader,
const base::FilePath& storage_dir,
os_crypt_async::OSCryptAsync* os_crypt_async,
optimization_guide::OptimizationGuideDecider* optimization_guide_decider)
: model_executor_(model_executor),
logs_uploader_(logs_uploader->GetWeakPtr()),
optimization_guide_decider_(optimization_guide_decider),
allowed_hosts_for_forms_annotations_(
GetAllowedHostsForFormsAnnotations()) {
encryptor_ready_subscription_ = os_crypt_async->GetInstance(
base::BindOnce(&UserAnnotationsService::OnOsCryptAsyncReady,
weak_ptr_factory_.GetWeakPtr(), storage_dir));
if (optimization_guide_decider_) {
optimization_guide_decider_->RegisterOptimizationTypes(
{optimization_guide::proto::FORMS_ANNOTATIONS});
}
}
UserAnnotationsService::UserAnnotationsService() = default;
UserAnnotationsService::~UserAnnotationsService() = default;
bool UserAnnotationsService::ShouldAddFormSubmissionForURL(const GURL& url) {
if (base::Contains(allowed_hosts_for_forms_annotations_, url.host())) {
return true;
}
// Only allow HTTPS sites.
if (!url.SchemeIs("https")) {
return false;
}
// Fall back to optimization guide if not in override list.
if (optimization_guide_decider_) {
optimization_guide::OptimizationGuideDecision decision =
optimization_guide_decider_->CanApplyOptimization(
url, optimization_guide::proto::FORMS_ANNOTATIONS,
/*metadata=*/nullptr);
return decision == optimization_guide::OptimizationGuideDecision::kTrue;
}
return false;
}
void UserAnnotationsService::AddFormSubmission(
const GURL& url,
const std::string& title,
optimization_guide::proto::AXTreeUpdate ax_tree_update,
std::unique_ptr<autofill::FormStructure> form,
ImportFormCallback callback) {
// `form` is assumed to never be `nullptr`.
CHECK(form);
pending_form_submissions_.emplace(std::make_unique<FormSubmissionHandler>(
this, url, title, std::move(ax_tree_update), std::move(form),
std::move(callback)));
if (pending_form_submissions_.size() != 1) {
return;
}
ProcessNextFormSubmission();
}
void UserAnnotationsService::RetrieveAllEntries(
base::OnceCallback<void(UserAnnotationsEntries)> callback) {
if (!user_annotations_database_) {
// TODO: b/361696651 - Record the failure.
return;
}
user_annotations_database_
.AsyncCall(&UserAnnotationsDatabase::RetrieveAllEntries)
.Then(base::BindOnce(ProcessEntryRetrieval, std::move(callback)));
}
void UserAnnotationsService::OnOsCryptAsyncReady(
const base::FilePath& storage_dir,
os_crypt_async::Encryptor encryptor,
bool success) {
if (!success) {
// TODO: b/361696651 - Record the failure.
return;
}
user_annotations_database_ = base::SequenceBound<UserAnnotationsDatabase>(
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_BLOCKING,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
storage_dir, std::move(encryptor));
if (auto manual_entries = switches::ParseFormsAnnotationsFromCommandLine()) {
RemoveAllEntries(base::BindOnce(
&UserAnnotationsService::InitializeFormsAnnotationsFromCommandLine,
weak_ptr_factory_.GetWeakPtr(), *manual_entries));
}
}
void UserAnnotationsService::InitializeFormsAnnotationsFromCommandLine(
const optimization_guide::proto::FormsAnnotationsResponse& manual_entries) {
SaveEntries(manual_entries);
}
void UserAnnotationsService::Shutdown() {}
bool UserAnnotationsService::IsDatabaseReady() {
return !!user_annotations_database_;
}
void UserAnnotationsService::SaveEntries(
const optimization_guide::proto::FormsAnnotationsResponse& entries) {
DCHECK(user_annotations_database_);
UserAnnotationsEntries upserted_entries = UserAnnotationsEntries(
entries.upserted_entries().begin(), entries.upserted_entries().end());
std::set<EntryID> deleted_entry_ids(entries.deleted_entry_ids().begin(),
entries.deleted_entry_ids().end());
user_annotations_database_.AsyncCall(&UserAnnotationsDatabase::UpdateEntries)
.WithArgs(upserted_entries, deleted_entry_ids)
.Then(base::BindOnce(RecordUserAnnotationsFormImportResult));
}
void UserAnnotationsService::SaveAutofillProfile(
const autofill::AutofillProfile& autofill_profile,
base::OnceCallback<void(UserAnnotationsExecutionResult)> callback) {
const UserAnnotationsEntries entries =
ConvertAutofillProfileToEntries(autofill_profile);
DCHECK(user_annotations_database_);
user_annotations_database_.AsyncCall(&UserAnnotationsDatabase::UpdateEntries)
.WithArgs(entries, std::set<EntryID>{})
.Then(base::BindOnce(NotifyAutofillProfileSaved, std::move(callback)));
}
void UserAnnotationsService::OnFormSubmissionComplete() {
pending_form_submissions_.pop();
ProcessNextFormSubmission();
}
void UserAnnotationsService::ProcessNextFormSubmission() {
if (pending_form_submissions_.empty()) {
return;
}
pending_form_submissions_.front()->Start();
}
void UserAnnotationsService::RemoveEntry(EntryID entry_id,
base::OnceClosure callback) {
if (!user_annotations_database_) {
RecordRemoveEntryResult(
UserAnnotationsExecutionResult::kCryptNotInitialized);
std::move(callback).Run();
return;
}
user_annotations_database_.AsyncCall(&UserAnnotationsDatabase::RemoveEntry)
.WithArgs(entry_id)
.Then(base::BindOnce(
[](base::OnceClosure callback, bool result) {
RecordRemoveEntryResult(
result ? UserAnnotationsExecutionResult::kSuccess
: UserAnnotationsExecutionResult::kSqlError);
std::move(callback).Run();
},
std::move(callback)));
}
void UserAnnotationsService::RemoveAllEntries(base::OnceClosure callback) {
if (!user_annotations_database_) {
RecordRemoveAllEntriesResult(
UserAnnotationsExecutionResult::kCryptNotInitialized);
std::move(callback).Run();
return;
}
user_annotations_database_
.AsyncCall(&UserAnnotationsDatabase::RemoveAllEntries)
.Then(base::BindOnce(
[](base::OnceClosure callback, bool result) {
RecordRemoveAllEntriesResult(
result ? UserAnnotationsExecutionResult::kSuccess
: UserAnnotationsExecutionResult::kSqlError);
std::move(callback).Run();
},
std::move(callback)));
}
void UserAnnotationsService::RemoveAnnotationsInRange(
const base::Time& delete_begin,
const base::Time& delete_end) {
if (!user_annotations_database_) {
return;
}
user_annotations_database_
.AsyncCall(&UserAnnotationsDatabase::RemoveAnnotationsInRange)
.WithArgs(delete_begin, delete_end);
}
void UserAnnotationsService::GetCountOfValuesContainedBetween(
base::Time begin,
base::Time end,
base::OnceCallback<void(int)> callback) {
if (!user_annotations_database_) {
RecordCountEntriesResult(
UserAnnotationsExecutionResult::kCryptNotInitialized);
std::move(callback).Run(0);
return;
}
user_annotations_database_
.AsyncCall(&UserAnnotationsDatabase::GetCountOfValuesContainedBetween)
.WithArgs(begin, end)
.Then(base::BindOnce(
[](base::OnceCallback<void(int)> callback, int result) {
RecordCountEntriesResult(
result ? UserAnnotationsExecutionResult::kSuccess
: UserAnnotationsExecutionResult::kSqlError);
std::move(callback).Run(result);
},
std::move(callback)));
}
} // namespace user_annotations

@ -1,187 +0,0 @@
// Copyright 2024 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_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_H_
#define COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_H_
#include <memory>
#include <queue>
#include <string>
#include <vector>
#include "base/callback_list.h"
#include "base/containers/queue.h"
#include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/sequence_bound.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/optimization_guide/core/optimization_guide_model_executor.h"
#include "components/user_annotations/user_annotations_types.h"
#include "url/gurl.h"
namespace autofill {
class AutofillProfile;
class FormStructure;
} // namespace autofill
namespace optimization_guide {
class OptimizationGuideDecider;
namespace proto {
class AXTreeUpdate;
} // namespace proto
} // namespace optimization_guide
namespace os_crypt_async {
class Encryptor;
class OSCryptAsync;
} // namespace os_crypt_async
namespace user_annotations {
class FormSubmissionHandler;
class UserAnnotationsDatabase;
class UserAnnotationsService : public KeyedService {
public:
UserAnnotationsService(
optimization_guide::OptimizationGuideModelExecutor* model_executor,
optimization_guide::ModelQualityLogsUploaderService* logs_uploader,
const base::FilePath& storage_dir,
os_crypt_async::OSCryptAsync* os_crypt_async,
optimization_guide::OptimizationGuideDecider* optimization_guide_decider);
UserAnnotationsService(const UserAnnotationsService&) = delete;
UserAnnotationsService& operator=(const UserAnnotationsService&) = delete;
~UserAnnotationsService() override;
// Whether the form submission for `url` should be added to user annotations.
// Virtual for testing.
virtual bool ShouldAddFormSubmissionForURL(const GURL& url);
// Adds a form submission to the user annotations. Calls `callback` according
// to the outcome of the import process. The `callback` will notify Autofill
// code about the import attempt so they can show a save prompt to the user.
// When the prompt is closed, the inner `prompt_acceptance_callback` will
// notify `this` about the user's decision. `form` is assumed to never be
// `nullptr`. Virtual for testing.
virtual void AddFormSubmission(
const GURL& url,
const std::string& title,
optimization_guide::proto::AXTreeUpdate ax_tree_update,
std::unique_ptr<autofill::FormStructure> form,
ImportFormCallback callback);
// Retrieves all entries from the database. Invokes `callback` when complete.
// Virtual for testing.
virtual void RetrieveAllEntries(
base::OnceCallback<void(UserAnnotationsEntries)> callback);
// Remove the user annotation entry with `entry_id` and calls `callback` upon
// completion.
// Virtual for testing.
virtual void RemoveEntry(EntryID entry_id, base::OnceClosure callback);
// Removes all the user annotation entries and calls `callback` upon
// completion.
// Virtual for testing.
virtual void RemoveAllEntries(base::OnceClosure callback);
// Removes the user annotation entries that were last modified from
// `delete_begin` to `delete_end`.
// Virtual for testing.
virtual void RemoveAnnotationsInRange(const base::Time& delete_begin,
const base::Time& delete_end);
// Returns the number of unique user annotations that were last modified
// between [`begin`, `end`).
// Virtual for testing.
virtual void GetCountOfValuesContainedBetween(
base::Time begin,
base::Time end,
base::OnceCallback<void(int)> callback);
// KeyedService:
void Shutdown() override;
// Saves `autofill_profile` to the database, then runs `callback`.
virtual void SaveAutofillProfile(
const autofill::AutofillProfile& autofill_profile,
base::OnceCallback<void(UserAnnotationsExecutionResult)> callback);
private:
friend class TestUserAnnotationsService;
friend class FormSubmissionHandler;
// Used in testing, to construct the service without encryptor and database.
UserAnnotationsService();
// Called when the encryptor is ready.
void OnOsCryptAsyncReady(const base::FilePath& storage_dir,
os_crypt_async::Encryptor encryptor,
bool success);
void InitializeFormsAnnotationsFromCommandLine(
const optimization_guide::proto::FormsAnnotationsResponse&
manual_entries);
// Returns whether the database initialization is complete.
bool IsDatabaseReady();
// Starts the processing of next pending form submission.
void ProcessNextFormSubmission();
// Saves the entries to database.
void SaveEntries(
const optimization_guide::proto::FormsAnnotationsResponse& entries);
// Called when the form submission is fully complete.
void OnFormSubmissionComplete();
optimization_guide::OptimizationGuideModelExecutor* model_executor() {
return model_executor_;
}
base::WeakPtr<optimization_guide::ModelQualityLogsUploaderService>
logs_uploader() {
return logs_uploader_;
}
// Database used to persist the user annotation entries.
base::SequenceBound<UserAnnotationsDatabase> user_annotations_database_;
// Maintains the subscription for `OSCryptAsync` and cancels upon destruction.
base::CallbackListSubscription encryptor_ready_subscription_;
// The model executor to use to normalize entries. Guaranteed to outlive
// `this`.
raw_ptr<optimization_guide::OptimizationGuideModelExecutor> model_executor_;
// The service used to upload model quality logs.
base::WeakPtr<optimization_guide::ModelQualityLogsUploaderService>
logs_uploader_;
// The optimization guide decider to determine whether to generate user
// annotations for a page. Guaranteed to outlive `this`.
raw_ptr<optimization_guide::OptimizationGuideDecider>
optimization_guide_decider_;
// The override list for allowed hosts for forms annotations.
// TODO: b/361692317 - Remove this once optimization guide actually populates
// list.
const std::vector<std::string> allowed_hosts_for_forms_annotations_;
// The queue of form submissions pending to be processed. Each form submission
// goes through multiple stages of processing, and until then the form
// submissions will wait in this queue. The first entry is the one that is
// currently being processed.
base::queue<std::unique_ptr<FormSubmissionHandler>> pending_form_submissions_;
base::WeakPtrFactory<UserAnnotationsService> weak_ptr_factory_{this};
};
} // namespace user_annotations
#endif // COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_H_

@ -1,570 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/user_annotations_service.h"
#include <memory>
#include "base/base64.h"
#include "base/command_line.h"
#include "base/files/scoped_temp_dir.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/gmock_move_support.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/protobuf_matchers.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "components/autofill/core/browser/country_type.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill_ai/core/browser/autofill_ai_features.h"
#include "components/optimization_guide/core/mock_optimization_guide_model_executor.h"
#include "components/optimization_guide/core/model_execution/model_execution_prefs.h"
#include "components/optimization_guide/core/model_quality/test_model_quality_logs_uploader_service.h"
#include "components/optimization_guide/core/optimization_guide_proto_util.h"
#include "components/optimization_guide/core/test_optimization_guide_decider.h"
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
#include "components/os_crypt/async/browser/os_crypt_async.h"
#include "components/os_crypt/async/browser/test_utils.h"
#include "components/prefs/testing_pref_service.h"
#include "components/user_annotations/user_annotations_switches.h"
#include "components/user_annotations/user_annotations_types.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace user_annotations {
namespace {
using ::base::test::EqualsProto;
using ::testing::_;
using ::testing::An;
using ::testing::IsEmpty;
class TestOptimizationGuideDecider
: public optimization_guide::TestOptimizationGuideDecider {
public:
optimization_guide::OptimizationGuideDecision CanApplyOptimization(
const GURL& url,
optimization_guide::proto::OptimizationType optimization_type,
optimization_guide::OptimizationMetadata* optimization_metadata)
override {
CHECK_EQ(optimization_type, optimization_guide::proto::FORMS_ANNOTATIONS);
if (url.host() == "allowed.com") {
return optimization_guide::OptimizationGuideDecision::kTrue;
}
return optimization_guide::OptimizationGuideDecision::kFalse;
}
};
class UserAnnotationsServiceTest : public testing::Test {
public:
void SetUp() override {
InitializeFeatureList();
CHECK(temp_dir_.CreateUniqueTempDir());
optimization_guide::model_execution::prefs::RegisterLocalStatePrefs(
local_state_.registry());
os_crypt_ = os_crypt_async::GetTestOSCryptAsyncForTesting(
/*is_sync_for_unittests=*/true);
optimization_guide_decider_ =
std::make_unique<TestOptimizationGuideDecider>();
logs_service_ = std::make_unique<
optimization_guide::TestModelQualityLogsUploaderService>(&local_state_);
service_ = std::make_unique<UserAnnotationsService>(
&model_executor_, logs_service_.get(), temp_dir_.GetPath(), os_crypt_.get(),
optimization_guide_decider_.get());
}
virtual void InitializeFeatureList() {
scoped_feature_list_.InitAndEnableFeature(autofill_ai::kAutofillAi);
}
UserAnnotationsEntries AddAndImportFormSubmission(
optimization_guide::proto::AXTreeUpdate ax_tree_update,
const autofill::FormData& form_data) {
UserAnnotationsEntries entries;
std::unique_ptr<autofill::FormStructure> form =
std::make_unique<autofill::FormStructure>(form_data);
service()->AddFormSubmission(
GURL("example.com"), "title", ax_tree_update, std::move(form),
base::BindLambdaForTesting(
[&entries](std::unique_ptr<autofill::FormStructure> form,
std::unique_ptr<user_annotations::FormAnnotationResponse>
form_annotation_response,
PromptAcceptanceCallback prompt_acceptance_callback) {
if (form_annotation_response) {
entries = form_annotation_response->to_be_upserted_entries;
}
std::move(prompt_acceptance_callback)
.Run({/*prompt_was_accepted=*/true,
/*did_user_interact=*/true});
}));
task_environment_.RunUntilIdle();
return entries;
}
UserAnnotationsEntries GetAllUserAnnotationsEntries() {
base::test::TestFuture<UserAnnotationsEntries> test_future;
service()->RetrieveAllEntries(test_future.GetCallback());
return test_future.Take();
}
UserAnnotationsService* service() { return service_.get(); }
optimization_guide::MockOptimizationGuideModelExecutor* model_executor() {
return &model_executor_;
}
TestOptimizationGuideDecider* optimization_guide_decider() {
return optimization_guide_decider_.get();
}
optimization_guide::TestModelQualityLogsUploaderService* logs_service() {
return logs_service_.get();
}
std::unique_ptr<optimization_guide::ModelQualityLogEntry> CreateLogEntry() {
return std::make_unique<optimization_guide::ModelQualityLogEntry>(
logs_service_->GetWeakPtr());
}
protected:
base::test::ScopedFeatureList scoped_feature_list_;
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::ScopedTempDir temp_dir_;
TestingPrefServiceSimple local_state_;
std::unique_ptr<optimization_guide::TestModelQualityLogsUploaderService>
logs_service_;
testing::NiceMock<optimization_guide::MockOptimizationGuideModelExecutor>
model_executor_;
std::unique_ptr<os_crypt_async::OSCryptAsync> os_crypt_;
std::unique_ptr<TestOptimizationGuideDecider> optimization_guide_decider_;
std::unique_ptr<UserAnnotationsService> service_;
};
TEST_F(UserAnnotationsServiceTest, FormsAnnotationsTypeRegistered) {
EXPECT_TRUE(base::Contains(
optimization_guide_decider()->registered_optimization_types(),
optimization_guide::proto::FORMS_ANNOTATIONS));
}
TEST_F(UserAnnotationsServiceTest, ShouldAddFormSubmissionForURL) {
EXPECT_FALSE(service()->ShouldAddFormSubmissionForURL(
GURL("https://notallowed.com/whatever")));
EXPECT_TRUE(service()->ShouldAddFormSubmissionForURL(
GURL("https://allowed.com/whatever")));
// Allowed host but not HTTPS.
EXPECT_FALSE(service()->ShouldAddFormSubmissionForURL(
GURL("http://allowed.com/whatever")));
}
TEST_F(UserAnnotationsServiceTest, RetrieveAllEntriesNoDB) {
base::HistogramTester histogram_tester;
auto entries = GetAllUserAnnotationsEntries();
histogram_tester.ExpectUniqueSample("UserAnnotations.EntryCount", 0, 1);
EXPECT_TRUE(entries.empty());
}
struct FormsAnnotationsTestRequest {
optimization_guide::proto::Any forms_annotations_response;
optimization_guide::proto::AXTreeUpdate ax_tree;
autofill::FormData form_data;
GURL url;
std::string title;
};
struct Entry {
size_t entry_id;
std::string key;
std::string value;
};
// Returns sample annotations for tests.
FormsAnnotationsTestRequest CreateSampleFormsAnnotationsTestRequest(
const std::vector<std::vector<std::u16string>>& request_entries =
{
{u"label", u"", u"whatever"},
{u"", u"nolabel", u"value"},
},
const std::vector<Entry>& response_upserted_entries = {
{0, "label", "whatever"},
{0, "nolabel", "value"},
}) {
optimization_guide::proto::FormsAnnotationsResponse response;
for (const auto& entry : response_upserted_entries) {
optimization_guide::proto::UserAnnotationsEntry* new_entry =
response.add_upserted_entries();
new_entry->set_entry_id(entry.entry_id);
new_entry->set_key(entry.key);
new_entry->set_value(entry.value);
}
std::vector<autofill::FormFieldData> form_fields;
for (const auto& entry : request_entries) {
autofill::FormFieldData form_field;
form_field.set_label(entry[0]);
form_field.set_name(entry[1]);
form_field.set_value(entry[2]);
form_fields.push_back(form_field);
}
autofill::FormData form_data;
form_data.set_fields(form_fields);
optimization_guide::proto::AXTreeUpdate ax_tree;
ax_tree.mutable_tree_data()->set_title("title");
return {optimization_guide::AnyWrapProto(response), ax_tree, form_data,
GURL("example.com"), "title"};
}
TEST_F(UserAnnotationsServiceTest, ExecuteFailed) {
base::HistogramTester histogram_tester;
EXPECT_CALL(
*model_executor(),
ExecuteModel(
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
An<optimization_guide::
OptimizationGuideModelExecutionResultCallback>()))
.WillOnce(base::test::RunOnceCallback<3>(
optimization_guide::OptimizationGuideModelExecutionResult(
base::unexpected(
optimization_guide::OptimizationGuideModelExecutionError::
FromModelExecutionError(
optimization_guide::
OptimizationGuideModelExecutionError::
ModelExecutionError::kGenericFailure)),
nullptr),
CreateLogEntry()));
autofill::FormFieldData form_field_data;
form_field_data.set_label(u"label");
form_field_data.set_value(u"whatever");
autofill::FormFieldData form_field_data2;
form_field_data2.set_name(u"nolabel");
form_field_data2.set_value(u"value");
autofill::FormData form_data;
form_data.set_fields({form_field_data, form_field_data2});
optimization_guide::proto::AXTreeUpdate ax_tree;
EXPECT_TRUE(AddAndImportFormSubmission(ax_tree, form_data).empty());
histogram_tester.ExpectUniqueSample(
"UserAnnotations.AddFormSubmissionResult",
UserAnnotationsExecutionResult::kResponseError, 1);
EXPECT_TRUE(logs_service()->uploaded_logs().empty());
}
TEST_F(UserAnnotationsServiceTest, UnexpectedResponseType) {
base::HistogramTester histogram_tester;
optimization_guide::proto::Any any;
EXPECT_CALL(
*model_executor(),
ExecuteModel(
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
An<optimization_guide::
OptimizationGuideModelExecutionResultCallback>()))
.WillOnce(base::test::RunOnceCallback<3>(
optimization_guide::OptimizationGuideModelExecutionResult(any,
nullptr),
CreateLogEntry()));
autofill::FormFieldData form_field_data;
form_field_data.set_label(u"label");
form_field_data.set_value(u"whatever");
autofill::FormFieldData form_field_data2;
form_field_data2.set_name(u"nolabel");
form_field_data2.set_value(u"value");
autofill::FormData form_data;
form_data.set_fields({form_field_data, form_field_data2});
optimization_guide::proto::AXTreeUpdate ax_tree;
EXPECT_TRUE(AddAndImportFormSubmission(ax_tree, form_data).empty());
histogram_tester.ExpectUniqueSample(
"UserAnnotations.AddFormSubmissionResult",
UserAnnotationsExecutionResult::kResponseMalformed, 1);
EXPECT_TRUE(logs_service()->uploaded_logs().empty());
}
TEST_F(UserAnnotationsServiceTest, RemoveEntry) {
base::HistogramTester histogram_tester;
auto test_request = CreateSampleFormsAnnotationsTestRequest();
EXPECT_CALL(
*model_executor(),
ExecuteModel(
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
An<optimization_guide::
OptimizationGuideModelExecutionResultCallback>()))
.WillOnce(base::test::RunOnceCallback<3>(
optimization_guide::OptimizationGuideModelExecutionResult(
test_request.forms_annotations_response, nullptr),
CreateLogEntry()));
EXPECT_FALSE(
AddAndImportFormSubmission(test_request.ax_tree, test_request.form_data)
.empty());
auto entries = GetAllUserAnnotationsEntries();
EXPECT_EQ(2u, entries.size());
base::test::TestFuture<void> test_future_remove_entry;
service()->RemoveEntry(entries[0].entry_id(),
test_future_remove_entry.GetCallback());
EXPECT_TRUE(test_future_remove_entry.Wait());
test_future_remove_entry.Clear();
EXPECT_EQ(1u, GetAllUserAnnotationsEntries().size());
histogram_tester.ExpectUniqueSample("UserAnnotations.RemoveEntry.Result",
UserAnnotationsExecutionResult::kSuccess,
1);
service()->RemoveEntry(entries[1].entry_id(),
test_future_remove_entry.GetCallback());
EXPECT_TRUE(test_future_remove_entry.Wait());
histogram_tester.ExpectUniqueSample("UserAnnotations.RemoveEntry.Result",
UserAnnotationsExecutionResult::kSuccess,
2);
EXPECT_TRUE(GetAllUserAnnotationsEntries().empty());
}
TEST_F(UserAnnotationsServiceTest, RemoveAllEntries) {
base::HistogramTester histogram_tester;
auto test_request = CreateSampleFormsAnnotationsTestRequest();
EXPECT_CALL(
*model_executor(),
ExecuteModel(
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
An<optimization_guide::
OptimizationGuideModelExecutionResultCallback>()))
.WillOnce(base::test::RunOnceCallback<3>(
optimization_guide::OptimizationGuideModelExecutionResult(
test_request.forms_annotations_response, nullptr),
CreateLogEntry()));
EXPECT_FALSE(
AddAndImportFormSubmission(test_request.ax_tree, test_request.form_data)
.empty());
EXPECT_EQ(2u, GetAllUserAnnotationsEntries().size());
base::test::TestFuture<void> test_future_remove_entry;
service()->RemoveAllEntries(test_future_remove_entry.GetCallback());
EXPECT_TRUE(test_future_remove_entry.Wait());
histogram_tester.ExpectUniqueSample("UserAnnotations.RemoveAllEntries.Result",
UserAnnotationsExecutionResult::kSuccess,
1);
EXPECT_TRUE(GetAllUserAnnotationsEntries().empty());
}
TEST_F(UserAnnotationsServiceTest, FormNotImported) {
base::HistogramTester histogram_tester;
auto test_request = CreateSampleFormsAnnotationsTestRequest();
EXPECT_CALL(
*model_executor(),
ExecuteModel(
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
An<optimization_guide::
OptimizationGuideModelExecutionResultCallback>()))
.WillOnce(base::test::RunOnceCallback<3>(
optimization_guide::OptimizationGuideModelExecutionResult(
test_request.forms_annotations_response, nullptr),
CreateLogEntry()));
service()->AddFormSubmission(
test_request.url, test_request.title, test_request.ax_tree,
std::make_unique<autofill::FormStructure>(test_request.form_data),
base::BindLambdaForTesting(
[](std::unique_ptr<autofill::FormStructure> form,
std::unique_ptr<user_annotations::FormAnnotationResponse>
form_annotation_response,
PromptAcceptanceCallback prompt_acceptance_callback) {
std::move(prompt_acceptance_callback)
.Run({/*prompt_was_accepted=*/false});
}));
EXPECT_TRUE(GetAllUserAnnotationsEntries().empty());
}
TEST_F(UserAnnotationsServiceTest, ParallelFormSubmissions) {
base::HistogramTester histogram_tester;
auto first_test_request = CreateSampleFormsAnnotationsTestRequest();
optimization_guide::OptimizationGuideModelExecutionResultCallback
first_execute_callback,
second_execute_callback;
PromptAcceptanceCallback first_prompt_acceptance_callback,
second_prompt_acceptance_callback;
EXPECT_CALL(
*model_executor(),
ExecuteModel(
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
An<optimization_guide::
OptimizationGuideModelExecutionResultCallback>()))
.WillOnce(MoveArg<3>(&first_execute_callback))
.WillOnce(MoveArg<3>(&second_execute_callback));
service()->AddFormSubmission(
first_test_request.url, first_test_request.title,
first_test_request.ax_tree,
std::make_unique<autofill::FormStructure>(first_test_request.form_data),
base::BindLambdaForTesting(
[&first_prompt_acceptance_callback](
std::unique_ptr<autofill::FormStructure> form,
std::unique_ptr<user_annotations::FormAnnotationResponse>
form_annotation_response,
PromptAcceptanceCallback callback) {
first_prompt_acceptance_callback = std::move(callback);
}));
auto second_test_request =
CreateSampleFormsAnnotationsTestRequest(/*request_entries=*/
{
{u"label", u"", u"whatever"},
{u"", u"nolabel", u"value"},
},
/*response_upserted_entries=*/{
{1, "label", "new_value"},
{2, "nolabel",
"new_nolabel_value"},
});
service()->AddFormSubmission(
second_test_request.url, second_test_request.title,
second_test_request.ax_tree,
std::make_unique<autofill::FormStructure>(second_test_request.form_data),
base::BindLambdaForTesting(
[&second_prompt_acceptance_callback](
std::unique_ptr<autofill::FormStructure> form,
std::unique_ptr<user_annotations::FormAnnotationResponse>
form_annotation_response,
PromptAcceptanceCallback callback) {
second_prompt_acceptance_callback = std::move(callback);
}));
// Only the first model execute should happen.
task_environment_.RunUntilIdle();
EXPECT_TRUE(first_execute_callback);
EXPECT_FALSE(second_execute_callback);
std::move(first_execute_callback)
.Run(optimization_guide::OptimizationGuideModelExecutionResult(
first_test_request.forms_annotations_response, nullptr),
CreateLogEntry());
// Only the first prompt acceptance call should happen.
task_environment_.RunUntilIdle();
EXPECT_FALSE(second_execute_callback);
EXPECT_TRUE(first_prompt_acceptance_callback);
std::move(first_prompt_acceptance_callback)
.Run({/*prompt_was_accepted=*/true, /*did_user_interact=*/true});
histogram_tester.ExpectUniqueSample("UserAnnotations.AddFormSubmissionResult",
UserAnnotationsExecutionResult::kSuccess,
1);
auto entries = GetAllUserAnnotationsEntries();
EXPECT_EQ(2u, entries.size());
EXPECT_EQ(entries[0].key(), "label");
EXPECT_EQ(entries[0].value(), "whatever");
EXPECT_EQ(entries[1].key(), "nolabel");
EXPECT_EQ(entries[1].value(), "value");
// Now the second form submission should happen.
task_environment_.RunUntilIdle();
std::move(second_execute_callback)
.Run(optimization_guide::OptimizationGuideModelExecutionResult(
second_test_request.forms_annotations_response, nullptr),
CreateLogEntry());
task_environment_.RunUntilIdle();
std::move(second_prompt_acceptance_callback)
.Run({/*prompt_was_accepted=*/true, /*did_user_interact=*/true});
histogram_tester.ExpectUniqueSample("UserAnnotations.AddFormSubmissionResult",
UserAnnotationsExecutionResult::kSuccess,
2);
entries = GetAllUserAnnotationsEntries();
EXPECT_EQ(2u, entries.size());
EXPECT_EQ(entries[0].key(), "label");
EXPECT_EQ(entries[0].value(), "new_value");
EXPECT_EQ(entries[1].key(), "nolabel");
EXPECT_EQ(entries[1].value(), "new_nolabel_value");
}
TEST_F(UserAnnotationsServiceTest, SaveAutofillProfile) {
base::HistogramTester histogram_tester;
autofill::AutofillProfile autofill_profile(AddressCountryCode("US"));
autofill::test::SetProfileInfo(&autofill_profile, "Jane", "J", "Doe",
"jd@example.com", "", "123 Main St", "",
"Raleigh", "NC", "12345", "US", "9195555555");
base::test::TestFuture<UserAnnotationsExecutionResult> test_future;
service()->SaveAutofillProfile(autofill_profile, test_future.GetCallback());
ASSERT_TRUE(test_future.Wait());
const UserAnnotationsEntries entries = GetAllUserAnnotationsEntries();
histogram_tester.ExpectUniqueSample("UserAnnotations.EntryCount", 10, 1);
EXPECT_EQ(entries.size(), 10u);
EXPECT_EQ(entries[0].key(), "First Name");
EXPECT_EQ(entries[0].value(), "Jane");
EXPECT_EQ(entries[1].key(), "Middle Name");
EXPECT_EQ(entries[1].value(), "J");
EXPECT_EQ(entries[2].key(), "Last Name");
EXPECT_EQ(entries[2].value(), "Doe");
EXPECT_EQ(entries[3].key(), "Email Address");
EXPECT_EQ(entries[3].value(), "jd@example.com");
EXPECT_EQ(entries[4].key(), "Phone Number [mobile]");
EXPECT_EQ(entries[4].value(), "9195555555");
EXPECT_EQ(entries[5].key(), "Address - City");
EXPECT_EQ(entries[5].value(), "Raleigh");
EXPECT_EQ(entries[6].key(), "Address - State");
EXPECT_EQ(entries[6].value(), "NC");
EXPECT_EQ(entries[7].key(), "Address - Zip Code");
EXPECT_EQ(entries[7].value(), "12345");
EXPECT_EQ(entries[8].key(), "Address - Country");
EXPECT_EQ(entries[8].value(), "US");
EXPECT_EQ(entries[9].key(), "Address - Street");
EXPECT_EQ(entries[9].value(), "123 Main St");
}
class UserAnnotationsServiceSeededAnnotationTest
: public UserAnnotationsServiceTest {
public:
void SetUp() override {
const std::vector<Entry>& response_upserted_entries = {
{0, "label", "whatever"},
{0, "nolabel", "value"},
};
optimization_guide::proto::FormsAnnotationsResponse response;
for (const auto& entry : response_upserted_entries) {
optimization_guide::proto::UserAnnotationsEntry* new_entry =
response.add_upserted_entries();
new_entry->set_entry_id(entry.entry_id);
new_entry->set_key(entry.key);
new_entry->set_value(entry.value);
}
std::string encoded_annotations;
response.SerializeToString(&encoded_annotations);
encoded_annotations = base::Base64Encode(encoded_annotations);
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kFormsAnnotationsOverride, encoded_annotations);
UserAnnotationsServiceTest::SetUp();
}
};
TEST_F(UserAnnotationsServiceSeededAnnotationTest, SeedAnnotations) {
task_environment_.RunUntilIdle();
auto entries = GetAllUserAnnotationsEntries();
EXPECT_EQ(2u, entries.size());
EXPECT_EQ(entries[0].key(), "label");
EXPECT_EQ(entries[0].value(), "whatever");
EXPECT_EQ(entries[1].key(), "nolabel");
EXPECT_EQ(entries[1].value(), "value");
}
} // namespace
} // namespace user_annotations

@ -1,46 +0,0 @@
#include "components/user_annotations/user_annotations_switches.h"
#include <optional>
#include "base/base64.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
namespace user_annotations {
namespace switches {
// Overrides providing form annotations for seeding the annotation store.
// The value should be a base64 encoded of an annotations response.
const char kFormsAnnotationsOverride[] =
"user-annotations-forms-annotation-override";
std::optional<optimization_guide::proto::FormsAnnotationsResponse>
ParseFormsAnnotationsFromCommandLine() {
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (!cmd_line->HasSwitch(kFormsAnnotationsOverride)) {
return std::nullopt;
}
std::string b64_pb = cmd_line->GetSwitchValueASCII(kFormsAnnotationsOverride);
std::string binary_pb;
if (!base::Base64Decode(b64_pb, &binary_pb)) {
LOG(ERROR) << "Invalid base64 encoding of the Hints Proto Override";
return std::nullopt;
}
optimization_guide::proto::FormsAnnotationsResponse forms_annotations =
optimization_guide::proto::FormsAnnotationsResponse();
if (!forms_annotations.ParseFromString(binary_pb)) {
LOG(ERROR) << "Invalid proto provided to the Forms Annotation Override";
return std::nullopt;
}
return forms_annotations;
}
} // namespace switches
} // namespace user_annotations

@ -1,19 +0,0 @@
#ifndef COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SWITCHES_H_
#define COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SWITCHES_H_
#include <optional>
#include "components/optimization_guide/proto/features/forms_annotations.pb.h"
namespace user_annotations {
namespace switches {
extern const char kFormsAnnotationsOverride[];
std::optional<optimization_guide::proto::FormsAnnotationsResponse>
ParseFormsAnnotationsFromCommandLine();
} // namespace switches
} // namespace user_annotations
#endif // COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SWITCHES_H_

@ -1,69 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/user_annotations_switches.h"
#include "base/base64.h"
#include "base/command_line.h"
#include "base/test/protobuf_matchers.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "components/user_annotations/user_annotations_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace user_annotations {
namespace {
using ::base::test::EqualsProto;
using ::testing::UnorderedElementsAre;
struct Entry {
size_t entry_id;
std::string key;
std::string value;
};
TEST(UserAnnotationsSwitchesTest, OverrideFormsAnnotations) {
const std::vector<Entry>& response_upserted_entries = {
{0, "label", "whatever"},
{0, "nolabel", "value"},
};
optimization_guide::proto::FormsAnnotationsResponse response;
for (const auto& entry : response_upserted_entries) {
optimization_guide::proto::UserAnnotationsEntry* new_entry =
response.add_upserted_entries();
new_entry->set_entry_id(entry.entry_id);
new_entry->set_key(entry.key);
new_entry->set_value(entry.value);
}
std::string encoded_annotations;
response.SerializeToString(&encoded_annotations);
encoded_annotations = base::Base64Encode(encoded_annotations);
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kFormsAnnotationsOverride, encoded_annotations);
auto output = switches::ParseFormsAnnotationsFromCommandLine();
EXPECT_TRUE(output.has_value());
EXPECT_THAT(output.value(), EqualsProto(response));
}
TEST(UserAnnotationsSwitchesTest, OverrideFormsAnnotationsBadFormat) {
std::string encoded_annotations = "Not a proto";
encoded_annotations = base::Base64Encode(encoded_annotations);
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kFormsAnnotationsOverride, encoded_annotations);
auto output = switches::ParseFormsAnnotationsFromCommandLine();
EXPECT_FALSE(output.has_value());
}
} // namespace
} // namespace user_annotations

@ -1,18 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_annotations/user_annotations_types.h"
namespace user_annotations {
FormAnnotationResponse::FormAnnotationResponse(
const std::vector<optimization_guide::proto::UserAnnotationsEntry>&
to_be_upserted_entries,
const std::string& model_execution_id)
: to_be_upserted_entries(to_be_upserted_entries),
model_execution_id(model_execution_id) {}
FormAnnotationResponse::~FormAnnotationResponse() = default;
} // namespace user_annotations

@ -1,95 +0,0 @@
// Copyright 2024 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_USER_ANNOTATIONS_USER_ANNOTATIONS_TYPES_H_
#define COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_TYPES_H_
#include <vector>
#include "base/functional/callback_forward.h"
#include "base/types/expected.h"
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
namespace optimization_guide::proto {
class UserAnnotationsEntry;
}
namespace autofill {
class FormStructure;
} // namespace autofill
namespace user_annotations {
typedef int64_t EntryID;
typedef std::vector<optimization_guide::proto::UserAnnotationsEntry>
UserAnnotationsEntries;
struct Entry {
// The row ID of this entry from the user annotations database. This is
// immutable except when retrieving the row from the database.
EntryID entry_id;
// The proto for this entry.
optimization_guide::proto::UserAnnotationsEntry entry_proto;
};
// Encapsulates the result of various operations with user annotations entries.
enum class UserAnnotationsExecutionResult {
kSuccess = 0,
kSqlError = 1,
kCryptNotInitialized = 2,
kCryptError = 3,
kResponseError = 4,
kResponseMalformed = 5,
kResponseTimedOut = 6,
// Insert new values before this line. Should be in sync with
// UserAnnotationsExecutionResult in user_annotations/enums.xml
kMaxValue = kResponseTimedOut
};
using UserAnnotationsEntryRetrievalResult =
base::expected<std::vector<optimization_guide::proto::UserAnnotationsEntry>,
UserAnnotationsExecutionResult>;
// Encapsulates the result of user interaction with the prediction improvements
// prompt.
struct PromptAcceptanceResult {
bool prompt_was_accepted = false;
bool did_user_interact = false;
bool did_thumbs_up_triggered = false;
bool did_thumbs_down_triggered = false;
};
// Encapsulates the result of annotating a form submission.
// `to_be_upserted_entries` is the updated entries, that will be shown in the
// Autofill prediction improvements prompt. `model_execution_id` is the server
// log id for model execution, and can be sent in any user submitted feedback.
struct FormAnnotationResponse {
std::vector<optimization_guide::proto::UserAnnotationsEntry>
to_be_upserted_entries;
std::string model_execution_id;
FormAnnotationResponse(
const std::vector<optimization_guide::proto::UserAnnotationsEntry>&
to_be_upserted_entries,
const std::string& model_execution_id);
~FormAnnotationResponse();
};
using PromptAcceptanceCallback =
base::OnceCallback<void(PromptAcceptanceResult result)>;
// Callback for notifying the form annotation result to Autofill. User decision
// for importing the updated form entries is notified to
// `UserAnnotationsService` via the `prompt_acceptance_callback`.
using ImportFormCallback = base::OnceCallback<void(
std::unique_ptr<autofill::FormStructure> form,
std::unique_ptr<FormAnnotationResponse> form_annotation_response,
PromptAcceptanceCallback prompt_acceptance_callback)>;
} // namespace user_annotations
#endif // COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_TYPES_H_

@ -161,8 +161,6 @@ static_library("test_support") {
"//components/prefs:test_support",
"//components/sync_preferences:test_support",
"//components/update_client",
"//components/user_annotations",
"//components/user_annotations:test_support",
"//components/user_prefs",
"//content/public/common",
"//content/test:test_support",

@ -66,7 +66,6 @@ CreateCounterForProfileAndPref(ProfileIOS* profile,
autofill::PersonalDataManagerFactory::GetForProfile(profile),
ios::WebDataServiceFactory::GetAutofillWebDataForProfile(
profile, ServiceAccessType::EXPLICIT_ACCESS),
/*user_annotations_service=*/nullptr,
SyncServiceFactory::GetForProfile(profile));
}

@ -193,10 +193,9 @@ class QuickDeleteMediatorTest : public PlatformTest {
void triggerUpdateUICallbackForAutofillResults(int num_suggestions,
int num_cards,
int num_addresses) {
browsing_data::AutofillCounter autofillCounter(nullptr, nullptr, nullptr,
nullptr);
browsing_data::AutofillCounter autofillCounter(nullptr, nullptr, nullptr);
const browsing_data::AutofillCounter::AutofillResult autofillResult(
&autofillCounter, num_suggestions, num_cards, num_addresses, 0, false);
&autofillCounter, num_suggestions, num_cards, num_addresses, false);
OCMExpect([consumer_
setAutofillSummary:quick_delete_util::GetCounterTextFromResult(
autofillResult, timeRange())]);
@ -410,11 +409,11 @@ TEST_F(QuickDeleteMediatorTest, TestAddressesSummary) {
triggerUpdateUICallbackForPasswordsResults(0);
// clang-format off
const struct TestCase {
int num_addresses;
bool sync_enabled;
NSString* expected_output;
} kTestCases[] = {
const struct TestCase {
int num_addresses;
bool sync_enabled;
NSString* expected_output;
} kTestCases[] = {
{0, true, l10n_util::GetNSString(
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_NO_DATA)},
{0, false, l10n_util::GetNSString(
@ -427,14 +426,14 @@ TEST_F(QuickDeleteMediatorTest, TestAddressesSummary) {
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_ADRESSES, 2)},
{2, false, l10n_util::GetPluralNSStringF(
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_ADRESSES, 2)},
};
};
// clang-format on
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr, nullptr);
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr);
for (const TestCase& test_case : kTestCases) {
const browsing_data::AutofillCounter::AutofillResult result(
&counter, 0, 0, test_case.num_addresses, 0, test_case.sync_enabled);
&counter, 0, 0, test_case.num_addresses, test_case.sync_enabled);
OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
OCMExpect([consumer_
setAutofillSummary:quick_delete_util::GetCounterTextFromResult(
@ -462,11 +461,11 @@ TEST_F(QuickDeleteMediatorTest, TestCardsSummary) {
triggerUpdateUICallbackForPasswordsResults(0);
// clang-format off
const struct TestCase {
int num_cards;
bool sync_enabled;
NSString* expected_output;
} kTestCases[] = {
const struct TestCase {
int num_cards;
bool sync_enabled;
NSString* expected_output;
} kTestCases[] = {
{0, true, l10n_util::GetNSString(
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_NO_DATA)},
{0, false, l10n_util::GetNSString(
@ -479,14 +478,14 @@ TEST_F(QuickDeleteMediatorTest, TestCardsSummary) {
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_PAYMENT_METHODS, 2)},
{2, false, l10n_util::GetPluralNSStringF(
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_PAYMENT_METHODS, 2)},
};
};
// clang-format on
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr, nullptr);
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr);
for (const TestCase& test_case : kTestCases) {
const browsing_data::AutofillCounter::AutofillResult result(
&counter, 0, test_case.num_cards, 0, 0, test_case.sync_enabled);
&counter, 0, test_case.num_cards, 0, test_case.sync_enabled);
OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
OCMExpect([consumer_
@ -516,11 +515,11 @@ TEST_F(QuickDeleteMediatorTest, TestSuggestionsSummary) {
triggerUpdateUICallbackForPasswordsResults(0);
// clang-format off
const struct TestCase {
int num_suggestions;
bool sync_enabled;
NSString* expected_output;
} kTestCases[] = {
const struct TestCase {
int num_suggestions;
bool sync_enabled;
NSString* expected_output;
} kTestCases[] = {
{0, true, l10n_util::GetNSString(
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_NO_DATA)},
{0, false, l10n_util::GetNSString(
@ -535,14 +534,14 @@ TEST_F(QuickDeleteMediatorTest, TestSuggestionsSummary) {
2)},
{2, false, l10n_util::GetPluralNSStringF(
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_SUGGESTIONS, 2)},
};
};
// clang-format on
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr, nullptr);
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr);
for (const TestCase& test_case : kTestCases) {
const browsing_data::AutofillCounter::AutofillResult result(
&counter, test_case.num_suggestions, 0, 0, 0, test_case.sync_enabled);
&counter, test_case.num_suggestions, 0, 0, test_case.sync_enabled);
OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
OCMExpect([consumer_
setAutofillSummary:quick_delete_util::GetCounterTextFromResult(

@ -278,8 +278,6 @@ histograms_xml_files = [
"//tools/metrics/histograms/metadata/uma/enums.xml",
"//tools/metrics/histograms/metadata/uma/histograms.xml",
"//tools/metrics/histograms/metadata/update_engine/histograms.xml",
"//tools/metrics/histograms/metadata/user_annotations/enums.xml",
"//tools/metrics/histograms/metadata/user_annotations/histograms.xml",
"//tools/metrics/histograms/metadata/user_education/histograms.xml",
"//tools/metrics/histograms/metadata/v8/enums.xml",
"//tools/metrics/histograms/metadata/v8/histograms.xml",

@ -1,7 +0,0 @@
per-file OWNERS=file://tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
# Prefer sending CLs to the owners listed below.
# Use chromium-metrics-reviews@google.com as a backup.
mcrouse@chromium.org
sophiechang@chromium.org
tbansal@chromium.org

@ -1,41 +0,0 @@
<!--
Copyright 2024 The Chromium Authors
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<!--
This file describes the enumerations referenced by entries in histograms.xml for
this directory. Some enums may instead be listed in the central enums.xml file
at src/tools/metrics/histograms/enums.xml when multiple files use them.
For best practices on writing enumerations descriptions, see
https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md#Enum-Histograms
Please follow the instructions in the OWNERS file in this directory to find a
reviewer. If no OWNERS file exists, please consider signing up at
go/reviewing-metrics (Googlers only), as all subdirectories are expected to
have an OWNERS file. As a last resort you can send the CL to
chromium-metrics-reviews@google.com.
-->
<histogram-configuration>
<!-- Enum types -->
<enums>
<enum name="UserAnnotationsExecutionResult">
<int value="0" label="Success"/>
<int value="1" label="SQL update failed"/>
<int value="2" label="OSCrypt is not initialized at startup"/>
<int value="3" label="OSCrypt encrypt/decrypt error"/>
<int value="4" label="Response error"/>
<int value="5" label="Response malformed"/>
<int value="6" label="Response timed out"/>
</enum>
</enums>
</histogram-configuration>

@ -1,67 +0,0 @@
<!--
Copyright 2024 The Chromium Authors
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<histogram-configuration>
<histograms>
<histogram name="UserAnnotations.AddFormSubmissionResult"
enum="UserAnnotationsExecutionResult" expires_after="2025-05-25">
<owner>rajendrant@chromium.org</owner>
<owner>sophiechang@chromium.org</owner>
<summary>
Records the result of a form submission to user annotations service.
Recorded for each form submission that is allowed to be stored in the user
annotations database.
</summary>
</histogram>
<histogram name="UserAnnotations.CountEntries.Result"
enum="UserAnnotationsExecutionResult" expires_after="M135">
<owner>rajendrant@chromium.org</owner>
<owner>sophiechang@chromium.org</owner>
<summary>
Records the result of counting entries within a certain time frame from user
annotations service. Recorded for each call to count entries from the
browsing data removal UI.
</summary>
</histogram>
<histogram name="UserAnnotations.EntryCount" units="Entries"
expires_after="M135">
<owner>dongyn@chromium.org</owner>
<owner>sophiechang@chromium.org</owner>
<summary>
Records the number of user annotations entries currently on disk. Recorded
once for each call to retrieve entries from disk.
</summary>
</histogram>
<histogram name="UserAnnotations.RemoveAllEntries.Result"
enum="UserAnnotationsExecutionResult" expires_after="M135">
<owner>rajendrant@chromium.org</owner>
<owner>sophiechang@chromium.org</owner>
<summary>
Records the result of removing all entries from user annotations service.
Recorded for each remove all entries call from the database via the
management UI.
</summary>
</histogram>
<histogram name="UserAnnotations.RemoveEntry.Result"
enum="UserAnnotationsExecutionResult" expires_after="M135">
<owner>rajendrant@chromium.org</owner>
<owner>sophiechang@chromium.org</owner>
<summary>
Records the result of removing a single entry from user annotations service.
Recorded for each user annotation entry removal from the database via the
management UI.
</summary>
</histogram>
</histograms>
</histogram-configuration>