From e1427279b333e17fffd3959adff577abffc95cf9 Mon Sep 17 00:00:00 2001 From: Darnell Andries Date: Fri, 26 May 2023 12:26:56 -0700 Subject: [PATCH] Add P3A metrics for Android Privacy Hub report --- android/brave_java_sources.gni | 1 + .../chrome/browser/app/BraveActivity.java | 20 ++++++ .../browser/brave_stats/BraveStatsUtil.java | 5 +- .../PrivacyHubMetricsFactory.java | 51 ++++++++++++++ .../onboarding/OnboardingPrefManager.java | 11 +++ browser/brave_browser_process.h | 2 + browser/brave_browser_process_impl.cc | 10 +++ browser/brave_browser_process_impl.h | 3 + browser/brave_local_state_prefs.cc | 2 + .../privacy_hub_metrics_factory_android.cc | 21 ++++++ browser/misc_metrics/sources.gni | 3 + browser/sources.gni | 1 + build/android/BUILD.gn | 1 + build/android/config.gni | 1 + components/misc_metrics/BUILD.gn | 4 ++ components/misc_metrics/common/BUILD.gn | 12 ++++ .../misc_metrics/common/misc_metrics.mojom | 15 ++++ components/misc_metrics/pref_names.cc | 2 + components/misc_metrics/pref_names.h | 1 + .../misc_metrics/privacy_hub_metrics.cc | 70 +++++++++++++++++++ components/misc_metrics/privacy_hub_metrics.h | 60 ++++++++++++++++ .../privacy_hub_metrics_unittest.cc | 50 +++++++++++++ components/p3a/metric_names.h | 3 + test/BUILD.gn | 1 + test/base/testing_brave_browser_process.cc | 6 ++ test/base/testing_brave_browser_process.h | 1 + 26 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 android/java/org/chromium/chrome/browser/misc_metrics/PrivacyHubMetricsFactory.java create mode 100644 browser/misc_metrics/privacy_hub_metrics_factory_android.cc create mode 100644 components/misc_metrics/common/BUILD.gn create mode 100644 components/misc_metrics/common/misc_metrics.mojom create mode 100644 components/misc_metrics/privacy_hub_metrics.cc create mode 100644 components/misc_metrics/privacy_hub_metrics.h create mode 100644 components/misc_metrics/privacy_hub_metrics_unittest.cc diff --git a/android/brave_java_sources.gni b/android/brave_java_sources.gni index 6b2f1e1a367..0e21a428463 100644 --- a/android/brave_java_sources.gni +++ b/android/brave_java_sources.gni @@ -237,6 +237,7 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/local_database/DisplayAdsTable.java", "../../brave/android/java/org/chromium/chrome/browser/local_database/SavedBandwidthTable.java", "../../brave/android/java/org/chromium/chrome/browser/local_database/TopSiteTable.java", + "../../brave/android/java/org/chromium/chrome/browser/misc_metrics/PrivacyHubMetricsFactory.java", "../../brave/android/java/org/chromium/chrome/browser/night_mode/settings/BraveRadioButtonGroupThemePreference.java", "../../brave/android/java/org/chromium/chrome/browser/night_mode/settings/BraveThemePreferences.java", "../../brave/android/java/org/chromium/chrome/browser/notifications/BraveNotificationPlatformBridge.java", diff --git a/android/java/org/chromium/chrome/browser/app/BraveActivity.java b/android/java/org/chromium/chrome/browser/app/BraveActivity.java index 5a2516bfb50..0a155c2a36b 100644 --- a/android/java/org/chromium/chrome/browser/app/BraveActivity.java +++ b/android/java/org/chromium/chrome/browser/app/BraveActivity.java @@ -109,6 +109,7 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.fullscreen.BrowserControlsManager; import org.chromium.chrome.browser.informers.BraveAndroidSyncDisabledInformer; import org.chromium.chrome.browser.informers.BraveSyncAccountDeletedInformer; +import org.chromium.chrome.browser.misc_metrics.PrivacyHubMetricsFactory; import org.chromium.chrome.browser.notifications.BraveNotificationWarningDialog; import org.chromium.chrome.browser.notifications.BravePermissionUtils; import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController; @@ -184,6 +185,7 @@ import org.chromium.components.safe_browsing.BraveSafeBrowsingApiHandler; import org.chromium.components.search_engines.TemplateUrl; import org.chromium.components.user_prefs.UserPrefs; import org.chromium.content_public.browser.WebContents; +import org.chromium.misc_metrics.mojom.PrivacyHubMetrics; import org.chromium.mojo.bindings.ConnectionErrorHandler; import org.chromium.mojo.system.MojoException; import org.chromium.ui.widget.Toast; @@ -247,6 +249,7 @@ public abstract class BraveActivity extends C private BraveWalletService mBraveWalletService; private KeyringService mKeyringService; private JsonRpcService mJsonRpcService; + private PrivacyHubMetrics mPrivacyHubMetrics; private SwapService mSwapService; private WalletModel mWalletModel; private BlockchainRegistry mBlockchainRegistry; @@ -1314,6 +1317,10 @@ public abstract class BraveActivity extends C startActivity(braveWalletIntent); } + public PrivacyHubMetrics getPrivacyHubMetrics() { + return mPrivacyHubMetrics; + } + private void checkForYandexSE() { String countryCode = Locale.getDefault().getCountry(); if (yandexRegions.contains(countryCode)) { @@ -1970,6 +1977,16 @@ public abstract class BraveActivity extends C mAssetRatioService = AssetRatioServiceFactory.getInstance().getAssetRatioService(this); } + private void initPrivacyHubMetrics() { + if (mPrivacyHubMetrics != null) { + return; + } + + mPrivacyHubMetrics = PrivacyHubMetricsFactory.getInstance().getMetricsService(this); + mPrivacyHubMetrics.recordEnabledStatus( + OnboardingPrefManager.getInstance().isBraveStatsEnabled()); + } + private void initSwapService() { if (mSwapService != null) { return; @@ -1986,6 +2003,7 @@ public abstract class BraveActivity extends C InitBraveWalletService(); InitKeyringService(); InitJsonRpcService(); + initPrivacyHubMetrics(); initSwapService(); setupWalletModel(); } @@ -1999,6 +2017,7 @@ public abstract class BraveActivity extends C if (mTxService != null) mTxService.close(); if (mEthTxManagerProxy != null) mEthTxManagerProxy.close(); if (mSolanaTxManagerProxy != null) mSolanaTxManagerProxy.close(); + if (mPrivacyHubMetrics != null) mPrivacyHubMetrics.close(); if (mBraveWalletService != null) mBraveWalletService.close(); mKeyringService = null; mBlockchainRegistry = null; @@ -2007,6 +2026,7 @@ public abstract class BraveActivity extends C mEthTxManagerProxy = null; mSolanaTxManagerProxy = null; mAssetRatioService = null; + mPrivacyHubMetrics = null; mBraveWalletService = null; } diff --git a/android/java/org/chromium/chrome/browser/brave_stats/BraveStatsUtil.java b/android/java/org/chromium/chrome/browser/brave_stats/BraveStatsUtil.java index f847bcd78c7..57e2b9008e5 100644 --- a/android/java/org/chromium/chrome/browser/brave_stats/BraveStatsUtil.java +++ b/android/java/org/chromium/chrome/browser/brave_stats/BraveStatsUtil.java @@ -103,11 +103,12 @@ public class BraveStatsUtil { public static void showBraveStats() { try { + BraveActivity activity = BraveActivity.getBraveActivity(); BraveStatsBottomSheetDialogFragment braveStatsBottomSheetDialogFragment = BraveStatsBottomSheetDialogFragment.newInstance(); braveStatsBottomSheetDialogFragment.show( - BraveActivity.getBraveActivity().getSupportFragmentManager(), - STATS_FRAGMENT_TAG); + activity.getSupportFragmentManager(), STATS_FRAGMENT_TAG); + activity.getPrivacyHubMetrics().recordView(); } catch (BraveActivity.BraveActivityNotFoundException e) { Log.e(TAG, "showBraveStats " + e); } diff --git a/android/java/org/chromium/chrome/browser/misc_metrics/PrivacyHubMetricsFactory.java b/android/java/org/chromium/chrome/browser/misc_metrics/PrivacyHubMetricsFactory.java new file mode 100644 index 00000000000..2b491dc3483 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/misc_metrics/PrivacyHubMetricsFactory.java @@ -0,0 +1,51 @@ +/* Copyright (c) 2023 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/. */ + +package org.chromium.chrome.browser.misc_metrics; + +import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; +import org.chromium.misc_metrics.mojom.PrivacyHubMetrics; +import org.chromium.mojo.bindings.ConnectionErrorHandler; +import org.chromium.mojo.bindings.Interface; +import org.chromium.mojo.bindings.Interface.Proxy.Handler; +import org.chromium.mojo.system.MessagePipeHandle; +import org.chromium.mojo.system.impl.CoreImpl; + +@JNINamespace("chrome::android") +public class PrivacyHubMetricsFactory { + private static final Object lock = new Object(); + private static PrivacyHubMetricsFactory instance; + + public static PrivacyHubMetricsFactory getInstance() { + synchronized (lock) { + if (instance == null) { + instance = new PrivacyHubMetricsFactory(); + } + } + return instance; + } + + private PrivacyHubMetricsFactory() {} + + public PrivacyHubMetrics getMetricsService(ConnectionErrorHandler connectionErrorHandler) { + long nativeHandle = PrivacyHubMetricsFactoryJni.get().getInterfaceToPrivacyHubMetrics(); + MessagePipeHandle handle = wrapNativeHandle(nativeHandle); + PrivacyHubMetrics metricsService = PrivacyHubMetrics.MANAGER.attachProxy(handle, 0); + Handler handler = ((Interface.Proxy) metricsService).getProxyHandler(); + handler.setErrorHandler(connectionErrorHandler); + + return metricsService; + } + + private MessagePipeHandle wrapNativeHandle(long nativeHandle) { + return CoreImpl.getInstance().acquireNativeHandle(nativeHandle).toMessagePipeHandle(); + } + + @NativeMethods + interface Natives { + long getInterfaceToPrivacyHubMetrics(); + } +} diff --git a/android/java/org/chromium/chrome/browser/onboarding/OnboardingPrefManager.java b/android/java/org/chromium/chrome/browser/onboarding/OnboardingPrefManager.java index 847688a1356..370a9adb079 100644 --- a/android/java/org/chromium/chrome/browser/onboarding/OnboardingPrefManager.java +++ b/android/java/org/chromium/chrome/browser/onboarding/OnboardingPrefManager.java @@ -12,7 +12,10 @@ import android.content.Intent; import android.content.SharedPreferences; import org.chromium.base.ContextUtils; +import org.chromium.base.Log; import org.chromium.chrome.browser.BraveAdsNativeHelper; +import org.chromium.chrome.browser.app.BraveActivity; +import org.chromium.chrome.browser.app.BraveActivity.BraveActivityNotFoundException; import org.chromium.chrome.browser.notifications.BraveOnboardingNotification; import org.chromium.chrome.browser.notifications.retention.RetentionNotificationUtil; import org.chromium.chrome.browser.profiles.Profile; @@ -27,6 +30,8 @@ import java.util.Map; * Provides information regarding onboarding. */ public class OnboardingPrefManager { + private static final String TAG = "OnboardingPrefMgr"; + private static final String PREF_ONBOARDING = "onboarding"; private static final String PREF_P3A_ONBOARDING = "p3a_onboarding"; private static final String PREF_CROSS_PROMO_MODAL = "cross_promo_modal"; @@ -173,6 +178,12 @@ public class OnboardingPrefManager { SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit(); sharedPreferencesEditor.putBoolean(PREF_BRAVE_STATS, enabled); sharedPreferencesEditor.apply(); + try { + BraveActivity activity = BraveActivity.getBraveActivity(); + activity.getPrivacyHubMetrics().recordEnabledStatus(enabled); + } catch (BraveActivityNotFoundException e) { + Log.e(TAG, "Could not report privacy hub enabled change to P3A: " + e); + } } public boolean isBraveStatsNotificationEnabled() { diff --git a/browser/brave_browser_process.h b/browser/brave_browser_process.h index 8e03d199e68..be4dea40714 100644 --- a/browser/brave_browser_process.h +++ b/browser/brave_browser_process.h @@ -65,6 +65,7 @@ class LocalhostPermissionComponent; namespace misc_metrics { class MenuMetrics; +class PrivacyHubMetrics; } // namespace misc_metrics namespace request_otr { @@ -148,6 +149,7 @@ class BraveBrowserProcess { virtual brave_ads::ResourceComponent* resource_component() = 0; virtual brave::BraveFarblingService* brave_farbling_service() = 0; virtual misc_metrics::MenuMetrics* menu_metrics() = 0; + virtual misc_metrics::PrivacyHubMetrics* privacy_hub_metrics() = 0; }; extern BraveBrowserProcess* g_brave_browser_process; diff --git a/browser/brave_browser_process_impl.cc b/browser/brave_browser_process_impl.cc index e6563bd9082..54bedbe2563 100644 --- a/browser/brave_browser_process_impl.cc +++ b/browser/brave_browser_process_impl.cc @@ -39,6 +39,7 @@ #include "brave/components/https_upgrade_exceptions/browser/https_upgrade_exceptions_service.h" #include "brave/components/localhost_permission/localhost_permission_component.h" #include "brave/components/misc_metrics/menu_metrics.h" +#include "brave/components/misc_metrics/privacy_hub_metrics.h" #include "brave/components/ntp_background_images/browser/ntp_background_images_service.h" #include "brave/components/p3a/buildflags.h" #include "brave/components/p3a/histograms_braveizer.h" @@ -533,3 +534,12 @@ misc_metrics::MenuMetrics* BraveBrowserProcessImpl::menu_metrics() { #endif return menu_metrics_.get(); } + +misc_metrics::PrivacyHubMetrics* +BraveBrowserProcessImpl::privacy_hub_metrics() { + if (!privacy_hub_metrics_) { + privacy_hub_metrics_ = + std::make_unique(local_state()); + } + return privacy_hub_metrics_.get(); +} diff --git a/browser/brave_browser_process_impl.h b/browser/brave_browser_process_impl.h index 6b76482cb7a..fd4e816f98e 100644 --- a/browser/brave_browser_process_impl.h +++ b/browser/brave_browser_process_impl.h @@ -60,6 +60,7 @@ class DebounceComponentInstaller; namespace misc_metrics { class MenuMetrics; +class PrivacyHubMetrics; } // namespace misc_metrics namespace request_otr { @@ -153,6 +154,7 @@ class BraveBrowserProcessImpl : public BraveBrowserProcess, #endif brave::BraveFarblingService* brave_farbling_service() override; misc_metrics::MenuMetrics* menu_metrics() override; + misc_metrics::PrivacyHubMetrics* privacy_hub_metrics() override; private: // BrowserProcessImpl overrides: @@ -230,6 +232,7 @@ class BraveBrowserProcessImpl : public BraveBrowserProcess, std::unique_ptr brave_farbling_service_; std::unique_ptr menu_metrics_; + std::unique_ptr privacy_hub_metrics_; std::unique_ptr brave_stats_helper_; SEQUENCE_CHECKER(sequence_checker_); diff --git a/browser/brave_local_state_prefs.cc b/browser/brave_local_state_prefs.cc index c549b57a237..065c35ee198 100644 --- a/browser/brave_local_state_prefs.cc +++ b/browser/brave_local_state_prefs.cc @@ -27,6 +27,7 @@ #include "brave/components/misc_metrics/general_browser_usage.h" #include "brave/components/misc_metrics/menu_metrics.h" #include "brave/components/misc_metrics/page_metrics_service.h" +#include "brave/components/misc_metrics/privacy_hub_metrics.h" #include "brave/components/ntp_background_images/browser/ntp_background_images_service.h" #include "brave/components/ntp_background_images/browser/view_counter_service.h" #include "brave/components/p3a/p3a_service.h" @@ -139,6 +140,7 @@ void RegisterLocalStatePrefs(PrefRegistrySimple* registry) { misc_metrics::PageMetricsService::RegisterPrefs(registry); brave_ads::BraveStatsHelper::RegisterLocalStatePrefs(registry); misc_metrics::GeneralBrowserUsage::RegisterPrefs(registry); + misc_metrics::PrivacyHubMetrics::RegisterPrefs(registry); playlist::PlaylistServiceFactory::RegisterLocalStatePrefs(registry); } diff --git a/browser/misc_metrics/privacy_hub_metrics_factory_android.cc b/browser/misc_metrics/privacy_hub_metrics_factory_android.cc new file mode 100644 index 00000000000..ebf56b5ffb8 --- /dev/null +++ b/browser/misc_metrics/privacy_hub_metrics_factory_android.cc @@ -0,0 +1,21 @@ +/* Copyright (c) 2023 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 "base/android/jni_android.h" +#include "brave/browser/brave_browser_process.h" +#include "brave/build/android/jni_headers/PrivacyHubMetricsFactory_jni.h" +#include "brave/components/misc_metrics/privacy_hub_metrics.h" + +namespace chrome { +namespace android { +static jlong JNI_PrivacyHubMetricsFactory_GetInterfaceToPrivacyHubMetrics( + JNIEnv* env) { + auto pending = g_brave_browser_process->privacy_hub_metrics()->MakeRemote(); + + return static_cast(pending.PassPipe().release().value()); +} + +} // namespace android +} // namespace chrome diff --git a/browser/misc_metrics/sources.gni b/browser/misc_metrics/sources.gni index 33a54f375eb..fa2658d4266 100644 --- a/browser/misc_metrics/sources.gni +++ b/browser/misc_metrics/sources.gni @@ -20,3 +20,6 @@ brave_browser_misc_metrics_deps = [ "//components/keyed_service/core", "//content/public/browser", ] + +brave_browser_misc_metrics_android_sources = + [ "//brave/browser/misc_metrics/privacy_hub_metrics_factory_android.cc" ] diff --git a/browser/sources.gni b/browser/sources.gni index 5d7cf533f8b..58610930144 100644 --- a/browser/sources.gni +++ b/browser/sources.gni @@ -305,6 +305,7 @@ if (is_android) { ] brave_chrome_browser_sources += brave_browser_brave_wallet_android_sources + brave_chrome_browser_sources += brave_browser_misc_metrics_android_sources brave_chrome_browser_deps += brave_browser_brave_wallet_android_deps brave_chrome_browser_deps += [ diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn index 6e6c48864de..26756911b1a 100644 --- a/build/android/BUILD.gn +++ b/build/android/BUILD.gn @@ -228,6 +228,7 @@ generate_jni("jni_headers") { "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BraveDappPermissionPromptDialog.java", "//brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/WalletNativeUtils.java", "//brave/android/java/org/chromium/chrome/browser/informers/BraveSyncAccountDeletedInformer.java", + "//brave/android/java/org/chromium/chrome/browser/misc_metrics/PrivacyHubMetricsFactory.java", "//brave/android/java/org/chromium/chrome/browser/notifications/BraveNotificationPlatformBridge.java", "//brave/android/java/org/chromium/chrome/browser/notifications/BraveNotificationSettingsBridge.java", "//brave/android/java/org/chromium/chrome/browser/ntp_background_images/NTPBackgroundImagesBridge.java", diff --git a/build/android/config.gni b/build/android/config.gni index 4e91eeaee20..37742fcc48f 100644 --- a/build/android/config.gni +++ b/build/android/config.gni @@ -34,6 +34,7 @@ brave_chrome_java_deps = [ "//brave/components/brave_wallet/common:mojom_java", "//brave/components/browser_ui/accessibility/android:java", "//brave/components/browser_ui/site_settings/android:java", + "//brave/components/misc_metrics/common:mojom_java", "//brave/components/playlist/common/mojom:mojom_java", "//brave/components/safe_browsing/android:brave_safe_browsing_java", "//brave/components/variations/android:java", diff --git a/components/misc_metrics/BUILD.gn b/components/misc_metrics/BUILD.gn index 61f20fbb449..21af686d87b 100644 --- a/components/misc_metrics/BUILD.gn +++ b/components/misc_metrics/BUILD.gn @@ -13,6 +13,8 @@ static_library("misc_metrics") { "page_metrics_service.h", "pref_names.cc", "pref_names.h", + "privacy_hub_metrics.cc", + "privacy_hub_metrics.h", ] deps = [ @@ -24,4 +26,6 @@ static_library("misc_metrics") { "//components/prefs", "//url", ] + + public_deps = [ "//brave/components/misc_metrics/common:mojom" ] } diff --git a/components/misc_metrics/common/BUILD.gn b/components/misc_metrics/common/BUILD.gn new file mode 100644 index 00000000000..1675f388874 --- /dev/null +++ b/components/misc_metrics/common/BUILD.gn @@ -0,0 +1,12 @@ +# Copyright (c) 2023 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/. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("mojom") { + generate_java = true + sources = [ "misc_metrics.mojom" ] + public_deps = [ "//mojo/public/mojom/base" ] +} diff --git a/components/misc_metrics/common/misc_metrics.mojom b/components/misc_metrics/common/misc_metrics.mojom new file mode 100644 index 00000000000..b140afaa9e4 --- /dev/null +++ b/components/misc_metrics/common/misc_metrics.mojom @@ -0,0 +1,15 @@ +// Copyright (c) 2023 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/. + +module misc_metrics.mojom; + +// Handler for Privacy Hub events from UI. +interface PrivacyHubMetrics { + // Records view of Privacy Hub report. + RecordView(); + + // Records enabled status of Privacy Hub report. + RecordEnabledStatus(bool isEnabled); +}; diff --git a/components/misc_metrics/pref_names.cc b/components/misc_metrics/pref_names.cc index 54144fd4061..360079a8eb6 100644 --- a/components/misc_metrics/pref_names.cc +++ b/components/misc_metrics/pref_names.cc @@ -14,4 +14,6 @@ const char kMiscMetricsMenuGroupActionCounts[] = const char kMiscMetricsMenuShownStorage[] = "brave.misc_metrics.menu_shown_storage"; const char kMiscMetricsPagesLoadedCount[] = "brave.core_metrics.pages_loaded"; +const char kMiscMetricsPrivacyHubViews[] = + "brave.misc_metrics.privacy_hub_views"; } // namespace misc_metrics diff --git a/components/misc_metrics/pref_names.h b/components/misc_metrics/pref_names.h index 5b0ded39dac..adfa8c818eb 100644 --- a/components/misc_metrics/pref_names.h +++ b/components/misc_metrics/pref_names.h @@ -12,6 +12,7 @@ extern const char kMiscMetricsMenuDismissStorage[]; extern const char kMiscMetricsMenuGroupActionCounts[]; extern const char kMiscMetricsMenuShownStorage[]; extern const char kMiscMetricsPagesLoadedCount[]; +extern const char kMiscMetricsPrivacyHubViews[]; } // namespace misc_metrics #endif // BRAVE_COMPONENTS_MISC_METRICS_PREF_NAMES_H_ diff --git a/components/misc_metrics/privacy_hub_metrics.cc b/components/misc_metrics/privacy_hub_metrics.cc new file mode 100644 index 00000000000..cb4079efc67 --- /dev/null +++ b/components/misc_metrics/privacy_hub_metrics.cc @@ -0,0 +1,70 @@ +/* Copyright (c) 2023 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/misc_metrics/privacy_hub_metrics.h" + +#include "base/metrics/histogram_macros.h" +#include "brave/components/misc_metrics/pref_names.h" +#include "brave/components/p3a_utils/bucket.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" + +namespace misc_metrics { + +namespace { +const int kViewsMonthlyBucketValues[] = {1, 10, 20}; +} // namespace + +const char kViewsMonthlyHistogramName[] = "Brave.PrivacyHub.Views"; +const char kIsEnabledHistogramName[] = "Brave.PrivacyHub.IsEnabled"; +const base::TimeDelta kReportUpdateInterval = base::Days(1); + +PrivacyHubMetrics::PrivacyHubMetrics(PrefService* local_state) + : view_storage_(local_state, kMiscMetricsPrivacyHubViews) { + SetUpTimer(); +} + +PrivacyHubMetrics::~PrivacyHubMetrics() = default; + +void PrivacyHubMetrics::RegisterPrefs(PrefRegistrySimple* registry) { + registry->RegisterListPref(kMiscMetricsPrivacyHubViews); +} + +#if BUILDFLAG(IS_ANDROID) +mojo::PendingRemote PrivacyHubMetrics::MakeRemote() { + mojo::PendingRemote remote; + receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver()); + return remote; +} +#endif // BUILDFLAG(IS_ANDROID) + +void PrivacyHubMetrics::RecordView() { + view_storage_.AddDelta(1u); + RecordViewCount(); +} + +void PrivacyHubMetrics::RecordEnabledStatus(bool is_enabled) { + // suspend metric if not enabled; we only want to report + // if the feature is enabled + int histogram_value = is_enabled ? 1 : INT_MAX - 1; + UMA_HISTOGRAM_EXACT_LINEAR(kIsEnabledHistogramName, histogram_value, 2); +} + +void PrivacyHubMetrics::RecordViewCount() { + auto sum = view_storage_.GetMonthlySum(); + if (sum > 0) { + p3a_utils::RecordToHistogramBucket(kViewsMonthlyHistogramName, + kViewsMonthlyBucketValues, sum); + } + SetUpTimer(); +} + +void PrivacyHubMetrics::SetUpTimer() { + report_timer_.Start(FROM_HERE, base::Time::Now() + kReportUpdateInterval, + base::BindOnce(&PrivacyHubMetrics::RecordViewCount, + base::Unretained(this))); +} + +} // namespace misc_metrics diff --git a/components/misc_metrics/privacy_hub_metrics.h b/components/misc_metrics/privacy_hub_metrics.h new file mode 100644 index 00000000000..8ac5e79f9de --- /dev/null +++ b/components/misc_metrics/privacy_hub_metrics.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2023 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_MISC_METRICS_PRIVACY_HUB_METRICS_H_ +#define BRAVE_COMPONENTS_MISC_METRICS_PRIVACY_HUB_METRICS_H_ + +#include "base/timer/wall_clock_timer.h" + +#include "brave/components/misc_metrics/common/misc_metrics.mojom.h" +#include "brave/components/time_period_storage/monthly_storage.h" + +#if BUILDFLAG(IS_ANDROID) +#include "mojo/public/cpp/bindings/receiver_set.h" +#endif // BUILDFLAG(IS_ANDROID) + +class PrefRegistrySimple; +class PrefService; + +namespace misc_metrics { + +extern const char kViewsMonthlyHistogramName[]; +extern const char kIsEnabledHistogramName[]; + +// TODO(djandries): consider refactoring this into a more generic +// metrics service if we receive additional metric requests for features +// that don't have a mojo service that we can piggyback onto. +class PrivacyHubMetrics : public mojom::PrivacyHubMetrics { + public: + explicit PrivacyHubMetrics(PrefService* local_state); + ~PrivacyHubMetrics() override; + + PrivacyHubMetrics(const PrivacyHubMetrics&) = delete; + PrivacyHubMetrics& operator=(const PrivacyHubMetrics&) = delete; + + static void RegisterPrefs(PrefRegistrySimple* registry); + +#if BUILDFLAG(IS_ANDROID) + mojo::PendingRemote MakeRemote(); +#endif // BUILDFLAG(IS_ANDROID) + + void RecordView() override; + void RecordEnabledStatus(bool is_enabled) override; + + private: + void RecordViewCount(); + void SetUpTimer(); + + MonthlyStorage view_storage_; + base::WallClockTimer report_timer_; + +#if BUILDFLAG(IS_ANDROID) + mojo::ReceiverSet receivers_; +#endif // BUILDFLAG(IS_ANDROID) +}; + +} // namespace misc_metrics + +#endif // BRAVE_COMPONENTS_MISC_METRICS_PRIVACY_HUB_METRICS_H_ diff --git a/components/misc_metrics/privacy_hub_metrics_unittest.cc b/components/misc_metrics/privacy_hub_metrics_unittest.cc new file mode 100644 index 00000000000..1b6c3241a40 --- /dev/null +++ b/components/misc_metrics/privacy_hub_metrics_unittest.cc @@ -0,0 +1,50 @@ +/* Copyright (c) 2023 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 + +#include "base/test/metrics/histogram_tester.h" +#include "brave/components/misc_metrics/privacy_hub_metrics.h" +#include "components/prefs/testing_pref_service.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace misc_metrics { + +class PrivacyHubMetricsUnitTest : public testing::Test { + public: + PrivacyHubMetricsUnitTest() + : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} + + void SetUp() override { + misc_metrics::PrivacyHubMetrics::RegisterPrefs(local_state_.registry()); + privacy_hub_metrics_ = std::make_unique(&local_state_); + } + + protected: + content::BrowserTaskEnvironment task_environment_; + TestingPrefServiceSimple local_state_; + base::HistogramTester histogram_tester_; + std::unique_ptr privacy_hub_metrics_; +}; + +TEST_F(PrivacyHubMetricsUnitTest, Views) { + histogram_tester_.ExpectTotalCount(kViewsMonthlyHistogramName, 0); + + for (size_t i = 0; i < 4; i++) { + privacy_hub_metrics_->RecordView(); + } + + histogram_tester_.ExpectBucketCount(kViewsMonthlyHistogramName, 0, 1); + histogram_tester_.ExpectBucketCount(kViewsMonthlyHistogramName, 1, 3); + + task_environment_.FastForwardBy(base::Days(30)); + histogram_tester_.ExpectBucketCount(kViewsMonthlyHistogramName, 1, 32); + + task_environment_.FastForwardBy(base::Days(10)); + histogram_tester_.ExpectBucketCount(kViewsMonthlyHistogramName, 1, 32); +} + +} // namespace misc_metrics diff --git a/components/p3a/metric_names.h b/components/p3a/metric_names.h index 4c709168e3b..f3971c818ca 100644 --- a/components/p3a/metric_names.h +++ b/components/p3a/metric_names.h @@ -184,6 +184,8 @@ constexpr inline auto kCollectedSlowHistograms = "Brave.General.BottomBarLocation", "Brave.P3A.TestSlowMetric", "Brave.Playlist.LastUsageTime", + "Brave.PrivacyHub.IsEnabled", + "Brave.PrivacyHub.Views", "Brave.ReaderMode.NumberReaderModeActivated", "Brave.Rewards.TipsSent", "Brave.Sync.EnabledTypes", @@ -207,6 +209,7 @@ constexpr inline auto kEphemeralHistograms = base::MakeFixedFlatSet({ "Brave.Playlist.UsageDaysInWeek", "Brave.Playlist.FirstTimeOffset", + "Brave.PrivacyHub.Views", "Brave.Rewards.EnabledInstallationTime", "Brave.Rewards.EnabledSource", "Brave.Rewards.InlineTipTrigger", diff --git a/test/BUILD.gn b/test/BUILD.gn index ce02f2c96c3..0b338b02d28 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -140,6 +140,7 @@ test("brave_unit_tests") { "//brave/components/content_settings/core/browser/brave_content_settings_utils_unittest.cc", "//brave/components/misc_metrics/general_browser_usage_unittest.cc", "//brave/components/misc_metrics/menu_metrics_unittest.cc", + "//brave/components/misc_metrics/privacy_hub_metrics_unittest.cc", "//brave/components/ntp_background_images/browser/ntp_background_images_service_unittest.cc", "//brave/components/ntp_background_images/browser/ntp_background_images_source_unittest.cc", "//brave/components/ntp_background_images/browser/view_counter_model_unittest.cc", diff --git a/test/base/testing_brave_browser_process.cc b/test/base/testing_brave_browser_process.cc index 43f102ec623..238e03425d1 100644 --- a/test/base/testing_brave_browser_process.cc +++ b/test/base/testing_brave_browser_process.cc @@ -186,6 +186,12 @@ misc_metrics::MenuMetrics* TestingBraveBrowserProcess::menu_metrics() { return nullptr; } +misc_metrics::PrivacyHubMetrics* +TestingBraveBrowserProcess::privacy_hub_metrics() { + NOTREACHED(); + return nullptr; +} + void TestingBraveBrowserProcess::SetAdBlockService( std::unique_ptr service) { ad_block_service_ = std::move(service); diff --git a/test/base/testing_brave_browser_process.h b/test/base/testing_brave_browser_process.h index 34ac9c7af90..7551c69e994 100644 --- a/test/base/testing_brave_browser_process.h +++ b/test/base/testing_brave_browser_process.h @@ -87,6 +87,7 @@ class TestingBraveBrowserProcess : public BraveBrowserProcess { brave_vpn::BraveVPNOSConnectionAPI* brave_vpn_os_connection_api() override; #endif misc_metrics::MenuMetrics* menu_metrics() override; + misc_metrics::PrivacyHubMetrics* privacy_hub_metrics() override; // Populate the mock process with services. Consumer is responsible for // cleaning these up after completion of a test.