From aa6ae781715bf6400c73c471121c3553cdd2da1b Mon Sep 17 00:00:00 2001 From: Darnell Andries Date: Tue, 26 Nov 2024 15:18:09 -0800 Subject: [PATCH] Add metric configuration and alternative metric attributes --- .../browser/brave_stats_updater_util.cc | 16 + .../browser/brave_stats_updater_util.h | 2 + components/p3a/BUILD.gn | 4 + .../p3a/constellation_helper_unittest.cc | 61 +- components/p3a/message_manager.cc | 47 +- components/p3a/message_manager.h | 3 + components/p3a/message_manager_unittest.cc | 28 +- components/p3a/metric_config.h | 60 ++ components/p3a/metric_log_store_unittest.cc | 2 +- components/p3a/metric_log_type.h | 1 - components/p3a/metric_names.h | 536 ++++++++---------- components/p3a/metric_names_unittest.cc | 8 +- components/p3a/p3a_message.cc | 181 ++++-- components/p3a/p3a_message.h | 23 +- components/p3a/p3a_service.cc | 11 +- components/p3a/p3a_service_unittest.cc | 11 +- components/p3a/region.cc | 350 ++++++++++++ components/p3a/region.h | 22 + components/p3a/region_unittest.cc | 59 ++ 19 files changed, 1002 insertions(+), 423 deletions(-) create mode 100644 components/p3a/metric_config.h create mode 100644 components/p3a/region.cc create mode 100644 components/p3a/region.h create mode 100644 components/p3a/region_unittest.cc diff --git a/components/brave_stats/browser/brave_stats_updater_util.cc b/components/brave_stats/browser/brave_stats_updater_util.cc index 2c98b7e8b129..e798efdb2914 100644 --- a/components/brave_stats/browser/brave_stats_updater_util.cc +++ b/components/brave_stats/browser/brave_stats_updater_util.cc @@ -56,6 +56,22 @@ std::string GetPlatformIdentifier() { #endif } +std::string GetGeneralPlatformIdentifier() { +#if BUILDFLAG(IS_WIN) + return "windows"; +#elif BUILDFLAG(IS_MAC) + return "macos"; +#elif BUILDFLAG(IS_LINUX) + return "linux"; +#elif BUILDFLAG(IS_IOS) + return "ios"; +#elif BUILDFLAG(IS_ANDROID) + return "android"; +#else + return std::string(); +#endif +} + int GetIsoWeekNumber(const base::Time& time) { char buffer[24]; time_t rawtime = time.ToTimeT(); diff --git a/components/brave_stats/browser/brave_stats_updater_util.h b/components/brave_stats/browser/brave_stats_updater_util.h index b79129850752..4b92cdbd0e1d 100644 --- a/components/brave_stats/browser/brave_stats_updater_util.h +++ b/components/brave_stats/browser/brave_stats_updater_util.h @@ -24,6 +24,8 @@ std::string GetDateAsYMD(const base::Time& time); std::string GetPlatformIdentifier(); +std::string GetGeneralPlatformIdentifier(); + int GetIsoWeekNumber(const base::Time& time); base::Time GetLastMondayTime(const base::Time& time); diff --git a/components/p3a/BUILD.gn b/components/p3a/BUILD.gn index 36791aeb8574..5c2160701352 100644 --- a/components/p3a/BUILD.gn +++ b/components/p3a/BUILD.gn @@ -24,6 +24,7 @@ static_library("p3a") { "histograms_braveizer.h", "message_manager.cc", "message_manager.h", + "metric_config.h", "metric_log_store.cc", "metric_log_store.h", "metric_log_type.cc", @@ -44,6 +45,8 @@ static_library("p3a") { "p3a_service.cc", "p3a_service.h", "pref_names.h", + "region.cc", + "region.h", "rotation_scheduler.cc", "rotation_scheduler.h", "scheduler.cc", @@ -100,6 +103,7 @@ source_set("unit_tests") { "nitro_utils/cose_unittest.cc", "p2a_protocols_unittest.cc", "p3a_service_unittest.cc", + "region_unittest.cc", "rotation_scheduler_unittest.cc", "scheduler_unittest.cc", "star_randomness_test_util.cc", diff --git a/components/p3a/constellation_helper_unittest.cc b/components/p3a/constellation_helper_unittest.cc index e84bf1bf89c8..08b2766d6366 100644 --- a/components/p3a/constellation_helper_unittest.cc +++ b/components/p3a/constellation_helper_unittest.cc @@ -16,6 +16,7 @@ #include "base/strings/string_util.h" #include "base/test/bind.h" #include "base/time/time.h" +#include "brave/components/p3a/metric_config.h" #include "brave/components/p3a/metric_log_type.h" #include "brave/components/p3a/p3a_config.h" #include "brave/components/p3a/p3a_message.h" @@ -255,8 +256,8 @@ TEST_F(P3AConstellationHelperTest, GenerateBasicMessage) { helper_->StartMessagePreparation( kTestHistogramName, log_type, GenerateP3AConstellationMessage(kTestHistogramName, test_epoch, - meta_info, kP3AUploadType, false, - false), + meta_info, kP3AUploadType, + std::nullopt), false); task_environment_.RunUntilIdle(); @@ -276,7 +277,7 @@ TEST_F(P3AConstellationHelperTest, IncludeRefcode) { meta_info.Init(&local_state_, "release", "2022-01-01"); std::string message_with_no_refcode = GenerateP3AConstellationMessage( - kTestHistogramName, 0, meta_info, kP3AUploadType, false, false); + kTestHistogramName, 0, meta_info, kP3AUploadType, std::nullopt); std::vector no_refcode_layers = base::SplitString( message_with_no_refcode, kP3AMessageConstellationLayerSeparator, base::WhitespaceHandling::TRIM_WHITESPACE, @@ -286,7 +287,8 @@ TEST_F(P3AConstellationHelperTest, IncludeRefcode) { EXPECT_FALSE(no_refcode_layers.at(7).starts_with("ref")); std::string message_with_refcode = GenerateP3AConstellationMessage( - kTestHistogramName, 0, meta_info, kP3AUploadType, true, false); + kTestHistogramName, 0, meta_info, kP3AUploadType, + MetricConfig{.append_attributes = {MetricAttribute::kRef}}); std::vector refcode_layers = base::SplitString( message_with_refcode, kP3AMessageConstellationLayerSeparator, base::WhitespaceHandling::TRIM_WHITESPACE, @@ -300,7 +302,8 @@ TEST_F(P3AConstellationHelperTest, IncludeRefcode) { meta_info.Init(&local_state_, "release", "2022-01-01"); message_with_refcode = GenerateP3AConstellationMessage( - kTestHistogramName, 0, meta_info, kP3AUploadType, true, false); + kTestHistogramName, 0, meta_info, kP3AUploadType, + MetricConfig{.append_attributes = {MetricAttribute::kRef}}); refcode_layers = base::SplitString(message_with_refcode, kP3AMessageConstellationLayerSeparator, base::WhitespaceHandling::TRIM_WHITESPACE, @@ -313,7 +316,8 @@ TEST_F(P3AConstellationHelperTest, IncludeRefcode) { meta_info.Init(&local_state_, "release", "2022-01-01"); message_with_refcode = GenerateP3AConstellationMessage( - kTestHistogramName, 0, meta_info, kP3AUploadType, true, false); + kTestHistogramName, 0, meta_info, kP3AUploadType, + MetricConfig{.append_attributes = {MetricAttribute::kRef}}); refcode_layers = base::SplitString(message_with_refcode, kP3AMessageConstellationLayerSeparator, base::WhitespaceHandling::TRIM_WHITESPACE, @@ -324,12 +328,53 @@ TEST_F(P3AConstellationHelperTest, IncludeRefcode) { #endif // !BUILDFLAG(IS_IOS) } +TEST_F(P3AConstellationHelperTest, CustomAttributes) { + MessageMetainfo meta_info; + meta_info.Init(&local_state_, "release", "2022-01-01"); + + // Test with custom attributes list + MetricConfig config{.attributes = MetricAttributes{ + MetricAttribute::kAnswerIndex, + MetricAttribute::kVersion, + MetricAttribute::kPlatform, + MetricAttribute::kGeneralPlatform, + MetricAttribute::kChannel, + MetricAttribute::kRegion, + MetricAttribute::kSubregion, + }}; + + std::string message = GenerateP3AConstellationMessage( + kTestHistogramName, 7, meta_info, kP3AUploadType, config); + + std::vector layers = + base::SplitString(message, kP3AMessageConstellationLayerSeparator, + base::WhitespaceHandling::TRIM_WHITESPACE, + base::SplitResult::SPLIT_WANT_NONEMPTY); + + // Verify number of layers matches number of non-null attributes + EXPECT_EQ(layers.size(), 8U); + + // Verify each layer's content + EXPECT_EQ(layers[0], base::StrCat({"metric_name|", kTestHistogramName})); + EXPECT_EQ(layers[1], "metric_value|7"); + EXPECT_EQ(layers[2], "version|" + meta_info.version()); + EXPECT_EQ(layers[3], "platform|" + meta_info.platform()); + EXPECT_EQ(layers[4], "general_platform|" + meta_info.general_platform()); + EXPECT_EQ(layers[5], "channel|release"); + EXPECT_EQ(layers[6], + base::StrCat({"region|", meta_info.region_identifiers().region})); + EXPECT_EQ( + layers[7], + base::StrCat({"subregion|", meta_info.region_identifiers().sub_region})); +} + TEST_F(P3AConstellationHelperTest, NebulaMessage) { MessageMetainfo meta_info; meta_info.Init(&local_state_, "release", "2022-01-01"); std::string message = GenerateP3AConstellationMessage( - kTestHistogramName, 3, meta_info, kP3AUploadType, false, true); + kTestHistogramName, 3, meta_info, kP3AUploadType, + MetricConfig{.nebula = true}); std::vector no_refcode_layers = base::SplitString(message, kP3AMessageConstellationLayerSeparator, base::WhitespaceHandling::TRIM_WHITESPACE, @@ -355,7 +400,7 @@ TEST_F(P3AConstellationHelperTest, NebulaSample) { kTestNebulaHistogramName, MetricLogType::kTypical, GenerateP3AConstellationMessage(kTestNebulaHistogramName, kTestTypicalEpoch, meta_info, - kP3AUploadType, false, true), + kP3AUploadType, std::nullopt), true); task_environment_.RunUntilIdle(); diff --git a/components/p3a/message_manager.cc b/components/p3a/message_manager.cc index 0efa918befa0..c3c6e242f4fa 100644 --- a/components/p3a/message_manager.cc +++ b/components/p3a/message_manager.cc @@ -311,11 +311,12 @@ void MessageManager::StartScheduledUpload(bool is_constellation, is_constellation ? constellation_send_log_stores_[log_type]->staged_log_type() : json_log_stores_[log_type]->staged_log_type(); - const bool is_nebula = is_constellation - ? p3a::kNebulaOnlyHistograms.contains( - constellation_send_log_stores_[log_type] - ->staged_log_histogram_name()) - : false; + bool is_nebula = false; + if (is_constellation) { + const auto* metric_config = GetMetricConfig( + constellation_send_log_stores_[log_type]->staged_log_histogram_name()); + is_nebula = metric_config && *metric_config && (*metric_config)->nebula; + } VLOG(2) << logging_prefix << " - Uploading " << log.size() << " bytes"; uploader_->UploadLog(log, upload_type, is_constellation, is_nebula, log_type); @@ -352,9 +353,10 @@ void MessageManager::StartScheduledConstellationPrep(MetricLogType log_type) { const std::string log_key = log_store->staged_log_key(); VLOG(2) << "MessageManager::StartScheduledConstellationPrep - Requesting " "randomness for histogram: " - << log_key; + << log_key << " " << log; - const bool is_nebula = p3a::kNebulaOnlyHistograms.contains(log_key); + const auto* metric_config = GetMetricConfig(log_key); + bool is_nebula = metric_config && *metric_config && (*metric_config)->nebula; if (is_nebula && !features::IsNebulaEnabled()) { // Do not report if Nebula feature is not enabled, // mark request as successful to avoid transmission. @@ -394,12 +396,10 @@ std::string MessageManager::SerializeLog(std::string_view histogram_name, message_meta_.Update(); if (is_constellation) { - const bool include_refcode = - p3a::kHistogramsWithRefcodeIncluded.contains(histogram_name); - const bool is_nebula = p3a::kNebulaOnlyHistograms.contains(histogram_name); - return GenerateP3AConstellationMessage(histogram_name, value, message_meta_, - upload_type, include_refcode, - is_nebula); + const auto* metric_config = GetMetricConfig(histogram_name); + return GenerateP3AConstellationMessage( + histogram_name, value, message_meta_, upload_type, + metric_config ? *metric_config : std::nullopt); } else { base::Value::Dict p3a_json_value = GenerateP3AMessageDict( histogram_name, value, log_type, message_meta_, upload_type); @@ -411,6 +411,23 @@ std::string MessageManager::SerializeLog(std::string_view histogram_name, } } +const std::optional* MessageManager::GetMetricConfig( + const std::string_view histogram_name) const { + const std::optional* metric_config = nullptr; + + auto it = p3a::kCollectedTypicalHistograms.find(histogram_name); + if (it != p3a::kCollectedTypicalHistograms.end()) { + metric_config = &it->second; + } else if (it = p3a::kCollectedSlowHistograms.find(histogram_name); + it != p3a::kCollectedSlowHistograms.end()) { + metric_config = &it->second; + } else if (it = p3a::kCollectedExpressHistograms.find(histogram_name); + it != p3a::kCollectedExpressHistograms.end()) { + metric_config = &it->second; + } + return metric_config; +} + bool MessageManager::IsActualMetric(const std::string& histogram_name) const { return p3a::kCollectedTypicalHistograms.contains(histogram_name) || p3a::kCollectedExpressHistograms.contains(histogram_name) || @@ -420,7 +437,9 @@ bool MessageManager::IsActualMetric(const std::string& histogram_name) const { bool MessageManager::IsEphemeralMetric( const std::string& histogram_name) const { - return p3a::kEphemeralHistograms.contains(histogram_name) || + const auto* metric_config = GetMetricConfig(histogram_name); + + return (metric_config && *metric_config && (*metric_config)->ephemeral) || delegate_->GetDynamicMetricLogType(histogram_name).has_value(); } diff --git a/components/p3a/message_manager.h b/components/p3a/message_manager.h index 8b55ebfc2db4..fb06677179e0 100644 --- a/components/p3a/message_manager.h +++ b/components/p3a/message_manager.h @@ -88,6 +88,9 @@ class MessageManager : public MetricLogStore::Delegate { std::string_view histogram_name, std::optional only_update_for_constellation = std::nullopt); + const std::optional* GetMetricConfig( + const std::string_view histogram_name) const; + private: void StartScheduledUpload(bool is_constellation, MetricLogType log_type); void StartScheduledConstellationPrep(MetricLogType log_type); diff --git a/components/p3a/message_manager_unittest.cc b/components/p3a/message_manager_unittest.cc index f9578977ab36..086c29b0fbc5 100644 --- a/components/p3a/message_manager_unittest.cc +++ b/components/p3a/message_manager_unittest.cc @@ -188,38 +188,38 @@ class P3AMessageManagerTest : public testing::Test, std::vector GetTestHistogramNames(MetricLogType log_type, size_t p3a_count, size_t p2a_count) { - auto histogram_names_begin = kCollectedExpressHistograms.cbegin(); - auto histogram_names_end = kCollectedExpressHistograms.cend(); + auto histograms_begin = kCollectedExpressHistograms.cbegin(); + auto histograms_end = kCollectedExpressHistograms.cend(); std::vector result; size_t p3a_i = 0; size_t p2a_i = 0; switch (log_type) { case MetricLogType::kExpress: - histogram_names_begin = kCollectedExpressHistograms.cbegin(); - histogram_names_end = kCollectedExpressHistograms.cend(); + histograms_begin = kCollectedExpressHistograms.cbegin(); + histograms_end = kCollectedExpressHistograms.cend(); break; case MetricLogType::kSlow: - histogram_names_begin = kCollectedSlowHistograms.cbegin(); - histogram_names_end = kCollectedSlowHistograms.cend(); + histograms_begin = kCollectedSlowHistograms.cbegin(); + histograms_end = kCollectedSlowHistograms.cend(); break; case MetricLogType::kTypical: - histogram_names_begin = kCollectedTypicalHistograms.cbegin(); - histogram_names_end = kCollectedTypicalHistograms.cend(); + histograms_begin = kCollectedTypicalHistograms.cbegin(); + histograms_end = kCollectedTypicalHistograms.cend(); break; default: NOTREACHED(); } - for (auto histogram_name_i = histogram_names_begin; - histogram_name_i != histogram_names_end; histogram_name_i++) { - if (histogram_name_i->rfind(kP2APrefix, 0) == 0) { + for (auto histogram_i = histograms_begin; histogram_i != histograms_end; + histogram_i++) { + if (histogram_i->first.rfind(kP2APrefix, 0) == 0) { if (p2a_i < p2a_count) { - result.push_back(std::string(*histogram_name_i)); + result.push_back(std::string(histogram_i->first)); p2a_i++; } } else if (p3a_i < p3a_count && - (histogram_name_i->starts_with("Brave.Core") || + (histogram_i->first.starts_with("Brave.Core") || log_type == MetricLogType::kExpress)) { - result.push_back(std::string(*histogram_name_i)); + result.push_back(std::string(histogram_i->first)); p3a_i++; } diff --git a/components/p3a/metric_config.h b/components/p3a/metric_config.h new file mode 100644 index 000000000000..d755216bf359 --- /dev/null +++ b/components/p3a/metric_config.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_P3A_METRIC_CONFIG_H_ +#define BRAVE_COMPONENTS_P3A_METRIC_CONFIG_H_ + +#include +#include + +namespace p3a { + +enum class MetricAttribute { + // Default attributes + kAnswerIndex, + kVersion, + kYoi, + kChannel, + kPlatform, + kCountryCode, + kWoi, + // Alternative attributes + kGeneralPlatform, + kRegion, + kSubregion, + kRef, + kMaxValue = kRef, +}; + +inline constexpr MetricAttribute kDefaultMetricAttributes[] = { + MetricAttribute::kAnswerIndex, MetricAttribute::kVersion, + MetricAttribute::kYoi, MetricAttribute::kChannel, + MetricAttribute::kPlatform, MetricAttribute::kCountryCode, + MetricAttribute::kWoi, +}; + +using MetricAttributes = std::array, 8>; +using MetricAttributesToAppend = std::array, 2>; + +struct MetricConfig { + // Once the metric value has been sent, the value will be removed from the log + // store + bool ephemeral; + // Should only be sent via Constellation + bool constellation_only; + // Should only be sent via Nebula + bool nebula; + // Avoid reporting "other" for countries not included in the allowlist + // and rely on STAR to provide k-anonymity + bool disable_country_strip; + // Ordered attributes to be included with the metric + std::optional attributes; + // Ordered attributes to be appended to the list of default attributes + MetricAttributesToAppend append_attributes; +}; + +} // namespace p3a + +#endif // BRAVE_COMPONENTS_P3A_METRIC_CONFIG_H_ diff --git a/components/p3a/metric_log_store_unittest.cc b/components/p3a/metric_log_store_unittest.cc index c49c7a5f8ffc..cab04950e9ef 100644 --- a/components/p3a/metric_log_store_unittest.cc +++ b/components/p3a/metric_log_store_unittest.cc @@ -56,7 +56,7 @@ class P3AMetricLogStoreTest : public testing::Test, for (size_t i = 1; i <= message_count && histogram_it != p3a::kCollectedTypicalHistograms.end(); i++) { - log_store->UpdateValue(std::string(*histogram_it), 2); + log_store->UpdateValue(std::string(histogram_it->first), 2); histogram_it++; } } diff --git a/components/p3a/metric_log_type.h b/components/p3a/metric_log_type.h index 0ae46634421c..442df775a295 100644 --- a/components/p3a/metric_log_type.h +++ b/components/p3a/metric_log_type.h @@ -9,7 +9,6 @@ #include #include - namespace p3a { inline constexpr char kCreativeMetricPrefix[] = "creativeInstanceId."; diff --git a/components/p3a/metric_names.h b/components/p3a/metric_names.h index 489f4ef4f258..84c1757cb8cd 100644 --- a/components/p3a/metric_names.h +++ b/components/p3a/metric_names.h @@ -8,7 +8,8 @@ #include -#include "base/containers/fixed_flat_set.h" +#include "base/containers/fixed_flat_map.h" +#include "brave/components/p3a/metric_config.h" namespace p3a { @@ -24,331 +25,240 @@ namespace p3a { // // clang-format off inline constexpr auto kCollectedTypicalHistograms = - base::MakeFixedFlatSet(base::sorted_unique,{ - "Brave.AIChat.AcquisitionSource", - "Brave.AIChat.AvgPromptCount", - "Brave.AIChat.ChatCount", - "Brave.AIChat.ChatCount.Nebula", - "Brave.AIChat.ContextMenu.FreeUsages", - "Brave.AIChat.ContextMenu.MostUsedAction", - "Brave.AIChat.ContextMenu.PremiumUsages", - "Brave.AIChat.Enabled.2", - "Brave.AIChat.Enabled.SidebarEnabledA", - "Brave.AIChat.MostUsedEntryPoint", - "Brave.AIChat.NewUserReturning", - "Brave.AIChat.OmniboxOpens", - "Brave.AIChat.OmniboxWeekCompare", - "Brave.AIChat.UsageWeekly", - "Brave.AIChat.UsageWeekly.SidebarEnabledA", - "Brave.Ads.ClearData", - "Brave.Core.BookmarkCount", - "Brave.Core.CrashReportsEnabled", - "Brave.Core.DomainsLoaded", - "Brave.Core.FailedHTTPSUpgrades.2", - "Brave.Core.FirstPageLoadTime", - "Brave.Core.IsDefault", - "Brave.Core.NumberOfExtensions", - "Brave.Core.PagesReloaded", - "Brave.Core.TabCount", - "Brave.Core.WeeklyUsage", - "Brave.Core.WeeklyUsage.Nebula", - "Brave.Core.WindowCount.2", - "Brave.DNS.AutoSecureRequests.2", - "Brave.DNS.AutoSecureRequests.Cloudflare.2", - "Brave.DNS.AutoSecureRequests.Quad9.2", - "Brave.DNS.AutoSecureRequests.Wikimedia.2", - "Brave.DNS.SecureSetting", - "Brave.Extensions.AdBlock", - "Brave.IOS.IsLikelyDefault", + base::MakeFixedFlatMap>({ + {"Brave.AIChat.AcquisitionSource", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.AvgPromptCount", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.ChatCount", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.ChatCount.Nebula", MetricConfig{.nebula = true}}, + {"Brave.AIChat.ContextMenu.FreeUsages", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.ContextMenu.MostUsedAction", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.ContextMenu.PremiumUsages", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.Enabled.2", {}}, + {"Brave.AIChat.Enabled.SidebarEnabledA", {}}, + {"Brave.AIChat.MostUsedEntryPoint", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.NewUserReturning", {}}, + {"Brave.AIChat.OmniboxOpens", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.OmniboxWeekCompare", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.UsageWeekly", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.UsageWeekly.SidebarEnabledA", MetricConfig{.ephemeral = true}}, + {"Brave.Ads.ClearData", MetricConfig{.ephemeral = true}}, + {"Brave.Core.BookmarkCount", {}}, + {"Brave.Core.CrashReportsEnabled", {}}, + {"Brave.Core.DomainsLoaded", {}}, + {"Brave.Core.FailedHTTPSUpgrades.2", MetricConfig{.ephemeral = true}}, + {"Brave.Core.FirstPageLoadTime", MetricConfig{.ephemeral = true}}, + {"Brave.Core.IsDefault", {}}, + {"Brave.Core.NumberOfExtensions", {}}, + {"Brave.Core.PagesReloaded", {}}, + {"Brave.Core.TabCount", {}}, + {"Brave.Core.WeeklyUsage", {}}, + {"Brave.Core.WeeklyUsage.Nebula", MetricConfig{.nebula = true}}, + {"Brave.Core.WindowCount.2", {}}, + {"Brave.DNS.AutoSecureRequests.2", MetricConfig{.ephemeral = true}}, + {"Brave.DNS.AutoSecureRequests.Cloudflare.2", MetricConfig{.ephemeral = true}}, + {"Brave.DNS.AutoSecureRequests.Quad9.2", MetricConfig{.ephemeral = true}}, + {"Brave.DNS.AutoSecureRequests.Wikimedia.2", MetricConfig{.ephemeral = true}}, + {"Brave.DNS.SecureSetting", {}}, + {"Brave.Extensions.AdBlock", {}}, + {"Brave.IOS.IsLikelyDefault", {}}, - "Brave.Importer.ImporterSource.2", - "Brave.NTP.CustomizeUsageStatus.2", - "Brave.NTP.NewTabsCreated.3", - "Brave.NTP.SponsoredMediaType", - "Brave.Omnibox.SearchCount.3", + {"Brave.Importer.ImporterSource.2", {}}, + {"Brave.NTP.CustomizeUsageStatus.2", {}}, + {"Brave.NTP.NewTabsCreated.3", {}}, + {"Brave.NTP.SponsoredMediaType", {}}, + {"Brave.Omnibox.SearchCount.3", {}}, // P2A // Ad Impressions - "Brave.P2A.ad_notification.impressions", - "Brave.P2A.ad_notification.impressions_per_segment.architecture", - "Brave.P2A.ad_notification.impressions_per_segment.artsentertainment", - "Brave.P2A.ad_notification.impressions_per_segment.automotive", - "Brave.P2A.ad_notification.impressions_per_segment.business", - "Brave.P2A.ad_notification.impressions_per_segment.careers", - "Brave.P2A.ad_notification.impressions_per_segment.cellphones", - "Brave.P2A.ad_notification.impressions_per_segment.crypto", - "Brave.P2A.ad_notification.impressions_per_segment.education", - "Brave.P2A.ad_notification.impressions_per_segment.familyparenting", - "Brave.P2A.ad_notification.impressions_per_segment.fashion", - "Brave.P2A.ad_notification.impressions_per_segment.folklore", - "Brave.P2A.ad_notification.impressions_per_segment.fooddrink", - "Brave.P2A.ad_notification.impressions_per_segment.gaming", - "Brave.P2A.ad_notification.impressions_per_segment.healthfitness", - "Brave.P2A.ad_notification.impressions_per_segment.history", - "Brave.P2A.ad_notification.impressions_per_segment.hobbiesinterests", - "Brave.P2A.ad_notification.impressions_per_segment.home", - "Brave.P2A.ad_notification.impressions_per_segment.law", - "Brave.P2A.ad_notification.impressions_per_segment.military", - "Brave.P2A.ad_notification.impressions_per_segment.other", - "Brave.P2A.ad_notification.impressions_per_segment.personalfinance", - "Brave.P2A.ad_notification.impressions_per_segment.pets", - "Brave.P2A.ad_notification.impressions_per_segment.realestate", - "Brave.P2A.ad_notification.impressions_per_segment.science", - "Brave.P2A.ad_notification.impressions_per_segment.sports", - "Brave.P2A.ad_notification.impressions_per_segment.technologycomputing", - "Brave.P2A.ad_notification.impressions_per_segment.travel", - "Brave.P2A.ad_notification.impressions_per_segment.untargeted", - "Brave.P2A.ad_notification.impressions_per_segment.weather", - // Ad Opportunities - "Brave.P2A.ad_notification.opportunities", - "Brave.P2A.ad_notification.opportunities_per_segment.architecture", - "Brave.P2A.ad_notification.opportunities_per_segment.artsentertainment", - "Brave.P2A.ad_notification.opportunities_per_segment.automotive", - "Brave.P2A.ad_notification.opportunities_per_segment.business", - "Brave.P2A.ad_notification.opportunities_per_segment.careers", - "Brave.P2A.ad_notification.opportunities_per_segment.cellphones", - "Brave.P2A.ad_notification.opportunities_per_segment.crypto", - "Brave.P2A.ad_notification.opportunities_per_segment.education", - "Brave.P2A.ad_notification.opportunities_per_segment.familyparenting", - "Brave.P2A.ad_notification.opportunities_per_segment.fashion", - "Brave.P2A.ad_notification.opportunities_per_segment.folklore", - "Brave.P2A.ad_notification.opportunities_per_segment.fooddrink", - "Brave.P2A.ad_notification.opportunities_per_segment.gaming", - "Brave.P2A.ad_notification.opportunities_per_segment.healthfitness", - "Brave.P2A.ad_notification.opportunities_per_segment.history", - "Brave.P2A.ad_notification.opportunities_per_segment.hobbiesinterests", - "Brave.P2A.ad_notification.opportunities_per_segment.home", - "Brave.P2A.ad_notification.opportunities_per_segment.law", - "Brave.P2A.ad_notification.opportunities_per_segment.military", - "Brave.P2A.ad_notification.opportunities_per_segment.other", - "Brave.P2A.ad_notification.opportunities_per_segment.personalfinance", - "Brave.P2A.ad_notification.opportunities_per_segment.pets", - "Brave.P2A.ad_notification.opportunities_per_segment.realestate", - "Brave.P2A.ad_notification.opportunities_per_segment.science", - "Brave.P2A.ad_notification.opportunities_per_segment.sports", - "Brave.P2A.ad_notification.opportunities_per_segment.technologycomputing", - "Brave.P2A.ad_notification.opportunities_per_segment.travel", - "Brave.P2A.ad_notification.opportunities_per_segment.untargeted", - "Brave.P2A.ad_notification.opportunities_per_segment.weather", - "Brave.P2A.inline_content_ad.impressions", - "Brave.P2A.inline_content_ad.opportunities", - "Brave.P2A.new_tab_page_ad.impressions", - "Brave.P2A.new_tab_page_ad.opportunities", - "Brave.P3A.SentAnswersCount", - "Brave.Playlist.FirstTimeOffset", - "Brave.Playlist.NewUserReturning", - "Brave.Playlist.UsageDaysInWeek", - "Brave.Rewards.AdTypesEnabled.2", - "Brave.Rewards.AutoContributionsState.3", - "Brave.Rewards.DesktopPanelCount", - "Brave.Rewards.EnabledSource", - "Brave.Rewards.MobileConversion", - "Brave.Rewards.MobilePanelCount", - "Brave.Rewards.SearchResultAdsOptin", - "Brave.Rewards.TipsState.2", - "Brave.Rewards.ToolbarButtonTrigger", - "Brave.Rewards.WalletBalance.3", - "Brave.Rewards.WalletState", - "Brave.Search.GoogleWidgetUsage", - "Brave.Search.Promo.BannerB", - "Brave.Search.Promo.BannerC", - "Brave.Search.Promo.BannerD", - "Brave.Search.Promo.Button", - "Brave.Search.Promo.DDGBannerA", - "Brave.Search.Promo.DDGBannerB", - "Brave.Search.Promo.DDGBannerC", - "Brave.Search.Promo.DDGBannerD", - "Brave.Search.Promo.NewTabPage", - "Brave.Search.QueriesBeforeChurn", - "Brave.Search.SwitchEngine", - "Brave.Search.WebDiscoveryAndAds", - "Brave.Search.WebDiscoveryEnabled", - "Brave.Search.WidgetDefault", - "Brave.Search.WidgetUsage", - "Brave.Shields.AdBlockSetting", - "Brave.Shields.CookieListEnabled", - "Brave.Shields.DomainAdsSettingsAboveGlobal", - "Brave.Shields.DomainAdsSettingsBelowGlobal", - "Brave.Shields.FingerprintBlockSetting", - "Brave.Shields.UsageStatus", - "Brave.Sidebar.Enabled", - "Brave.Sidebar.SettingChange.SidebarEnabledA", - "Brave.Sync.JoinType", - "Brave.Sync.Status.2", - "Brave.Today.ClickCardDepth", - "Brave.Today.LastUsageTime", - "Brave.Today.NewUserReturning", - "Brave.Today.NonRewardsAdViews", - "Brave.Today.RewardsAdViews", - "Brave.Today.SidebarFilterUsages", - "Brave.Today.WeeklySessionCount", - "Brave.Today.WeeklyTotalCardClicks", - "Brave.Today.WeeklyTotalCardViews", - "Brave.VPN.HideWidget", - "Brave.VPN.LastUsageTime", - "Brave.VPN.NewUserReturning", - "Brave.VPN.WidgetUsage", - "Brave.VerticalTabs.GroupTabs", - "Brave.VerticalTabs.OpenTabs", - "Brave.VerticalTabs.PinnedTabs", - "Brave.Wallet.ActiveBtcAccounts", - "Brave.Wallet.ActiveEthAccounts", - "Brave.Wallet.ActiveSolAccounts", - "Brave.Wallet.ActiveZecAccounts", - "Brave.Wallet.BtcTransactionSent", - "Brave.Wallet.EthTransactionSent", - "Brave.Wallet.NFTCount", - "Brave.Wallet.NewUserBalance", - "Brave.Wallet.NewUserReturning", - "Brave.Wallet.OnboardingConversion.3", - "Brave.Wallet.SolTransactionSent", - "Brave.Wallet.ZecTransactionSent", - "Brave.WebTorrent.UsageWeekly", - "Brave.Welcome.InteractionStatus.2", + {"Brave.P2A.ad_notification.impressions", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.architecture", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.artsentertainment", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.automotive", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.business", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.careers", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.cellphones", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.crypto", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.education", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.familyparenting", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.fashion", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.folklore", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.fooddrink", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.gaming", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.healthfitness", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.history", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.hobbiesinterests", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.home", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.law", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.military", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.other", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.personalfinance", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.pets", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.realestate", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.science", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.sports", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.technologycomputing", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.travel", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.untargeted", {}}, + {"Brave.P2A.ad_notification.impressions_per_segment.weather", {}}, + // Ad Opportunities + {"Brave.P2A.ad_notification.opportunities", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.architecture", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.artsentertainment", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.automotive", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.business", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.careers", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.cellphones", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.crypto", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.education", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.familyparenting", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.fashion", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.folklore", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.fooddrink", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.gaming", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.healthfitness", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.history", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.hobbiesinterests", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.home", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.law", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.military", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.other", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.personalfinance", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.pets", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.realestate", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.science", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.sports", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.technologycomputing", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.travel", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.untargeted", {}}, + {"Brave.P2A.ad_notification.opportunities_per_segment.weather", {}}, + {"Brave.P2A.inline_content_ad.impressions", {}}, + {"Brave.P2A.inline_content_ad.opportunities", {}}, + {"Brave.P2A.new_tab_page_ad.impressions", {}}, + {"Brave.P2A.new_tab_page_ad.opportunities", {}}, + {"Brave.P3A.SentAnswersCount", {}}, + {"Brave.Playlist.FirstTimeOffset", MetricConfig{.ephemeral = true}}, + {"Brave.Playlist.NewUserReturning", {}}, + {"Brave.Playlist.UsageDaysInWeek", MetricConfig{.ephemeral = true}}, + {"Brave.Rewards.AdTypesEnabled.2", {}}, + {"Brave.Rewards.AutoContributionsState.3", {}}, + {"Brave.Rewards.DesktopPanelCount", MetricConfig{.ephemeral = true}}, + {"Brave.Rewards.EnabledSource", MetricConfig{.ephemeral = true}}, + {"Brave.Rewards.MobileConversion", MetricConfig{.ephemeral = true}}, + {"Brave.Rewards.MobilePanelCount", MetricConfig{.ephemeral = true}}, + {"Brave.Rewards.SearchResultAdsOptin", MetricConfig{.ephemeral = true}}, + {"Brave.Rewards.TipsState.2", {}}, + {"Brave.Rewards.ToolbarButtonTrigger", MetricConfig{.ephemeral = true}}, + {"Brave.Rewards.WalletBalance.3", {}}, + {"Brave.Rewards.WalletState", {}}, + {"Brave.Search.GoogleWidgetUsage", MetricConfig{.ephemeral = true}}, + {"Brave.Search.Promo.BannerB", {}}, + {"Brave.Search.Promo.BannerC", {}}, + {"Brave.Search.Promo.BannerD", {}}, + {"Brave.Search.Promo.Button", {}}, + {"Brave.Search.Promo.DDGBannerA", {}}, + {"Brave.Search.Promo.DDGBannerB", {}}, + {"Brave.Search.Promo.DDGBannerC", {}}, + {"Brave.Search.Promo.DDGBannerD", {}}, + {"Brave.Search.Promo.NewTabPage", {}}, + {"Brave.Search.QueriesBeforeChurn", MetricConfig{.ephemeral = true}}, + {"Brave.Search.SwitchEngine", {}}, + {"Brave.Search.WebDiscoveryAndAds", {}}, + {"Brave.Search.WebDiscoveryEnabled", {}}, + {"Brave.Search.WidgetDefault", {}}, + {"Brave.Search.WidgetUsage", MetricConfig{.ephemeral = true}}, + {"Brave.Shields.AdBlockSetting", {}}, + {"Brave.Shields.CookieListEnabled", {}}, + {"Brave.Shields.DomainAdsSettingsAboveGlobal", {}}, + {"Brave.Shields.DomainAdsSettingsBelowGlobal", {}}, + {"Brave.Shields.FingerprintBlockSetting", {}}, + {"Brave.Shields.UsageStatus", {}}, + {"Brave.Sidebar.Enabled", {}}, + {"Brave.Sidebar.SettingChange.SidebarEnabledA", {}}, + {"Brave.Sync.JoinType", MetricConfig{.ephemeral = true}}, + {"Brave.Sync.Status.2", {}}, + {"Brave.Today.ClickCardDepth", MetricConfig{.ephemeral = true}}, + {"Brave.Today.LastUsageTime", {}}, + {"Brave.Today.NewUserReturning", {}}, + {"Brave.Today.NonRewardsAdViews", {}}, + {"Brave.Today.RewardsAdViews", {}}, + {"Brave.Today.SidebarFilterUsages", MetricConfig{.ephemeral = true}}, + {"Brave.Today.WeeklySessionCount", {}}, + {"Brave.Today.WeeklyTotalCardClicks", MetricConfig{.ephemeral = true}}, + {"Brave.Today.WeeklyTotalCardViews", {}}, + {"Brave.VPN.HideWidget", MetricConfig{.ephemeral = true}}, + {"Brave.VPN.LastUsageTime", {}}, + {"Brave.VPN.NewUserReturning", {}}, + {"Brave.VPN.WidgetUsage", MetricConfig{.ephemeral = true}}, + {"Brave.VerticalTabs.GroupTabs", MetricConfig{.ephemeral = true}}, + {"Brave.VerticalTabs.OpenTabs", MetricConfig{.ephemeral = true}}, + {"Brave.VerticalTabs.PinnedTabs", MetricConfig{.ephemeral = true}}, + {"Brave.Wallet.ActiveBtcAccounts", {}}, + {"Brave.Wallet.ActiveEthAccounts", {}}, + {"Brave.Wallet.ActiveSolAccounts", {}}, + {"Brave.Wallet.ActiveZecAccounts", {}}, + {"Brave.Wallet.BtcTransactionSent", {}}, + {"Brave.Wallet.EthTransactionSent", {}}, + {"Brave.Wallet.NFTCount", MetricConfig{.ephemeral = true}}, + {"Brave.Wallet.NewUserBalance", MetricConfig{.ephemeral = true}}, + {"Brave.Wallet.NewUserReturning", {}}, + {"Brave.Wallet.OnboardingConversion.3", MetricConfig{.ephemeral = true}}, + {"Brave.Wallet.SolTransactionSent", {}}, + {"Brave.Wallet.ZecTransactionSent", {}}, + {"Brave.WebTorrent.UsageWeekly", MetricConfig{.ephemeral = true}}, + {"Brave.Welcome.InteractionStatus.2", {}}, }); inline constexpr auto kCollectedSlowHistograms = - base::MakeFixedFlatSet(base::sorted_unique,{ - "Brave.AIChat.ContextMenu.LastUsageTime", - "Brave.AIChat.LastUsageTime", - "Brave.AIChat.UsageMonthly", - "Brave.Core.PrimaryLang", - "Brave.Core.ProfileCount", - "Brave.Core.UsageMonthly", - "Brave.P3A.TestSlowMetric", - "Brave.Playlist.LastUsageTime", - "Brave.Rewards.PageViewCount", - "Brave.Rewards.RecurringTip", - "Brave.Rewards.TipsSent.2", - "Brave.Search.SearchSuggest", - "Brave.Shields.ForgetFirstParty", - "Brave.Sync.EnabledTypes", - "Brave.Sync.SyncedObjectsCount.2", - "Brave.Today.ChannelCount.2", - "Brave.Today.DirectFeedsTotal.3", - "Brave.Today.PublisherCount.2", - "Brave.Today.UsageMonthly", - "Brave.Wallet.UsageMonthly", + base::MakeFixedFlatMap>({ + {"Brave.AIChat.ContextMenu.LastUsageTime", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.LastUsageTime", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.UsageMonthly", MetricConfig{.ephemeral = true}}, + {"Brave.Core.PrimaryLang", MetricConfig{.constellation_only = true}}, + {"Brave.Core.ProfileCount", {}}, + {"Brave.Core.UsageMonthly", {}}, + {"Brave.P3A.TestSlowMetric", {}}, + {"Brave.Playlist.LastUsageTime", {}}, + {"Brave.Rewards.PageViewCount", MetricConfig{.ephemeral = true}}, + {"Brave.Rewards.RecurringTip", MetricConfig{.ephemeral = true}}, + {"Brave.Rewards.TipsSent.2", MetricConfig{.ephemeral = true}}, + {"Brave.Search.SearchSuggest", {}}, + {"Brave.Shields.ForgetFirstParty", {}}, + {"Brave.Sync.EnabledTypes", {}}, + {"Brave.Sync.SyncedObjectsCount.2", {}}, + {"Brave.Today.ChannelCount.2", MetricConfig{.ephemeral = true}}, + {"Brave.Today.DirectFeedsTotal.3", MetricConfig{.ephemeral = true}}, + {"Brave.Today.PublisherCount.2", MetricConfig{.ephemeral = true}}, + {"Brave.Today.UsageMonthly", MetricConfig{.ephemeral = true}}, + {"Brave.Wallet.UsageMonthly", MetricConfig{.ephemeral = true}}, }); inline constexpr auto kCollectedExpressHistograms = - base::MakeFixedFlatSet(base::sorted_unique,{ - "Brave.AIChat.UsageDaily.2", - "Brave.AIChat.UsageDaily.SidebarEnabledA", - "Brave.Core.UsageDaily", - "Brave.DayZero.A.InstallTime", - "Brave.DayZero.B.InstallTime", - "Brave.Rewards.EnabledInstallationTime", - "Brave.Search.BraveDaily", - "Brave.Search.DefaultEngine.4", - "Brave.Today.IsEnabled", - "Brave.Today.UsageDaily", - "Brave.Uptime.BrowserOpenTime.2", - "Brave.Wallet.UsageDaily", - "creativeInstanceId.total.count", + base::MakeFixedFlatMap>({ + {"Brave.AIChat.UsageDaily.2", MetricConfig{.ephemeral = true}}, + {"Brave.AIChat.UsageDaily.SidebarEnabledA", MetricConfig{.ephemeral = true}}, + {"Brave.Core.UsageDaily", {}}, + {"Brave.DayZero.A.InstallTime", MetricConfig{ + .ephemeral = true, + .constellation_only = true, + .append_attributes = MetricAttributesToAppend{MetricAttribute::kRef} + }}, + {"Brave.DayZero.B.InstallTime", MetricConfig{ + .ephemeral = true, + .constellation_only = true, + .append_attributes = MetricAttributesToAppend{MetricAttribute::kRef} + }}, + {"Brave.Rewards.EnabledInstallationTime", MetricConfig{.ephemeral = true}}, + {"Brave.Search.BraveDaily", MetricConfig{.ephemeral = true}}, + {"Brave.Search.DefaultEngine.4", {}}, + {"Brave.Today.IsEnabled", MetricConfig{.ephemeral = true}}, + {"Brave.Today.UsageDaily", MetricConfig{.ephemeral = true}}, + {"Brave.Uptime.BrowserOpenTime.2", MetricConfig{.ephemeral = true}}, + {"Brave.Wallet.UsageDaily", MetricConfig{.ephemeral = true}}, + {"creativeInstanceId.total.count", {}}, }); -// List of metrics that should only be sent once per latest histogram update. -// Once the metric value has been sent, the value will be removed from the log store. -inline constexpr auto kEphemeralHistograms = - base::MakeFixedFlatSet(base::sorted_unique,{ - "Brave.AIChat.AcquisitionSource", - "Brave.AIChat.AvgPromptCount", - "Brave.AIChat.ChatCount", - "Brave.AIChat.ContextMenu.FreeUsages", - "Brave.AIChat.ContextMenu.LastUsageTime", - "Brave.AIChat.ContextMenu.MostUsedAction", - "Brave.AIChat.ContextMenu.PremiumUsages", - "Brave.AIChat.LastUsageTime", - "Brave.AIChat.MostUsedEntryPoint", - "Brave.AIChat.OmniboxOpens", - "Brave.AIChat.OmniboxWeekCompare", - "Brave.AIChat.UsageDaily.2", - "Brave.AIChat.UsageDaily.SidebarEnabledA", - "Brave.AIChat.UsageMonthly", - "Brave.AIChat.UsageWeekly", - "Brave.AIChat.UsageWeekly.SidebarEnabledA", - "Brave.Ads.ClearData", - "Brave.Core.FailedHTTPSUpgrades.2", - "Brave.Core.FirstPageLoadTime", - "Brave.DNS.AutoSecureRequests.2", - "Brave.DNS.AutoSecureRequests.Cloudflare.2", - "Brave.DNS.AutoSecureRequests.Quad9.2", - "Brave.DNS.AutoSecureRequests.Wikimedia.2", - "Brave.DayZero.A.InstallTime", - "Brave.DayZero.B.InstallTime", - "Brave.Playlist.FirstTimeOffset", - "Brave.Playlist.UsageDaysInWeek", - "Brave.Rewards.DesktopPanelCount", - "Brave.Rewards.EnabledInstallationTime", - "Brave.Rewards.EnabledSource", - "Brave.Rewards.MobileConversion", - "Brave.Rewards.MobilePanelCount", - "Brave.Rewards.PageViewCount", - "Brave.Rewards.RecurringTip", - "Brave.Rewards.SearchResultAdsOptin", - "Brave.Rewards.TipsSent.2", - "Brave.Rewards.ToolbarButtonTrigger", - "Brave.Search.BraveDaily", - "Brave.Search.GoogleWidgetUsage", - "Brave.Search.QueriesBeforeChurn", - "Brave.Search.WidgetUsage", - "Brave.Sync.JoinType", - "Brave.Today.ChannelCount.2", - "Brave.Today.ClickCardDepth", - "Brave.Today.DirectFeedsTotal.3", - "Brave.Today.IsEnabled", - "Brave.Today.PublisherCount.2", - "Brave.Today.SidebarFilterUsages", - "Brave.Today.UsageDaily", - "Brave.Today.UsageMonthly", - "Brave.Today.WeeklyTotalCardClicks", - "Brave.Uptime.BrowserOpenTime.2", - "Brave.VPN.HideWidget", - "Brave.VPN.WidgetUsage", - "Brave.VerticalTabs.GroupTabs", - "Brave.VerticalTabs.OpenTabs", - "Brave.VerticalTabs.PinnedTabs", - "Brave.Wallet.NFTCount", - "Brave.Wallet.NewUserBalance", - "Brave.Wallet.OnboardingConversion.3", - "Brave.Wallet.UsageDaily", - "Brave.Wallet.UsageMonthly", - "Brave.WebTorrent.UsageWeekly", -}); - -// List of metrics that should only be via STAR/Constellation. -// TODO(djandries): remove this once JSON deprecation is complete -inline constexpr auto kConstellationOnlyHistograms = - base::MakeFixedFlatSet(base::sorted_unique,{ - "Brave.Core.PrimaryLang", - "Brave.DayZero.A.InstallTime", - "Brave.DayZero.B.InstallTime", -}); - -// List of metrics which will include the stored refcode when transmitted -// via the STAR/Constellation protocol. -inline constexpr auto kHistogramsWithRefcodeIncluded = - base::MakeFixedFlatSet(base::sorted_unique,{ - "Brave.DayZero.A.InstallTime", - "Brave.DayZero.B.InstallTime", -}); - -// List of metrics that should be protected by Nebula. -// -// We intend to apply Nebula to all questions by default, -// subject to verification that it behaves as expected. -// This list tests a small number of questions to confirm -// this, and should be removed or converted to an exception -// list once we're satisfied with the implementation. -inline constexpr auto kNebulaOnlyHistograms = - base::MakeFixedFlatSet(base::sorted_unique,{ - "Brave.AIChat.ChatCount.Nebula", - "Brave.Core.WeeklyUsage.Nebula", -}); +} // namespace p3a // clang-format on -} // namespace p3a - #endif // BRAVE_COMPONENTS_P3A_METRIC_NAMES_H_ diff --git a/components/p3a/metric_names_unittest.cc b/components/p3a/metric_names_unittest.cc index 6ae2188fe3b2..1a98b0585c5a 100644 --- a/components/p3a/metric_names_unittest.cc +++ b/components/p3a/metric_names_unittest.cc @@ -35,12 +35,12 @@ TEST(P3AMetrics, Enumerable) { // Check that we can loop through the set members. DLOG(INFO) << "Set of collected metrics has " << size << " members:"; for (auto item : kCollectedTypicalHistograms) { - DLOG(INFO) << " " << item; + DLOG(INFO) << " " << item.first; // Each item should be a set member. - EXPECT_TRUE(kCollectedTypicalHistograms.contains(item)); + EXPECT_TRUE(kCollectedTypicalHistograms.contains(item.first)); // Each item should be different from the previous one. - EXPECT_NE(item, last); - last = std::string(item); + EXPECT_NE(item.first, last); + last = std::string(item.first); // Count the number of items. count++; } diff --git a/components/p3a/p3a_message.cc b/components/p3a/p3a_message.cc index 991b74bc10f5..ae7fead336b0 100644 --- a/components/p3a/p3a_message.cc +++ b/components/p3a/p3a_message.cc @@ -11,7 +11,6 @@ #include #include "base/containers/fixed_flat_set.h" -#include "base/containers/flat_set.h" #include "base/i18n/timezone.h" #include "base/logging.h" #include "base/strings/strcat.h" @@ -20,7 +19,8 @@ #include "base/strings/string_util.h" #include "brave/components/brave_stats/browser/brave_stats_updater_util.h" #include "brave/components/l10n/common/locale_util.h" -#include "brave/components/l10n/common/prefs.h" +#include "brave/components/p3a/metric_config.h" +#include "brave/components/p3a/region.h" #include "brave/components/p3a/uploader.h" #include "brave/components/version_info/version_info.h" #include "components/prefs/pref_service.h" @@ -37,6 +37,7 @@ constexpr char kMetricNameAttributeName[] = "metric_name"; constexpr char kMetricValueAttributeName[] = "metric_value"; constexpr char kMetricNameAndValueAttributeName[] = "metric_name_and_value"; constexpr char kPlatformAttributeName[] = "platform"; +constexpr char kGeneralPlatformAttributeName[] = "general_platform"; constexpr char kChannelAttributeName[] = "channel"; constexpr char kYosAttributeName[] = "yos"; constexpr char kWosAttributeName[] = "wos"; @@ -45,6 +46,8 @@ constexpr char kWoiAttributeName[] = "woi"; constexpr char kYoiAttributeName[] = "yoi"; constexpr char kCountryCodeAttributeName[] = "country_code"; constexpr char kVersionAttributeName[] = "version"; +constexpr char kRegionAttributeName[] = "region"; +constexpr char kSubregionAttributeName[] = "subregion"; constexpr char kCadenceAttributeName[] = "cadence"; constexpr char kRefAttributeName[] = "ref"; @@ -64,6 +67,92 @@ constexpr auto kNotableCountries = base::MakeFixedFlatSet( {"US", "FR", "PH", "GB", "IN", "DE", "BR", "CA", "IT", "ES", "NL", "MX", "AU", "RU", "JP", "PL", "ID", "KR", "AR", "AT"}); +std::vector> PopulateConstellationAttributes( + const std::string_view metric_name, + const uint64_t metric_value, + const MessageMetainfo& meta, + const std::optional& metric_config, + const std::vector& attributes_to_load, + bool is_creative) { + base::Time::Exploded exploded; + meta.date_of_install().LocalExplode(&exploded); + DCHECK_GE(exploded.year, 999); + + std::vector> attributes; + if (metric_config && metric_config->nebula) { + attributes = { + {kMetricNameAndValueAttributeName, + base::JoinString({metric_name, base::NumberToString(metric_value)}, + kP3AMessageNebulaNameValueSeparator)}}; + } else { + attributes = {{kMetricNameAttributeName, std::string(metric_name)}}; + } + std::string country_code; + for (const auto& attribute : attributes_to_load) { + switch (attribute) { + case MetricAttribute::kAnswerIndex: + if (metric_config && metric_config->nebula) { + continue; + } + attributes.push_back( + {kMetricValueAttributeName, base::NumberToString(metric_value)}); + break; + case MetricAttribute::kVersion: + if (is_creative) { + continue; + } + attributes.push_back({kVersionAttributeName, meta.version()}); + break; + case MetricAttribute::kYoi: + if (is_creative) { + continue; + } + attributes.push_back( + {kYoiAttributeName, base::NumberToString(exploded.year)}); + break; + case MetricAttribute::kChannel: + attributes.push_back({kChannelAttributeName, meta.channel()}); + break; + case MetricAttribute::kPlatform: + attributes.push_back({kPlatformAttributeName, meta.platform()}); + break; + case MetricAttribute::kCountryCode: + if (is_creative) { + country_code = meta.country_code_from_locale_raw(); + } else { + country_code = meta.GetCountryCodeForNormalMetrics( + metric_config && metric_config->disable_country_strip); + } + attributes.push_back({kCountryCodeAttributeName, country_code}); + break; + case MetricAttribute::kWoi: + if (is_creative) { + continue; + } + attributes.push_back( + {kWoiAttributeName, base::NumberToString(meta.woi())}); + break; + case MetricAttribute::kGeneralPlatform: + attributes.push_back( + {kGeneralPlatformAttributeName, meta.general_platform()}); + break; + case MetricAttribute::kRegion: + attributes.push_back({kRegionAttributeName, + std::string(meta.region_identifiers().region)}); + break; + case MetricAttribute::kSubregion: + attributes.push_back( + {kSubregionAttributeName, + std::string(meta.region_identifiers().sub_region)}); + break; + case MetricAttribute::kRef: + attributes.push_back({kRefAttributeName, meta.ref()}); + break; + } + } + return attributes; +} + } // namespace MessageMetainfo::MessageMetainfo() = default; @@ -112,7 +201,8 @@ base::Value::Dict GenerateP3AMessageDict(std::string_view metric_name, result.Set(kYoiAttributeName, install_exploded.year); // Fill meta. - result.Set(kCountryCodeAttributeName, meta.GetCountryCodeForNormalMetrics()); + result.Set(kCountryCodeAttributeName, + meta.GetCountryCodeForNormalMetrics(false)); result.Set(kVersionAttributeName, meta.version()); result.Set(kWoiAttributeName, meta.woi()); @@ -140,53 +230,34 @@ base::Value::Dict GenerateP3AMessageDict(std::string_view metric_name, return result; } -std::string GenerateP3AConstellationMessage(std::string_view metric_name, - uint64_t metric_value, - const MessageMetainfo& meta, - const std::string& upload_type, - bool include_refcode, - bool is_nebula) { - base::Time::Exploded exploded; - meta.date_of_install().LocalExplode(&exploded); - DCHECK_GE(exploded.year, 999); - - std::vector> attributes; - - std::string metric_name_str = std::string(metric_name); - std::string metric_value_str = base::NumberToString(metric_value); - - if (!is_nebula) { - attributes = {{{kMetricNameAttributeName, metric_name_str}, - {kMetricValueAttributeName, metric_value_str}}}; - } else { - attributes = {{kMetricNameAndValueAttributeName, - base::JoinString({metric_name_str, metric_value_str}, - kP3AMessageNebulaNameValueSeparator)}}; - } - - bool is_creative = upload_type == kP3ACreativeUploadType; - - if (!is_creative) { - attributes.push_back({kVersionAttributeName, meta.version()}); - attributes.push_back( - {kYoiAttributeName, base::NumberToString(exploded.year)}); - } - - attributes.push_back({kChannelAttributeName, meta.channel()}); - attributes.push_back({kPlatformAttributeName, meta.platform()}); - - if (is_creative) { - attributes.push_back( - {kCountryCodeAttributeName, meta.country_code_from_locale_raw()}); +std::string GenerateP3AConstellationMessage( + std::string_view metric_name, + uint64_t metric_value, + const MessageMetainfo& meta, + const std::string& upload_type, + const std::optional& metric_config) { + std::vector attributes_to_load; + if (metric_config && metric_config->attributes) { + for (const auto& attr : *metric_config->attributes) { + if (attr.has_value()) { + attributes_to_load.push_back(attr.value()); + } + } } else { - attributes.push_back( - {kCountryCodeAttributeName, meta.GetCountryCodeForNormalMetrics()}); - attributes.push_back({kWoiAttributeName, base::NumberToString(meta.woi())}); + attributes_to_load.assign(std::begin(kDefaultMetricAttributes), + std::end(kDefaultMetricAttributes)); + if (metric_config && !metric_config->append_attributes.empty()) { + for (const auto& attr : metric_config->append_attributes) { + if (attr.has_value()) { + attributes_to_load.push_back(attr.value()); + } + } + } } - if (include_refcode) { - attributes.push_back({kRefAttributeName, meta.ref()}); - } + auto attributes = PopulateConstellationAttributes( + metric_name, metric_value, meta, metric_config, attributes_to_load, + upload_type == kP3ACreativeUploadType); std::vector serialized_attributes(attributes.size()); @@ -205,6 +276,7 @@ void MessageMetainfo::Init(PrefService* local_state, std::string week_of_install) { local_state_ = local_state; platform_ = brave_stats::GetPlatformIdentifier(); + general_platform_ = brave_stats::GetGeneralPlatformIdentifier(); channel_ = brave_channel; InitVersion(); InitRef(); @@ -216,11 +288,15 @@ void MessageMetainfo::Init(PrefService* local_state, } woi_ = brave_stats::GetIsoWeekNumber(date_of_install_); - country_code_from_timezone_ = + country_code_from_timezone_raw_ = base::ToUpperASCII(base::CountryCodeForCurrentTimezone()); country_code_from_locale_raw_ = brave_l10n::GetDefaultISOCountryCodeString(); + country_code_from_timezone_ = country_code_from_timezone_raw_; country_code_from_locale_ = country_code_from_locale_raw_; + region_identifiers_ = + GetRegionIdentifiers(GetCountryCodeForNormalMetrics(true)); + MaybeStripCountry(); Update(); @@ -285,10 +361,17 @@ void MessageMetainfo::MaybeStripCountry() { } } -const std::string& MessageMetainfo::GetCountryCodeForNormalMetrics() const { +const std::string& MessageMetainfo::GetCountryCodeForNormalMetrics( + bool raw) const { #if BUILDFLAG(IS_IOS) + if (raw) { + return country_code_from_locale_raw_; + } return country_code_from_locale_; #else + if (raw) { + return country_code_from_timezone_raw_; + } return country_code_from_timezone_; #endif // BUILDFLAG(IS_IOS) } diff --git a/components/p3a/p3a_message.h b/components/p3a/p3a_message.h index 4e6b618c68f9..16eba10dfa9a 100644 --- a/components/p3a/p3a_message.h +++ b/components/p3a/p3a_message.h @@ -12,7 +12,9 @@ #include "base/time/time.h" #include "base/values.h" +#include "brave/components/p3a/metric_config.h" #include "brave/components/p3a/metric_log_type.h" +#include "brave/components/p3a/region.h" class PrefService; @@ -33,15 +35,19 @@ class MessageMetainfo { void Update(); - const std::string& GetCountryCodeForNormalMetrics() const; + const std::string& GetCountryCodeForNormalMetrics(bool raw) const; const std::string& platform() const { return platform_; } + const std::string& general_platform() const { return general_platform_; } const std::string& channel() const { return channel_; } const std::string& version() const { return version_; } const std::string& country_code_from_locale_raw() const { return country_code_from_locale_raw_; } const std::string& ref() const { return ref_; } + const RegionIdentifiers& region_identifiers() const { + return region_identifiers_; + } base::Time date_of_install() const { return date_of_install_; } base::Time date_of_survey() const { return date_of_survey_; } int woi() const { return woi_; } @@ -59,6 +65,7 @@ class MessageMetainfo { void MaybeStripCountry(); std::string platform_; + std::string general_platform_; std::string version_; std::string channel_; base::Time date_of_install_; @@ -66,8 +73,10 @@ class MessageMetainfo { int woi_; // Week of install. Remove this occasionally and extract from // above. std::string country_code_from_timezone_; + std::string country_code_from_timezone_raw_; std::string country_code_from_locale_; std::string country_code_from_locale_raw_; + RegionIdentifiers region_identifiers_; // May contain 'none', a 'BRV'-prefixed refcode, or 'other'. std::string ref_; @@ -80,12 +89,12 @@ base::Value::Dict GenerateP3AMessageDict(std::string_view metric_name, const MessageMetainfo& meta, const std::string& upload_type); -std::string GenerateP3AConstellationMessage(std::string_view metric_name, - uint64_t metric_value, - const MessageMetainfo& meta, - const std::string& upload_type, - bool include_refcode, - bool is_nebula); +std::string GenerateP3AConstellationMessage( + std::string_view metric_name, + uint64_t metric_value, + const MessageMetainfo& meta, + const std::string& upload_type, + const std::optional& metric_config); } // namespace p3a diff --git a/components/p3a/p3a_service.cc b/components/p3a/p3a_service.cc index 7157e4cdece4..ddca9d736e2b 100644 --- a/components/p3a/p3a_service.cc +++ b/components/p3a/p3a_service.cc @@ -109,15 +109,13 @@ void P3AService::InitCallback(std::string_view histogram_name) { } void P3AService::InitCallbacks() { - for (const std::string_view histogram_name : - p3a::kCollectedTypicalHistograms) { + for (const auto& [histogram_name, _] : p3a::kCollectedTypicalHistograms) { InitCallback(histogram_name); } - for (const std::string_view histogram_name : - p3a::kCollectedExpressHistograms) { + for (const auto& [histogram_name, _] : p3a::kCollectedExpressHistograms) { InitCallback(histogram_name); } - for (const std::string_view histogram_name : p3a::kCollectedSlowHistograms) { + for (const auto& [histogram_name, _] : p3a::kCollectedSlowHistograms) { InitCallback(histogram_name); } for (const auto& [histogram_name, log_type] : dynamic_metric_log_types_) { @@ -315,7 +313,8 @@ void P3AService::HandleHistogramChange( only_update_for_constellation); return; } - if (kConstellationOnlyHistograms.contains(histogram_name)) { + const auto* metric_config = message_manager_->GetMetricConfig(histogram_name); + if (metric_config && *metric_config && (*metric_config)->constellation_only) { only_update_for_constellation = true; } message_manager_->UpdateMetricValue(std::string(histogram_name), bucket, diff --git a/components/p3a/p3a_service_unittest.cc b/components/p3a/p3a_service_unittest.cc index 332188b9cc0a..637811c2b0fb 100644 --- a/components/p3a/p3a_service_unittest.cc +++ b/components/p3a/p3a_service_unittest.cc @@ -104,16 +104,15 @@ class P3AServiceTest : public testing::Test { std::vector result; size_t p3a_i = 0; size_t p2a_i = 0; - for (const std::string_view histogram_name : - p3a::kCollectedTypicalHistograms) { - if (histogram_name.rfind(kP2APrefix, 0) == 0) { + for (const auto& histogram_pair : p3a::kCollectedTypicalHistograms) { + if (histogram_pair.first.rfind(kP2APrefix, 0) == 0) { if (p2a_i < p2a_count) { - result.push_back(std::string(histogram_name)); + result.push_back(std::string(histogram_pair.first)); p2a_i++; } } else if (p3a_i < p3a_count && - histogram_name.starts_with("Brave.Core")) { - result.push_back(std::string(histogram_name)); + histogram_pair.first.starts_with("Brave.Core")) { + result.push_back(std::string(histogram_pair.first)); p3a_i++; } diff --git a/components/p3a/region.cc b/components/p3a/region.cc new file mode 100644 index 000000000000..235ead8ce13a --- /dev/null +++ b/components/p3a/region.cc @@ -0,0 +1,350 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/p3a/region.h" + +#include + +#include "base/containers/fixed_flat_map.h" + +namespace p3a { + +namespace { + +constexpr char kOtherIdentifier[] = "other"; + +enum class Region { + kAsia, + kEurope, + kAfrica, + kOceania, + kAmericas, +}; + +enum class Subregion { + kSouthernAsia, + kNorthernEurope, + kSouthernEurope, + kNorthernAfrica, + kSubSaharanAfrica, + kLatinAmericaAndTheCaribbean, + kWesternAsia, + kWesternEurope, + kEasternEurope, + kNorthernAmerica, + kSoutheasternAsia, + kEasternAsia, + kOceania, + kCentralAsia, +}; + +inline constexpr auto kCountryRegions = + base::MakeFixedFlatMap>({ + {"AF", {Region::kAsia, Subregion::kSouthernAsia}}, + {"AX", {Region::kEurope, Subregion::kNorthernEurope}}, + {"AL", {Region::kEurope, Subregion::kSouthernEurope}}, + {"DZ", {Region::kAfrica, Subregion::kNorthernAfrica}}, + {"AS", {Region::kOceania, Subregion::kOceania}}, + {"AD", {Region::kEurope, Subregion::kSouthernEurope}}, + {"AO", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"AI", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"AG", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"AR", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"AM", {Region::kAsia, Subregion::kWesternAsia}}, + {"AW", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"AU", {Region::kOceania, Subregion::kOceania}}, + {"AT", {Region::kEurope, Subregion::kWesternEurope}}, + {"AZ", {Region::kAsia, Subregion::kWesternAsia}}, + {"BS", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"BH", {Region::kAsia, Subregion::kWesternAsia}}, + {"BD", {Region::kAsia, Subregion::kSouthernAsia}}, + {"BB", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"BY", {Region::kEurope, Subregion::kEasternEurope}}, + {"BE", {Region::kEurope, Subregion::kWesternEurope}}, + {"BZ", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"BJ", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"BM", {Region::kAmericas, Subregion::kNorthernAmerica}}, + {"BT", {Region::kAsia, Subregion::kSouthernAsia}}, + {"BO", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"BQ", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"BA", {Region::kEurope, Subregion::kSouthernEurope}}, + {"BW", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"BV", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"BR", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"IO", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"BN", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"BG", {Region::kEurope, Subregion::kEasternEurope}}, + {"BF", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"BI", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"CV", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"KH", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"CM", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"CA", {Region::kAmericas, Subregion::kNorthernAmerica}}, + {"KY", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"CF", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"TD", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"CL", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"CN", {Region::kAsia, Subregion::kEasternAsia}}, + {"CX", {Region::kOceania, Subregion::kOceania}}, + {"CC", {Region::kOceania, Subregion::kOceania}}, + {"CO", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"KM", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"CG", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"CD", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"CK", {Region::kOceania, Subregion::kOceania}}, + {"CR", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"CI", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"HR", {Region::kEurope, Subregion::kSouthernEurope}}, + {"CU", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"CW", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"CY", {Region::kAsia, Subregion::kWesternAsia}}, + {"CZ", {Region::kEurope, Subregion::kEasternEurope}}, + {"DK", {Region::kEurope, Subregion::kNorthernEurope}}, + {"DJ", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"DM", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"DO", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"EC", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"EG", {Region::kAfrica, Subregion::kNorthernAfrica}}, + {"SV", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"GQ", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"ER", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"EE", {Region::kEurope, Subregion::kNorthernEurope}}, + {"SZ", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"ET", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"FK", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"FO", {Region::kEurope, Subregion::kNorthernEurope}}, + {"FJ", {Region::kOceania, Subregion::kOceania}}, + {"FI", {Region::kEurope, Subregion::kNorthernEurope}}, + {"FR", {Region::kEurope, Subregion::kWesternEurope}}, + {"GF", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"PF", {Region::kOceania, Subregion::kOceania}}, + {"TF", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"GA", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"GM", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"GE", {Region::kAsia, Subregion::kWesternAsia}}, + {"DE", {Region::kEurope, Subregion::kWesternEurope}}, + {"GH", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"GI", {Region::kEurope, Subregion::kSouthernEurope}}, + {"GR", {Region::kEurope, Subregion::kSouthernEurope}}, + {"GL", {Region::kAmericas, Subregion::kNorthernAmerica}}, + {"GD", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"GP", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"GU", {Region::kOceania, Subregion::kOceania}}, + {"GT", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"GG", {Region::kEurope, Subregion::kNorthernEurope}}, + {"GN", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"GW", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"GY", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"HT", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"HM", {Region::kOceania, Subregion::kOceania}}, + {"VA", {Region::kEurope, Subregion::kSouthernEurope}}, + {"HN", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"HK", {Region::kAsia, Subregion::kEasternAsia}}, + {"HU", {Region::kEurope, Subregion::kEasternEurope}}, + {"IS", {Region::kEurope, Subregion::kNorthernEurope}}, + {"IN", {Region::kAsia, Subregion::kSouthernAsia}}, + {"ID", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"IR", {Region::kAsia, Subregion::kSouthernAsia}}, + {"IQ", {Region::kAsia, Subregion::kWesternAsia}}, + {"IE", {Region::kEurope, Subregion::kNorthernEurope}}, + {"IM", {Region::kEurope, Subregion::kNorthernEurope}}, + {"IL", {Region::kAsia, Subregion::kWesternAsia}}, + {"IT", {Region::kEurope, Subregion::kSouthernEurope}}, + {"JM", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"JP", {Region::kAsia, Subregion::kEasternAsia}}, + {"JE", {Region::kEurope, Subregion::kNorthernEurope}}, + {"JO", {Region::kAsia, Subregion::kWesternAsia}}, + {"KZ", {Region::kAsia, Subregion::kCentralAsia}}, + {"KE", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"KI", {Region::kOceania, Subregion::kOceania}}, + {"KP", {Region::kAsia, Subregion::kEasternAsia}}, + {"KR", {Region::kAsia, Subregion::kEasternAsia}}, + {"KW", {Region::kAsia, Subregion::kWesternAsia}}, + {"KG", {Region::kAsia, Subregion::kCentralAsia}}, + {"LA", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"LV", {Region::kEurope, Subregion::kNorthernEurope}}, + {"LB", {Region::kAsia, Subregion::kWesternAsia}}, + {"LS", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"LR", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"LY", {Region::kAfrica, Subregion::kNorthernAfrica}}, + {"LI", {Region::kEurope, Subregion::kWesternEurope}}, + {"LT", {Region::kEurope, Subregion::kNorthernEurope}}, + {"LU", {Region::kEurope, Subregion::kWesternEurope}}, + {"MO", {Region::kAsia, Subregion::kEasternAsia}}, + {"MG", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"MW", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"MY", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"MV", {Region::kAsia, Subregion::kSouthernAsia}}, + {"ML", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"MT", {Region::kEurope, Subregion::kSouthernEurope}}, + {"MH", {Region::kOceania, Subregion::kOceania}}, + {"MQ", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"MR", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"MU", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"YT", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"MX", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"FM", {Region::kOceania, Subregion::kOceania}}, + {"MD", {Region::kEurope, Subregion::kEasternEurope}}, + {"MC", {Region::kEurope, Subregion::kWesternEurope}}, + {"MN", {Region::kAsia, Subregion::kEasternAsia}}, + {"ME", {Region::kEurope, Subregion::kSouthernEurope}}, + {"MS", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"MA", {Region::kAfrica, Subregion::kNorthernAfrica}}, + {"MZ", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"MM", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"NA", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"NR", {Region::kOceania, Subregion::kOceania}}, + {"NP", {Region::kAsia, Subregion::kSouthernAsia}}, + {"NL", {Region::kEurope, Subregion::kWesternEurope}}, + {"NC", {Region::kOceania, Subregion::kOceania}}, + {"NZ", {Region::kOceania, Subregion::kOceania}}, + {"NI", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"NE", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"NG", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"NU", {Region::kOceania, Subregion::kOceania}}, + {"NF", {Region::kOceania, Subregion::kOceania}}, + {"MK", {Region::kEurope, Subregion::kSouthernEurope}}, + {"MP", {Region::kOceania, Subregion::kOceania}}, + {"NO", {Region::kEurope, Subregion::kNorthernEurope}}, + {"OM", {Region::kAsia, Subregion::kWesternAsia}}, + {"PK", {Region::kAsia, Subregion::kSouthernAsia}}, + {"PW", {Region::kOceania, Subregion::kOceania}}, + {"PS", {Region::kAsia, Subregion::kWesternAsia}}, + {"PA", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"PG", {Region::kOceania, Subregion::kOceania}}, + {"PY", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"PE", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"PH", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"PN", {Region::kOceania, Subregion::kOceania}}, + {"PL", {Region::kEurope, Subregion::kEasternEurope}}, + {"PT", {Region::kEurope, Subregion::kSouthernEurope}}, + {"PR", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"QA", {Region::kAsia, Subregion::kWesternAsia}}, + {"RE", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"RO", {Region::kEurope, Subregion::kEasternEurope}}, + {"RU", {Region::kEurope, Subregion::kEasternEurope}}, + {"RW", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"BL", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"SH", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"KN", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"LC", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"MF", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"PM", {Region::kAmericas, Subregion::kNorthernAmerica}}, + {"VC", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"WS", {Region::kOceania, Subregion::kOceania}}, + {"SM", {Region::kEurope, Subregion::kSouthernEurope}}, + {"ST", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"SA", {Region::kAsia, Subregion::kWesternAsia}}, + {"SN", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"RS", {Region::kEurope, Subregion::kSouthernEurope}}, + {"SC", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"SL", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"SG", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"SX", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"SK", {Region::kEurope, Subregion::kEasternEurope}}, + {"SI", {Region::kEurope, Subregion::kSouthernEurope}}, + {"SB", {Region::kOceania, Subregion::kOceania}}, + {"SO", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"ZA", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"GS", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"SS", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"ES", {Region::kEurope, Subregion::kSouthernEurope}}, + {"LK", {Region::kAsia, Subregion::kSouthernAsia}}, + {"SD", {Region::kAfrica, Subregion::kNorthernAfrica}}, + {"SR", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"SJ", {Region::kEurope, Subregion::kNorthernEurope}}, + {"SE", {Region::kEurope, Subregion::kNorthernEurope}}, + {"CH", {Region::kEurope, Subregion::kWesternEurope}}, + {"SY", {Region::kAsia, Subregion::kWesternAsia}}, + {"TW", {Region::kAsia, Subregion::kEasternAsia}}, + {"TJ", {Region::kAsia, Subregion::kCentralAsia}}, + {"TZ", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"TH", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"TL", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"TG", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"TK", {Region::kOceania, Subregion::kOceania}}, + {"TO", {Region::kOceania, Subregion::kOceania}}, + {"TT", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"TN", {Region::kAfrica, Subregion::kNorthernAfrica}}, + {"TR", {Region::kAsia, Subregion::kWesternAsia}}, + {"TM", {Region::kAsia, Subregion::kCentralAsia}}, + {"TC", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"TV", {Region::kOceania, Subregion::kOceania}}, + {"UG", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"UA", {Region::kEurope, Subregion::kEasternEurope}}, + {"AE", {Region::kAsia, Subregion::kWesternAsia}}, + {"GB", {Region::kEurope, Subregion::kNorthernEurope}}, + {"US", {Region::kAmericas, Subregion::kNorthernAmerica}}, + {"UM", {Region::kOceania, Subregion::kOceania}}, + {"UY", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"UZ", {Region::kAsia, Subregion::kCentralAsia}}, + {"VU", {Region::kOceania, Subregion::kOceania}}, + {"VE", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"VN", {Region::kAsia, Subregion::kSoutheasternAsia}}, + {"VG", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"VI", {Region::kAmericas, Subregion::kLatinAmericaAndTheCaribbean}}, + {"WF", {Region::kOceania, Subregion::kOceania}}, + {"EH", {Region::kAfrica, Subregion::kNorthernAfrica}}, + {"YE", {Region::kAsia, Subregion::kWesternAsia}}, + {"ZM", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + {"ZW", {Region::kAfrica, Subregion::kSubSaharanAfrica}}, + }); + +inline constexpr auto kRegionToString = + base::MakeFixedFlatMap({ + {Region::kAsia, "asia"}, + {Region::kEurope, "europe"}, + {Region::kAfrica, "africa"}, + {Region::kOceania, "oceania"}, + {Region::kAmericas, "americas"}, + }); + +inline constexpr auto kSubregionToString = + base::MakeFixedFlatMap({ + {Subregion::kSouthernAsia, "southern-asia"}, + {Subregion::kNorthernEurope, "northern-europe"}, + {Subregion::kSouthernEurope, "southern-europe"}, + {Subregion::kNorthernAfrica, "northern-africa"}, + {Subregion::kSubSaharanAfrica, "subsaharan-africa"}, + {Subregion::kLatinAmericaAndTheCaribbean, "latin-america-caribbean"}, + {Subregion::kWesternAsia, "western-asia"}, + {Subregion::kWesternEurope, "western-europe"}, + {Subregion::kEasternEurope, "eastern-europe"}, + {Subregion::kNorthernAmerica, "northern-america"}, + {Subregion::kSoutheasternAsia, "southeastern-asia"}, + {Subregion::kEasternAsia, "eastern-asia"}, + {Subregion::kOceania, "oceania"}, + {Subregion::kCentralAsia, "central-asia"}, + }); + +} // namespace + +RegionIdentifiers GetRegionIdentifiers(std::string_view country_code) { + auto region_data = kCountryRegions.find(country_code); + + if (region_data == kCountryRegions.end()) { + return {kOtherIdentifier, kOtherIdentifier}; + } + + auto region_str_it = kRegionToString.find(region_data->second.first); + auto subregion_str_it = kSubregionToString.find(region_data->second.second); + + std::string_view region_str; + std::string_view subregion_str; + if (region_str_it == kRegionToString.end()) { + region_str = kOtherIdentifier; + } else { + region_str = region_str_it->second; + } + if (subregion_str_it == kSubregionToString.end()) { + subregion_str = kOtherIdentifier; + } else { + subregion_str = subregion_str_it->second; + } + + return {region_str, subregion_str}; +} + +} // namespace p3a diff --git a/components/p3a/region.h b/components/p3a/region.h new file mode 100644 index 000000000000..94cc58bbd93a --- /dev/null +++ b/components/p3a/region.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_P3A_REGION_H_ +#define BRAVE_COMPONENTS_P3A_REGION_H_ + +#include + +namespace p3a { + +struct RegionIdentifiers { + std::string_view region; + std::string_view sub_region; +}; + +RegionIdentifiers GetRegionIdentifiers(std::string_view country_code); + +} // namespace p3a + +#endif // BRAVE_COMPONENTS_P3A_REGION_H_ diff --git a/components/p3a/region_unittest.cc b/components/p3a/region_unittest.cc new file mode 100644 index 000000000000..4b49d9d380ab --- /dev/null +++ b/components/p3a/region_unittest.cc @@ -0,0 +1,59 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/p3a/region.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace p3a { + +TEST(P3ARegionTest, GetRegionIdentifiers) { + // Test valid country codes + { + auto result = GetRegionIdentifiers("US"); + EXPECT_EQ(result.region, "americas"); + EXPECT_EQ(result.sub_region, "northern-america"); + } + + { + auto result = GetRegionIdentifiers("IN"); + EXPECT_EQ(result.region, "asia"); + EXPECT_EQ(result.sub_region, "southern-asia"); + } + + { + auto result = GetRegionIdentifiers("FR"); + EXPECT_EQ(result.region, "europe"); + EXPECT_EQ(result.sub_region, "western-europe"); + } + + { + auto result = GetRegionIdentifiers("AU"); + EXPECT_EQ(result.region, "oceania"); + EXPECT_EQ(result.sub_region, "oceania"); + } + + { + auto result = GetRegionIdentifiers("ZA"); + EXPECT_EQ(result.region, "africa"); + EXPECT_EQ(result.sub_region, "subsaharan-africa"); + } + + // Test invalid country code + { + auto result = GetRegionIdentifiers("XX"); + EXPECT_EQ(result.region, "other"); + EXPECT_EQ(result.sub_region, "other"); + } + + // Test empty country code + { + auto result = GetRegionIdentifiers(""); + EXPECT_EQ(result.region, "other"); + EXPECT_EQ(result.sub_region, "other"); + } +} + +} // namespace p3a