0

Remove RAPPOR reporting infrastructure.

Only a handful of metrics were still reported using this, which
are have been confirmed to be OK to remove.

Includes code to clear the obsolete rappor prefs.

Bug: 1016906
Change-Id: I8765494bcf6730107e585e8a244195b29d61f42e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2672923
Reviewed-by: Martin Šrámek <msramek@chromium.org>
Reviewed-by: Steven Holte <holte@chromium.org>
Reviewed-by: Jochen Eisinger <jochen@chromium.org>
Commit-Queue: Alexei Svitkine <asvitkine@chromium.org>
Cr-Commit-Position: refs/heads/master@{#850848}
This commit is contained in:
Alexei Svitkine
2021-02-04 23:25:06 +00:00
committed by Chromium LUCI CQ
parent 8f8e1306c0
commit 2d96608b43
125 changed files with 42 additions and 4985 deletions
.gitignoreBUILD.gnWATCHLISTS
chrome
components
content
ios
tools

1
.gitignore vendored

@ -188,7 +188,6 @@ vs-chromium-project.txt
/components/gcm_driver.xml
/components/leveldb_proto_test_support.xml
/components/ntp_tiles/resources/internal
/components/rappor.xml
/components/resources/default_100_percent/google_chrome
/components/resources/default_200_percent/google_chrome
/components/resources/default_300_percent/google_chrome

@ -718,7 +718,6 @@ group("gn_all") {
"//chrome/tools/convert_dict",
"//components/constrained_window:unit_tests",
"//components/metrics:serialization",
"//components/rappor:unit_tests",
"//components/services/filesystem:filesystem_service_unittests",
"//components/sessions:unit_tests",
"//media/blink:media_blink_unittests",

@ -1301,7 +1301,6 @@
'|chromecast/browser/metrics/'\
'|components/metrics/'\
'|components/metrics_services_manager/'\
'|components/rappor/'\
'|components/variations/'\
# Exclude XML files; in particular, histograms.xml.
'|tools/metrics/[^.]*([.](?!xml$).*)?$',

@ -3444,7 +3444,6 @@ generate_jni("chrome_jni_headers") {
"java/src/org/chromium/chrome/browser/provider/ChromeBrowserProviderImpl.java",
"java/src/org/chromium/chrome/browser/push_messaging/PushMessagingServiceObserver.java",
"java/src/org/chromium/chrome/browser/query_tiles/TileProviderFactory.java",
"java/src/org/chromium/chrome/browser/rappor/RapporServiceBridge.java",
"java/src/org/chromium/chrome/browser/read_later/ReadingListBridge.java",
"java/src/org/chromium/chrome/browser/resources/ResourceMapper.java",
"java/src/org/chromium/chrome/browser/rlz/RevenueStats.java",

@ -1190,7 +1190,6 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/query_tiles/QueryTileSection.java",
"java/src/org/chromium/chrome/browser/query_tiles/QueryTileUtils.java",
"java/src/org/chromium/chrome/browser/query_tiles/TileProviderFactory.java",
"java/src/org/chromium/chrome/browser/rappor/RapporServiceBridge.java",
"java/src/org/chromium/chrome/browser/read_later/ReadLaterIPHController.java",
"java/src/org/chromium/chrome/browser/read_later/ReadingListBridge.java",
"java/src/org/chromium/chrome/browser/read_later/ReadingListUtils.java",

@ -4,24 +4,18 @@
package org.chromium.chrome.browser.customtabs;
import android.text.TextUtils;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.base.task.PostTask;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.gsa.GSAState;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.rappor.RapporServiceBridge;
import org.chromium.chrome.browser.webapps.WebappCustomTabTimeSpentLogger;
import org.chromium.content_public.browser.UiThreadTaskTraits;
import javax.inject.Inject;
@ -98,19 +92,8 @@ public class CustomTabActivityLifecycleUmaTracker implements PauseResumeWithNati
@Override
public void onFinishNativeInitialization() {
String clientName =
mConnection.getClientPackageNameForSession(mIntentDataProvider.getSession());
if (TextUtils.isEmpty(clientName)) clientName = mIntentDataProvider.getClientPackageName();
final String packageName = clientName;
if (TextUtils.isEmpty(packageName) || packageName.contains(mActivity.getPackageName())) {
return;
if (mWebappTimeSpentLogger != null) {
mWebappTimeSpentLogger.onPause();
}
PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
RapporServiceBridge.sampleString("CustomTabs.ServiceClient.PackageName", packageName);
if (GSAState.isGsaPackageName(packageName)) return;
RapporServiceBridge.sampleString(
"CustomTabs.ServiceClient.PackageNameThirdParty", packageName);
});
}
}

@ -1,32 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.rappor;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
/**
* JNI bridge to the native Rappor service from Java.
*/
@JNINamespace("rappor")
public final class RapporServiceBridge {
private RapporServiceBridge() {
// Only for static use.
}
public static void sampleString(String metric, String sampleValue) {
RapporServiceBridgeJni.get().sampleString(metric, sampleValue);
}
public static void sampleDomainAndRegistryFromURL(String metric, String url) {
RapporServiceBridgeJni.get().sampleDomainAndRegistryFromURL(metric, url);
}
@NativeMethods
interface Natives {
void sampleDomainAndRegistryFromURL(String metric, String url);
void sampleString(String metric, String sampleValue);
}
}

@ -2150,7 +2150,6 @@ static_library("browser") {
"//components/proxy_config",
"//components/query_parser",
"//components/query_tiles",
"//components/rappor",
"//components/reading_list/core",
"//components/reading_list/features:flags",
"//components/renderer_context_menu",
@ -2827,7 +2826,6 @@ static_library("browser") {
"android/provider/chrome_browser_provider.cc",
"android/provider/chrome_browser_provider.h",
"android/provider/run_on_ui_thread_blocking.h",
"android/rappor/rappor_service_bridge.cc",
"android/reading_list/reading_list_bridge.cc",
"android/reading_list/reading_list_bridge.h",
"android/reading_list/reading_list_manager_factory.cc",

@ -244,7 +244,6 @@ include_rules = [
"+components/query_parser",
"+components/query_tiles",
"+components/quirks",
"+components/rappor",
"+components/reading_list/core",
"+components/reading_list/features",
"+components/remote_cocoa/app_shim",

@ -1,38 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/jni_string.h"
#include "chrome/android/chrome_jni_headers/RapporServiceBridge_jni.h"
#include "chrome/browser/browser_process.h"
#include "components/rappor/public/rappor_utils.h"
#include "components/rappor/rappor_service_impl.h"
#include "url/gurl.h"
using base::android::JavaParamRef;
namespace rappor {
void JNI_RapporServiceBridge_SampleDomainAndRegistryFromURL(
JNIEnv* env,
const JavaParamRef<jstring>& j_metric,
const JavaParamRef<jstring>& j_url) {
// TODO(knn): UMA metrics hash the string to prevent frequent re-encoding,
// perhaps we should do that as well.
std::string metric(base::android::ConvertJavaStringToUTF8(env, j_metric));
GURL gurl(base::android::ConvertJavaStringToUTF8(env, j_url));
rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(),
metric, gurl);
}
void JNI_RapporServiceBridge_SampleString(
JNIEnv* env,
const JavaParamRef<jstring>& j_metric,
const JavaParamRef<jstring>& j_value) {
std::string metric(base::android::ConvertJavaStringToUTF8(env, j_metric));
std::string value(base::android::ConvertJavaStringToUTF8(env, j_value));
rappor::SampleString(g_browser_process->rappor_service(),
metric, rappor::UMA_RAPPOR_TYPE, value);
}
} // namespace rappor

@ -78,7 +78,6 @@ static_library("vr_android") {
"//components/omnibox/browser",
"//components/page_info",
"//components/permissions",
"//components/rappor",
"//components/search_engines:search_engines",
"//components/webxr:webxr",
"//components/webxr/android",

@ -101,10 +101,6 @@ class PrintJobManager;
class PrintPreviewDialogController;
}
namespace rappor {
class RapporServiceImpl;
}
namespace resource_coordinator {
class ResourceCoordinatorParts;
class TabManager;
@ -134,7 +130,6 @@ class BrowserProcess {
// Services: any of these getters may return NULL
virtual metrics::MetricsService* metrics_service() = 0;
virtual rappor::RapporServiceImpl* rappor_service() = 0;
virtual ProfileManager* profile_manager() = 0;
virtual PrefService* local_state() = 0;
virtual scoped_refptr<network::SharedURLLoaderFactory>

@ -105,8 +105,6 @@
#include "components/prefs/json_pref_store.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/rappor/public/rappor_utils.h"
#include "components/rappor/rappor_service_impl.h"
#include "components/safe_browsing/core/safe_browsing_service_interface.h"
#include "components/sessions/core/session_id_generator.h"
#include "components/subresource_filter/content/browser/ruleset_service.h"
@ -218,12 +216,6 @@ static constexpr base::TimeDelta kEndSessionTimeout =
using content::BrowserThread;
using content::ChildProcessSecurityPolicy;
rappor::RapporService* GetBrowserRapporService() {
if (g_browser_process != nullptr)
return g_browser_process->rappor_service();
return nullptr;
}
BrowserProcessImpl::BrowserProcessImpl(StartupData* startup_data)
: startup_data_(startup_data),
browser_policy_connector_(startup_data->chrome_feature_list_creator()
@ -256,8 +248,6 @@ void BrowserProcessImpl::Init() {
download_status_updater_ = std::make_unique<DownloadStatusUpdater>();
rappor::SetDefaultServiceAccessor(&GetBrowserRapporService);
#if BUILDFLAG(ENABLE_PRINTING)
// Must be created after the NotificationService.
print_job_manager_ = std::make_unique<printing::PrintJobManager>();
@ -656,11 +646,6 @@ metrics::MetricsService* BrowserProcessImpl::metrics_service() {
return GetMetricsServicesManager()->GetMetricsService();
}
rappor::RapporServiceImpl* BrowserProcessImpl::rappor_service() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return GetMetricsServicesManager()->GetRapporServiceImpl();
}
SystemNetworkContextManager*
BrowserProcessImpl::system_network_context_manager() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

@ -133,7 +133,6 @@ class BrowserProcessImpl : public BrowserProcess,
metrics_services_manager::MetricsServicesManager* GetMetricsServicesManager()
override;
metrics::MetricsService* metrics_service() override;
rappor::RapporServiceImpl* rappor_service() override;
// TODO(qinmin): Remove this method as callers can retrieve the global
// instance from SystemNetworkContextManager directly.
SystemNetworkContextManager* system_network_context_manager() override;

@ -136,7 +136,6 @@
#include "components/prefs/pref_service.h"
#include "components/prefs/pref_value_store.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/rappor/rappor_service_impl.h"
#include "components/site_isolation/site_isolation_policy.h"
#include "components/spellcheck/spellcheck_buildflags.h"
#include "components/startup_metric_utils/browser/startup_metric_utils.h"

@ -300,7 +300,6 @@ source_set("chromeos") {
"//components/printing/common:mojo_interfaces",
"//components/proxy_config",
"//components/quirks",
"//components/rappor",
"//components/renderer_context_menu",
"//components/reporting/util:status",
"//components/reporting/util:task_runner_context",

@ -846,7 +846,6 @@ static_library("extensions") {
"//components/pref_registry",
"//components/privacy_sandbox:privacy_sandbox_prefs",
"//components/proxy_config",
"//components/rappor",
"//components/resources",
"//components/safe_browsing:buildflags",
"//components/safe_browsing/content/web_ui:web_ui",

@ -28,7 +28,6 @@
#include "components/metrics/enabled_state_provider.h"
#include "components/metrics/metrics_state_manager.h"
#include "components/prefs/pref_service.h"
#include "components/rappor/rappor_service_impl.h"
#include "components/variations/service/variations_service.h"
#include "components/variations/variations_associated_data.h"
#include "components/version_info/version_info.h"
@ -232,13 +231,6 @@ ChromeMetricsServicesManagerClient::GetEnabledStateProviderForTesting() {
return *enabled_state_provider_;
}
std::unique_ptr<rappor::RapporServiceImpl>
ChromeMetricsServicesManagerClient::CreateRapporServiceImpl() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return std::make_unique<rappor::RapporServiceImpl>(
local_state_, base::BindRepeating(&chrome::IsOffTheRecordSessionActive));
}
std::unique_ptr<variations::VariationsService>
ChromeMetricsServicesManagerClient::CreateVariationsService() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);

@ -76,7 +76,6 @@ class ChromeMetricsServicesManagerClient
class ChromeEnabledStateProvider;
// metrics_services_manager::MetricsServicesManagerClient:
std::unique_ptr<rappor::RapporServiceImpl> CreateRapporServiceImpl() override;
std::unique_ptr<variations::VariationsService> CreateVariationsService()
override;
std::unique_ptr<metrics::MetricsServiceClient> CreateMetricsServiceClient()

@ -46,7 +46,6 @@
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "components/page_load_metrics/browser/page_load_metrics_embedder_base.h"
#include "components/page_load_metrics/browser/page_load_tracker.h"
#include "components/rappor/rappor_service_impl.h"
#include "content/public/browser/web_contents.h"
#include "extensions/buildflags/buildflags.h"
#include "url/gurl.h"

@ -135,7 +135,6 @@
#include "components/prefs/pref_service.h"
#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/rappor/rappor_service_impl.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/search_engines/template_url_prepopulate_data.h"
#include "components/security_interstitials/content/insecure_form_blocking_page.h"
@ -538,6 +537,11 @@ const char kDataReductionProxyLastConfigRetrievalTime[] =
"data_reduction.last_config_retrieval_time";
const char kDataReductionProxyConfig[] = "data_reduction.config";
// Deprecated 2/2021.
const char kRapporCohortSeed[] = "rappor.cohort_seed";
const char kRapporLastDailySample[] = "rappor.last_daily_sample";
const char kRapporSecret[] = "rappor.secret";
// Register local state used only for migration (clearing or moving to a new
// key).
void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
@ -565,6 +569,10 @@ void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
registry->RegisterListPref(enterprise_connectors::kOnBulkDataEntryPref);
registry->RegisterListPref(enterprise_connectors::kOnSecurityEventPref);
#endif // !defined(OS_ANDROID)
registry->RegisterIntegerPref(kRapporCohortSeed, -1);
registry->RegisterInt64Pref(kRapporLastDailySample, 0);
registry->RegisterStringPref(kRapporSecret, std::string());
}
// Register prefs used only for migration (clearing or moving to a new key).
@ -674,7 +682,6 @@ void RegisterLocalState(PrefRegistrySimple* registry) {
ProfileInfoCache::RegisterPrefs(registry);
ProfileNetworkContextService::RegisterLocalStatePrefs(registry);
profiles::RegisterPrefs(registry);
rappor::RapporServiceImpl::RegisterPrefs(registry);
RegisterScreenshotPrefs(registry);
safe_browsing::RegisterLocalStatePrefs(registry);
secure_origin_allowlist::RegisterPrefs(registry);
@ -1194,6 +1201,11 @@ void MigrateObsoleteLocalStatePrefs(PrefService* local_state) {
local_state->ClearPref(enterprise_connectors::kOnSecurityEventPref);
#endif // !defined(OS_ANDROID)
// Added 2/2021.
local_state->ClearPref(kRapporCohortSeed);
local_state->ClearPref(kRapporLastDailySample);
local_state->ClearPref(kRapporSecret);
// Please don't delete the following line. It is used by PRESUBMIT.py.
// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS
}

@ -13,7 +13,6 @@
#include "components/bookmarks/common/bookmark_pref_names.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/rappor/rappor_pref_names.h"
#include "components/reading_list/core/reading_list_pref_names.h"
#include "components/ukm/ukm_pref_names.h"
@ -144,12 +143,6 @@ const char* const kPersistentPrefNames[] = {
prefs::kUseCustomChromeFrame,
#endif
// Rappor preferences are not used in incognito mode, but they are written
// in startup if they don't exist. So if the startup would be in incognito,
// they need to be persisted.
rappor::prefs::kRapporCohortSeed,
rappor::prefs::kRapporSecret,
// Reading list preferences are common between incognito and regular mode.
reading_list::prefs::kReadingListHasUnseenEntries,

@ -98,7 +98,7 @@ const char kEngineErrorCodeMetricName[] = "SoftwareReporter.EngineErrorCode";
// SoftwareReporterLogsUploadResult enum defined in the histograms.xml file.
const int kSwReporterLogsUploadResultMax = 30;
// Reports metrics about the software reporter via UMA (and sometimes Rappor).
// Reports metrics about the software reporter via UMA.
class UMAHistogramReporter {
public:
UMAHistogramReporter() : UMAHistogramReporter(std::string()) {}
@ -171,7 +171,7 @@ class UMAHistogramReporter {
reporter_key.DeleteValue(chrome_cleaner::kEngineErrorCodeValueName);
}
// Reports UwS found by the software reporter tool via UMA and RAPPOR.
// Reports UwS found by the software reporter tool via UMA.
void ReportFoundUwS() const {
base::win::RegKey reporter_key;
std::vector<base::string16> found_uws_strings;

@ -482,7 +482,6 @@ static_library("ui") {
"//components/previews/core",
"//components/proxy_config",
"//components/query_parser",
"//components/rappor",
"//components/reading_list/core",
"//components/reading_list/features:flags",
"//components/renderer_context_menu",

@ -370,7 +370,6 @@ void ContentSettingMixedScriptBubbleModel::OnLearnMoreClicked() {
}
void ContentSettingMixedScriptBubbleModel::OnCustomLinkClicked() {
DCHECK(rappor_service());
MixedContentSettingsTabHelper* mixed_content_settings =
MixedContentSettingsTabHelper::FromWebContents(web_contents());
if (mixed_content_settings) {
@ -1677,10 +1676,7 @@ ContentSettingBubbleModel::CreateContentSettingBubbleModel(
ContentSettingBubbleModel::ContentSettingBubbleModel(Delegate* delegate,
WebContents* web_contents)
: web_contents_(web_contents),
owner_(nullptr),
delegate_(delegate),
rappor_service_(g_browser_process->rappor_service()) {
: web_contents_(web_contents), owner_(nullptr), delegate_(delegate) {
DCHECK(web_contents_);
}

@ -37,10 +37,6 @@ namespace content {
class WebContents;
}
namespace rappor {
class RapporServiceImpl;
}
namespace ui {
class Event;
}
@ -223,12 +219,6 @@ class ContentSettingBubbleModel {
// Cast this bubble into ContentSettingNotificationsBubbleModel if possible.
virtual ContentSettingNotificationsBubbleModel* AsNotificationsBubbleModel();
// Sets the Rappor service used for testing.
void SetRapporServiceImplForTesting(
rappor::RapporServiceImpl* rappor_service) {
rappor_service_ = rappor_service;
}
protected:
// |web_contents| must outlive this.
ContentSettingBubbleModel(Delegate* delegate,
@ -281,15 +271,12 @@ class ContentSettingBubbleModel {
void set_cancel_button_text(const base::string16& cancel_button_text) {
bubble_content_.cancel_button_text = cancel_button_text;
}
rappor::RapporServiceImpl* rappor_service() const { return rappor_service_; }
private:
content::WebContents* web_contents_;
Owner* owner_;
Delegate* delegate_;
BubbleContent bubble_content_;
// The service used to record Rappor metrics. Can be set for testing.
rappor::RapporServiceImpl* rappor_service_;
DISALLOW_COPY_AND_ASSIGN(ContentSettingBubbleModel);
};

@ -259,7 +259,6 @@ component("vr_common") {
"//chrome/common:constants",
"//components/omnibox/browser",
"//components/omnibox/browser",
"//components/rappor/public:public",
"//components/ukm/content",
"//content/public/browser",
"//device/base",
@ -386,7 +385,6 @@ component("vr_base") {
deps = [
"//base",
"//chrome/app:generated_resources",
"//components/rappor:rappor",
"//components/security_state/core",
"//components/ukm/content",
"//components/url_formatter",

@ -40,7 +40,6 @@ include_rules = [
"+components/plugins/renderer",
"+components/printing/common",
"+components/printing/renderer",
"+components/rappor/public/mojom",
"+components/safe_browsing/buildflags.h",
"+components/safe_browsing/content/renderer",
"+components/safe_browsing/content/common",

@ -233,7 +233,6 @@ static_library("test_support") {
"//components/performance_manager/test_support",
"//components/permissions:test_support",
"//components/prefs:test_support",
"//components/rappor:test_support",
"//components/safe_browsing/core/db:v4_test_util",
"//components/search_engines:test_support",
"//components/sessions:test_support",

@ -155,10 +155,6 @@ metrics::MetricsService* TestingBrowserProcess::metrics_service() {
return nullptr;
}
rappor::RapporServiceImpl* TestingBrowserProcess::rappor_service() {
return rappor_service_;
}
SystemNetworkContextManager*
TestingBrowserProcess::system_network_context_manager() {
return nullptr;
@ -510,11 +506,6 @@ void TestingBrowserProcess::SetFlocSortingLshClustersService(
floc_sorting_lsh_clusters_service_.swap(service);
}
void TestingBrowserProcess::SetRapporServiceImpl(
rappor::RapporServiceImpl* rappor_service) {
rappor_service_ = rappor_service;
}
void TestingBrowserProcess::SetShuttingDown(bool is_shutting_down) {
is_shutting_down_ = is_shutting_down;
}

@ -81,7 +81,6 @@ class TestingBrowserProcess : public BrowserProcess {
metrics_services_manager::MetricsServicesManager* GetMetricsServicesManager()
override;
metrics::MetricsService* metrics_service() override;
rappor::RapporServiceImpl* rappor_service() override;
SystemNetworkContextManager* system_network_context_manager() override;
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory()
override;
@ -165,7 +164,6 @@ class TestingBrowserProcess : public BrowserProcess {
std::unique_ptr<NotificationPlatformBridge> notification_platform_bridge);
void SetSystemNotificationHelper(
std::unique_ptr<SystemNotificationHelper> system_notification_helper);
void SetRapporServiceImpl(rappor::RapporServiceImpl* rappor_service);
void SetShuttingDown(bool is_shutting_down);
void ShutdownBrowserPolicyConnector();
TestingBrowserProcessPlatformPart* GetTestPlatformPart();
@ -214,7 +212,6 @@ class TestingBrowserProcess : public BrowserProcess {
// The following objects are not owned by TestingBrowserProcess:
PrefService* local_state_ = nullptr;
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
rappor::RapporServiceImpl* rappor_service_ = nullptr;
std::unique_ptr<TestingBrowserProcessPlatformPart> platform_part_;
std::unique_ptr<network::TestNetworkConnectionTracker>

@ -814,12 +814,6 @@ FILES = [
'archive': 'metrics-metadata.zip',
'optional': ['dev', 'official'],
},
{
'filename': 'rappor.xml',
'buildtype': ['dev', 'official'],
'archive': 'metrics-metadata.zip',
'optional': ['dev', 'official'],
},
{
'filename': 'ukm.xml',
'buildtype': ['dev', 'official'],

@ -131,7 +131,6 @@ test("components_unittests") {
"//components/proxy_config:unit_tests",
"//components/qr_code_generator:unit_tests",
"//components/query_parser:unit_tests",
"//components/rappor:unit_tests",
"//components/reading_list/core:unit_tests",
"//components/reporting/encryption:unit_tests",
"//components/reporting/storage:unit_tests",

@ -40,9 +40,6 @@ const base::Feature kHttpRetryFeature{"UMAHttpRetry",
// ablate a clients upload of all logs that use |metrics::ReportingService|
// to upload logs. This include |metrics::MetricsReportingService| for uploading
// UMA logs. |ukm::UKMReportionService| for uploading UKM logs.
// Rappor service use |rappor::LogUploader| which is not a
// |metrics::ReportingService| so, it won't be ablated.
// similar frequency.
// To restrict the study to UMA or UKM, set the "service-affected" param.
const base::Feature kAblateMetricsLogUploadFeature{
"AblateMetricsLogUpload", base::FEATURE_DISABLED_BY_DEFAULT};

@ -12,7 +12,6 @@ static_library("metrics_services_manager") {
deps = [
"//base",
"//components/metrics",
"//components/rappor",
"//components/ukm",
"//components/variations",
"//components/variations/service",

@ -2,7 +2,6 @@ include_rules = [
"-components",
"+components/metrics",
"+components/metrics_services_manager",
"+components/rappor",
"+components/ukm",
"+components/variations",
"+services/network",

@ -15,7 +15,6 @@
#include "components/metrics/metrics_state_manager.h"
#include "components/metrics/metrics_switches.h"
#include "components/metrics_services_manager/metrics_services_manager_client.h"
#include "components/rappor/rappor_service_impl.h"
#include "components/ukm/ukm_service.h"
#include "components/variations/service/variations_service.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
@ -43,15 +42,6 @@ metrics::MetricsService* MetricsServicesManager::GetMetricsService() {
return GetMetricsServiceClient()->GetMetricsService();
}
rappor::RapporServiceImpl* MetricsServicesManager::GetRapporServiceImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!rappor_service_) {
rappor_service_ = client_->CreateRapporServiceImpl();
rappor_service_->Initialize(client_->GetURLLoaderFactory());
}
return rappor_service_.get();
}
ukm::UkmService* MetricsServicesManager::GetUkmService() {
DCHECK(thread_checker_.CalledOnValidThread());
return GetMetricsServiceClient()->GetUkmService();
@ -100,8 +90,8 @@ void MetricsServicesManager::UpdatePermissions(bool current_may_record,
}
}
// Stash the current permissions so that we can update the RapporServiceImpl
// correctly when the Rappor preference changes.
// Stash the current permissions so that we can update the services correctly
// when preferences change.
may_record_ = current_may_record;
consent_given_ = current_consent_given;
may_upload_ = current_may_upload;
@ -115,7 +105,6 @@ void MetricsServicesManager::UpdateRunningServices() {
const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
if (cmdline->HasSwitch(metrics::switches::kMetricsRecordingOnly)) {
metrics->StartRecordingForTests();
GetRapporServiceImpl()->Update(true, false);
return;
}
@ -133,8 +122,6 @@ void MetricsServicesManager::UpdateRunningServices() {
}
UpdateUkmService();
GetRapporServiceImpl()->Update(may_record_, may_upload_);
}
void MetricsServicesManager::UpdateUkmService() {

@ -20,10 +20,6 @@ class MetricsService;
class MetricsServiceClient;
}
namespace rappor {
class RapporServiceImpl;
}
namespace ukm {
class UkmService;
}
@ -38,7 +34,7 @@ class MetricsServicesManagerClient;
// MetricsServicesManager is a helper class for embedders that use the various
// metrics-related services in a Chrome-like fashion: MetricsService (via its
// client), RapporServiceImpl and VariationsService.
// client) and VariationsService.
class MetricsServicesManager {
public:
// Creates the MetricsServicesManager with the given client.
@ -60,9 +56,6 @@ class MetricsServicesManager {
// additionally creating the MetricsServiceClient in that case).
metrics::MetricsService* GetMetricsService();
// Returns the RapporServiceImpl, creating it if it hasn't been created yet.
rappor::RapporServiceImpl* GetRapporServiceImpl();
// Returns the UkmService, creating it if it hasn't been created yet.
ukm::UkmService* GetUkmService();
@ -86,10 +79,6 @@ class MetricsServicesManager {
bool IsMetricsConsentGiven() const;
private:
// Update the managed services when permissions for recording/uploading
// metrics change.
void UpdateRapporServiceImpl();
// Returns the MetricsServiceClient, creating it if it hasn't been
// created yet (and additionally creating the MetricsService in that case).
metrics::MetricsServiceClient* GetMetricsServiceClient();
@ -124,9 +113,6 @@ class MetricsServicesManager {
// The MetricsServiceClient. Owns the MetricsService.
std::unique_ptr<metrics::MetricsServiceClient> metrics_service_client_;
// The RapporServiceImpl, for RAPPOR metric uploads.
std::unique_ptr<rappor::RapporServiceImpl> rappor_service_;
// The VariationsService, for server-side experiments infrastructure.
std::unique_ptr<variations::VariationsService> variations_service_;

@ -19,10 +19,6 @@ namespace network {
class SharedURLLoaderFactory;
}
namespace rappor {
class RapporServiceImpl;
}
namespace variations {
class VariationsService;
}
@ -36,8 +32,6 @@ class MetricsServicesManagerClient {
virtual ~MetricsServicesManagerClient() {}
// Methods that create the various services in the context of the embedder.
virtual std::unique_ptr<rappor::RapporServiceImpl>
CreateRapporServiceImpl() = 0;
virtual std::unique_ptr<variations::VariationsService>
CreateVariationsService() = 0;
virtual std::unique_ptr<metrics::MetricsServiceClient>

@ -58,7 +58,6 @@ static_library("ntp_tiles") {
"//components/image_fetcher/core",
"//components/pref_registry",
"//components/prefs",
"//components/rappor/public",
"//components/resources",
"//components/search",
"//components/search_engines",
@ -101,7 +100,6 @@ source_set("unit_tests") {
"//components/image_fetcher/core",
"//components/image_fetcher/core:test_support",
"//components/pref_registry:pref_registry",
"//components/rappor:test_support",
"//components/sync_preferences:test_support",
"//net:test_support",
"//services/data_decoder/public/cpp:test_support",

@ -8,7 +8,6 @@ include_rules = [
"+components/image_fetcher",
"+components/pref_registry",
"+components/prefs",
"+components/rappor",
"+components/search_engines",
"+components/search",
"+components/strings/grit/components_strings.h",

@ -1,101 +0,0 @@
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//testing/test.gni")
static_library("rappor") {
sources = [
"bloom_filter.cc",
"bloom_filter.h",
"byte_vector_utils.cc",
"byte_vector_utils.h",
"log_uploader.cc",
"log_uploader.h",
"log_uploader_interface.h",
"rappor_metric.cc",
"rappor_metric.h",
"rappor_parameters.cc",
"rappor_pref_names.cc",
"rappor_pref_names.h",
"rappor_prefs.cc",
"rappor_prefs.h",
"rappor_service_impl.cc",
"rappor_service_impl.h",
"rappor_utils.cc",
"reports.cc",
"reports.h",
"sample.cc",
"sampler.cc",
"sampler.h",
]
public_deps = [
"//components/rappor/proto",
"//components/rappor/public",
]
deps = [
"//base",
"//components/metrics",
"//components/prefs",
"//components/variations",
"//crypto",
"//net",
"//services/network/public/cpp:cpp",
]
}
static_library("test_support") {
testonly = true
sources = [
"test_log_uploader.cc",
"test_log_uploader.h",
"test_rappor_service.cc",
"test_rappor_service.h",
]
public_deps = [ ":rappor" ]
deps = [
"//base",
"//components/prefs:test_support",
]
}
source_set("unit_tests") {
testonly = true
sources = [
"bloom_filter_unittest.cc",
"byte_vector_utils_unittest.cc",
"log_uploader_unittest.cc",
"rappor_metric_unittest.cc",
"rappor_prefs_unittest.cc",
"rappor_service_unittest.cc",
"rappor_utils_unittest.cc",
"reports_unittest.cc",
"sampler_unittest.cc",
]
deps = [
":rappor",
":test_support",
"//base",
"//base/test:test_support",
"//components/metrics",
"//components/prefs:test_support",
"//net:test_support",
"//services/network:test_support",
"//services/network/public/cpp:cpp",
"//testing/gtest",
"//url",
]
}
# Convenience testing target
test("rappor_unittests") {
sources = [ "//components/test/run_all_unittests.cc" ]
deps = [
":unit_tests",
"//components/test:test_support",
]
}

@ -1,10 +0,0 @@
include_rules = [
"+components/metrics",
"+components/prefs",
"+components/variations",
"+crypto",
"+mojo/public/cpp",
"+net",
"+services/network",
"+third_party/smhasher",
]

@ -1,3 +0,0 @@
monorail {
component: "Internals>Metrics"
}

@ -1,2 +0,0 @@
asvitkine@chromium.org
holte@chromium.org

@ -1,9 +0,0 @@
# Rappor (Randomized Aggregatable Privacy Preserving Ordinal Responses)
RAPPOR reports consist of randomly generated data that is biased based on data
collected from the user. Data from many users can be aggregated to learn
information about the population, but little or nothing can be concluded about
individual users from their reports.
Documentation:
http://www.chromium.org/developers/design-documents/rappor

@ -1,71 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/bloom_filter.h"
#include <stddef.h>
#include "base/check_op.h"
#include "base/containers/span.h"
#include "base/hash/legacy_hash.h"
#include "base/numerics/safe_conversions.h"
namespace rappor {
namespace {
uint32_t ComputeHash(const std::string& str, uint32_t seed) {
// Using CityHash here because we have support for it in Dremel. Many hash
// functions, such as MD5, SHA1, or Murmur, would probably also work.
return base::legacy::CityHash64WithSeed(
base::as_bytes(base::make_span(str)), seed);
}
} // namespace
BloomFilter::BloomFilter(size_t bytes_size,
uint32_t hash_function_count,
uint32_t hash_seed_offset)
: bytes_(bytes_size),
hash_function_count_(hash_function_count),
hash_seed_offset_(hash_seed_offset) {
DCHECK_GT(bytes_size, 0u);
}
BloomFilter::~BloomFilter() {}
void BloomFilter::SetString(const std::string& str) {
for (size_t i = 0; i < bytes_.size(); ++i) {
bytes_[i] = 0;
}
for (size_t i = 0; i < hash_function_count_; ++i) {
uint32_t index = ComputeHash(str, hash_seed_offset_ + i);
// Note that the "bytes" are uint8_t, so they are always 8-bits.
uint32_t byte_index = (index / 8) % bytes_.size();
uint32_t bit_index = index % 8;
bytes_[byte_index] |= 1 << bit_index;
}
}
namespace internal {
uint64_t GetBloomBits(size_t bytes_size,
uint32_t hash_function_count,
uint32_t hash_seed_offset,
const std::string& str) {
// Make sure result fits in uint64_t.
DCHECK_LE(bytes_size, 8u);
uint64_t output = 0;
const uint64_t bits_size = base::strict_cast<uint64_t>(bytes_size) * 8;
for (size_t i = 0; i < hash_function_count; ++i) {
uint64_t index = base::strict_cast<uint64_t>(
ComputeHash(str, hash_seed_offset + i));
output |= 1ULL << (index % bits_size);
}
return output;
}
} // namespace internal
} // namespace rappor

@ -1,61 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_BLOOM_FILTER_H_
#define COMPONENTS_RAPPOR_BLOOM_FILTER_H_
#include <stdint.h>
#include <string>
#include "base/macros.h"
#include "components/rappor/byte_vector_utils.h"
namespace rappor {
// BloomFilter is a simple Bloom filter for keeping track of a set of strings.
class BloomFilter {
public:
// Constructs a BloomFilter using |bytes_size| bytes of Bloom filter bits,
// and |hash_function_count| hash functions to set bits in the filter. The
// hash functions will be generated by using seeds in the range
// |hash_seed_offset| to (|hash_seed_offset| + |hash_function_count|).
BloomFilter(size_t bytes_size,
uint32_t hash_function_count,
uint32_t hash_seed_offset);
~BloomFilter();
// Sets the Bloom filter bits to contain a single string.
void SetString(const std::string& str);
// Returns the current value of the Bloom filter's bit array.
const ByteVector& bytes() const { return bytes_; }
private:
// Stores the byte array of the Bloom filter.
ByteVector bytes_;
// The number of bits to set for each string added.
uint32_t hash_function_count_;
// A number add to a hash function index to get a seed for that hash function.
uint32_t hash_seed_offset_;
DISALLOW_COPY_AND_ASSIGN(BloomFilter);
};
namespace internal {
// A function for getting bloom filters less than or equal to 64 bits.
uint64_t GetBloomBits(size_t bytes_size,
uint32_t hash_function_count,
uint32_t hash_seed_offset,
const std::string& str);
} // namespace internal
} // namespace rappor
#endif // COMPONENTS_RAPPOR_BLOOM_FILTER_H_

@ -1,67 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/bloom_filter.h"
#include <stdint.h>
#include "components/rappor/byte_vector_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace rappor {
TEST(BloomFilterTest, TinyFilter) {
BloomFilter filter(1u, 4u, 0u);
// Size is 1 and it's initially empty
EXPECT_EQ(1u, filter.bytes().size());
EXPECT_EQ(0x00, filter.bytes()[0]);
// "Test" has a self-collision, and only sets 3 bits.
filter.SetString("Test");
EXPECT_EQ(0x2a, filter.bytes()[0]);
// Setting the same value shouldn't change anything.
filter.SetString("Test");
EXPECT_EQ(0x2a, filter.bytes()[0]);
BloomFilter filter2(1u, 4u, 0u);
EXPECT_EQ(0x00, filter2.bytes()[0]);
filter2.SetString("Bar");
EXPECT_EQ(0xa8, filter2.bytes()[0]);
// The new string should replace the old one.
filter.SetString("Bar");
EXPECT_EQ(0xa8, filter.bytes()[0]);
}
TEST(BloomFilterTest, HugeFilter) {
// Create a 500 bit filter, and use a large seed offset to see if anything
// breaks.
BloomFilter filter(500u, 1u, 0xabdef123);
// Size is 500 and it's initially empty
EXPECT_EQ(500u, filter.bytes().size());
EXPECT_EQ(0, CountBits(filter.bytes()));
filter.SetString("Bar");
EXPECT_EQ(1, CountBits(filter.bytes()));
// Adding the same value shouldn't change anything.
filter.SetString("Bar");
EXPECT_EQ(1, CountBits(filter.bytes()));
}
TEST(BloomFilterTest, GetBloomBitsSmall) {
uint64_t bytes_from_get = internal::GetBloomBits(1u, 4u, 0u, "Bar");
EXPECT_EQ(0xa8u, bytes_from_get);
}
TEST(BloomFilterTest, GetBloomBitsLarge) {
// Make sure that a 64-bit bloom filter can set the full range of bits.
uint64_t bytes_from_get = internal::GetBloomBits(8u, 1024u, 0u, "Bar");
EXPECT_EQ(0xffffffffffffffffu, bytes_from_get);
}
} // namespace rappor

@ -1,249 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/byte_vector_utils.h"
#include <string.h>
#include <algorithm>
#include <string>
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/rand_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "crypto/random.h"
namespace rappor {
namespace {
// Reinterpets a ByteVector as a StringPiece.
base::StringPiece ByteVectorAsStringPiece(const ByteVector& lhs) {
return base::StringPiece(reinterpret_cast<const char *>(&lhs[0]), lhs.size());
}
// Concatenates parameters together as a string.
std::string Concat(const ByteVector& value, char c, base::StringPiece data) {
return base::StrCat(
{ByteVectorAsStringPiece(value), base::StringPiece(&c, 1), data});
}
// Performs the operation: K = HMAC(K, data)
// The input "K" is passed by initializing |hmac| with it.
// The output "K" is returned by initializing |result| with it.
// Returns false on an error.
bool HMAC_Rotate(const crypto::HMAC& hmac,
const std::string& data,
crypto::HMAC* result) {
ByteVector key(hmac.DigestLength());
if (!hmac.Sign(data, &key[0], key.size()))
return false;
return result->Init(ByteVectorAsStringPiece(key));
}
// Performs the operation: V = HMAC(K, V)
// The input "K" is passed by initializing |hmac| with it.
// "V" is read from and written to |value|.
// Returns false on an error.
bool HMAC_Rehash(const crypto::HMAC& hmac, ByteVector* value) {
return hmac.Sign(ByteVectorAsStringPiece(*value),
&(*value)[0], value->size());
}
// Implements (Key, V) = HMAC_DRBG_Update(provided_data, Key, V)
// See: http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
// "V" is read from and written to |value|.
// The input "Key" is passed by initializing |hmac1| with it.
// The output "Key" is returned by initializing |out_hmac| with it.
// Returns false on an error.
bool HMAC_DRBG_Update(base::StringPiece provided_data,
const crypto::HMAC& hmac1,
ByteVector* value,
crypto::HMAC* out_hmac) {
// HMAC_DRBG Update Process
crypto::HMAC temp_hmac(crypto::HMAC::SHA256);
crypto::HMAC* hmac2 = provided_data.size() > 0 ? &temp_hmac : out_hmac;
// 1. K = HMAC(K, V || 0x00 || provided_data)
if (!HMAC_Rotate(hmac1, Concat(*value, 0x00, provided_data), hmac2))
return false;
// 2. V = HMAC(K, V)
if (!HMAC_Rehash(*hmac2, value))
return false;
// 3. If (provided_data = Null), then return K and V.
if (hmac2 == out_hmac)
return true;
// 4. K = HMAC(K, V || 0x01 || provided_data)
if (!HMAC_Rotate(*hmac2, Concat(*value, 0x01, provided_data), out_hmac))
return false;
// 5. V = HMAC(K, V)
return HMAC_Rehash(*out_hmac, value);
}
} // namespace
void Uint64ToByteVector(uint64_t value, size_t size, ByteVector* output) {
DCHECK_LE(size, 8u);
DCHECK_EQ(size, output->size());
for (size_t i = 0; i < size; i++) {
// Get the value of the i-th smallest byte and copy it to the byte vector.
uint64_t shift = i * 8;
uint64_t byte_mask = static_cast<uint64_t>(0xff) << shift;
(*output)[i] = (value & byte_mask) >> shift;
}
}
ByteVector* ByteVectorAnd(const ByteVector& lhs, ByteVector* rhs) {
DCHECK_EQ(lhs.size(), rhs->size());
for (size_t i = 0; i < lhs.size(); ++i) {
(*rhs)[i] = lhs[i] & (*rhs)[i];
}
return rhs;
}
ByteVector* ByteVectorOr(const ByteVector& lhs, ByteVector* rhs) {
DCHECK_EQ(lhs.size(), rhs->size());
for (size_t i = 0; i < lhs.size(); ++i) {
(*rhs)[i] = lhs[i] | (*rhs)[i];
}
return rhs;
}
ByteVector* ByteVectorMerge(const ByteVector& mask,
const ByteVector& lhs,
ByteVector* rhs) {
DCHECK_EQ(lhs.size(), rhs->size());
for (size_t i = 0; i < lhs.size(); ++i) {
(*rhs)[i] = (lhs[i] & ~mask[i]) | ((*rhs)[i] & mask[i]);
}
return rhs;
}
int CountBits(const ByteVector& vector) {
int bit_count = 0;
for (size_t i = 0; i < vector.size(); ++i) {
uint8_t byte = vector[i];
for (int j = 0; j < 8 ; ++j) {
if (byte & (1 << j))
bit_count++;
}
}
return bit_count;
}
ByteVectorGenerator::ByteVectorGenerator(size_t byte_count)
: byte_count_(byte_count) {}
ByteVectorGenerator::~ByteVectorGenerator() {}
ByteVector ByteVectorGenerator::GetRandomByteVector() {
ByteVector bytes(byte_count_);
crypto::RandBytes(&bytes[0], bytes.size());
return bytes;
}
ByteVector ByteVectorGenerator::GetWeightedRandomByteVector(
Probability probability) {
switch (probability) {
case PROBABILITY_100:
return ByteVector(byte_count_, 0xff);
case PROBABILITY_75: {
ByteVector bytes = GetRandomByteVector();
return *ByteVectorOr(GetRandomByteVector(), &bytes);
}
case PROBABILITY_50:
return GetRandomByteVector();
case PROBABILITY_25: {
ByteVector bytes = GetRandomByteVector();
return *ByteVectorAnd(GetRandomByteVector(), &bytes);
}
case PROBABILITY_0:
return ByteVector(byte_count_);
}
NOTREACHED();
return ByteVector(byte_count_);
}
HmacByteVectorGenerator::HmacByteVectorGenerator(
size_t byte_count,
const std::string& entropy_input,
base::StringPiece personalization_string)
: ByteVectorGenerator(byte_count),
hmac_(crypto::HMAC::SHA256),
value_(hmac_.DigestLength(), 0x01),
generated_bytes_(0) {
// HMAC_DRBG Instantiate Process
// See: http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
// 1. seed_material = entropy_input + nonce + personalization_string
// Note: We are using the 8.6.7 interpretation, where the entropy_input and
// nonce are acquired at the same time from the same source.
DCHECK_EQ(kEntropyInputSize, entropy_input.size());
std::string seed_material =
base::StrCat({entropy_input, personalization_string});
// 2. Key = 0x00 00...00
crypto::HMAC hmac1(crypto::HMAC::SHA256);
if (!hmac1.Init(std::string(hmac_.DigestLength(), 0x00)))
NOTREACHED();
// 3. V = 0x01 01...01
// (value_ in initializer list)
// 4. (Key, V) = HMAC_DRBG_Update(seed_material, Key, V)
if (!HMAC_DRBG_Update(seed_material, hmac1, &value_, &hmac_))
NOTREACHED();
}
HmacByteVectorGenerator::~HmacByteVectorGenerator() {}
HmacByteVectorGenerator::HmacByteVectorGenerator(
const HmacByteVectorGenerator& prev_request)
: ByteVectorGenerator(prev_request.byte_count()),
hmac_(crypto::HMAC::SHA256),
value_(prev_request.value_),
generated_bytes_(0) {
if (!HMAC_DRBG_Update("", prev_request.hmac_, &value_, &hmac_))
NOTREACHED();
}
// HMAC_DRBG requires entropy input to be security_strength bits long,
// and nonce to be at least 1/2 security_strength bits long. We
// generate them both as a single "extra strong" entropy input.
// max_security_strength for SHA256 is 256 bits.
// See: http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
const size_t HmacByteVectorGenerator::kEntropyInputSize = (256 / 8) * 3 / 2;
// static
std::string HmacByteVectorGenerator::GenerateEntropyInput() {
return base::RandBytesAsString(kEntropyInputSize);
}
ByteVector HmacByteVectorGenerator::GetRandomByteVector() {
// Streams bytes from HMAC_DRBG_Generate
// See: http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
const size_t digest_length = hmac_.DigestLength();
DCHECK_EQ(value_.size(), digest_length);
ByteVector bytes(byte_count());
uint8_t* data = &bytes[0];
size_t bytes_to_go = byte_count();
while (bytes_to_go > 0) {
size_t requested_byte_in_digest = generated_bytes_ % digest_length;
if (requested_byte_in_digest == 0) {
// Do step 4.1 of the HMAC_DRBG Generate Process for more bits.
// V = HMAC(Key, V)
if (!HMAC_Rehash(hmac_, &value_))
NOTREACHED();
}
size_t n = std::min(bytes_to_go,
digest_length - requested_byte_in_digest);
memcpy(data, &value_[requested_byte_in_digest], n);
data += n;
bytes_to_go -= n;
generated_bytes_ += n;
// Check max_number_of_bits_per_request from 10.1 Table 2
// max_number_of_bits_per_request == 2^19 bits == 2^16 bytes
DCHECK_LT(generated_bytes_, 1U << 16);
}
return bytes;
}
} // namespace rappor

@ -1,121 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_BYTE_VECTOR_UTILS_H_
#define COMPONENTS_RAPPOR_BYTE_VECTOR_UTILS_H_
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "components/rappor/public/rappor_parameters.h"
#include "crypto/hmac.h"
namespace rappor {
// A vector of 8-bit integers used to store a set of binary bits.
typedef std::vector<uint8_t> ByteVector;
// Converts the lowest |size| bytes of |value| into a ByteVector.
void Uint64ToByteVector(uint64_t value, size_t size, ByteVector* output);
// Computes a bitwise AND of byte vectors and stores the result in rhs.
// Returns rhs for chaining.
ByteVector* ByteVectorAnd(const ByteVector& lhs, ByteVector* rhs);
// Computes a bitwise OR of byte vectors and stores the result in rhs.
// Returns rhs for chaining.
ByteVector* ByteVectorOr(const ByteVector& lhs, ByteVector* rhs);
// Merges the contents of lhs and rhs vectors according to a mask vector.
// The i-th bit of the result vector will be the i-th bit of either the lhs
// or rhs vector, based on the i-th bit of the mask vector.
// Equivalent to (lhs & ~mask) | (rhs & mask). Stores the result in rhs.
// Returns rhs for chaining.
ByteVector* ByteVectorMerge(const ByteVector& mask,
const ByteVector& lhs,
ByteVector* rhs);
// Counts the number of bits set in the byte vector.
int CountBits(const ByteVector& vector);
// A utility object for generating random binary data with different
// likelihood of bits being true, using entropy from crypto::RandBytes().
class ByteVectorGenerator {
public:
explicit ByteVectorGenerator(size_t byte_count);
virtual ~ByteVectorGenerator();
// Generates a random byte vector where the bits are independent random
// variables which are true with the given |probability|.
ByteVector GetWeightedRandomByteVector(Probability probability);
protected:
// Size of vectors to be generated.
size_t byte_count() const { return byte_count_; }
// Generates a random vector of bytes from a uniform distribution.
virtual ByteVector GetRandomByteVector();
private:
size_t byte_count_;
DISALLOW_COPY_AND_ASSIGN(ByteVectorGenerator);
};
// A ByteVectorGenerator that uses a pseudo-random function to generate a
// deterministically random bits. This class only implements a single request
// from HMAC_DRBG and streams up to 2^19 bits from that request.
// Ref: http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
// We're using our own PRNG instead of crypto::RandBytes because we need to
// generate a repeatable sequence of bits from the same seed. Conservatively,
// we're choosing to use HMAC_DRBG here, as it is one of the best studied
// and standardized ways of generating deterministic, unpredictable sequences
// based on a secret seed.
class HmacByteVectorGenerator : public ByteVectorGenerator {
public:
// Constructor takes the size of the vector to generate, along with a
// |entropy_input| and |personalization_string| to seed the pseudo-random
// number generator. The string parameters are treated as byte arrays.
HmacByteVectorGenerator(size_t byte_count,
const std::string& entropy_input,
base::StringPiece personalization_string);
~HmacByteVectorGenerator() override;
// Generates a random string suitable for passing to the constructor as
// |entropy_input|.
static std::string GenerateEntropyInput();
// Key size required for 128-bit security strength (including nonce).
static const size_t kEntropyInputSize;
protected:
// Generate byte vector generator that streams from the next request instead
// of the current one. For testing against NIST test vectors only.
explicit HmacByteVectorGenerator(const HmacByteVectorGenerator& prev_request);
// ByteVector implementation:
ByteVector GetRandomByteVector() override;
private:
// HMAC initalized with the value of "Key" HMAC_DRBG_Initialize.
crypto::HMAC hmac_;
// The "V" value from HMAC_DRBG.
ByteVector value_;
// Total number of bytes streamed from the HMAC_DRBG Generate Process.
size_t generated_bytes_;
DISALLOW_ASSIGN(HmacByteVectorGenerator);
};
} // namespace rappor
#endif // COMPONENTS_RAPPOR_BYTE_VECTOR_UTILS_H_

@ -1,166 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/byte_vector_utils.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace rappor {
namespace {
class SecondRequest : public HmacByteVectorGenerator {
public:
SecondRequest(const HmacByteVectorGenerator& first_request)
: HmacByteVectorGenerator(first_request) {}
};
std::string HexToString(const char* hex) {
ByteVector bv;
base::HexStringToBytes(hex, &bv);
return std::string(bv.begin(), bv.end());
}
} // namespace
TEST(ByteVectorTest, Uint64ToByteVectorSmall) {
ByteVector bytes(1);
Uint64ToByteVector(0x10, 1, &bytes);
EXPECT_EQ(1u, bytes.size());
EXPECT_EQ(0x10, bytes[0]);
}
TEST(ByteVectorTest, Uint64ToByteVectorLarge) {
ByteVector bytes(8);
Uint64ToByteVector(0xfedcba9876543210, 8, &bytes);
EXPECT_EQ(8u, bytes.size());
EXPECT_EQ(0x10, bytes[0]);
EXPECT_EQ(0xfe, bytes[7]);
}
TEST(ByteVectorTest, ByteVectorAnd) {
ByteVector lhs(2);
lhs[1] = 0x12;
ByteVector rhs(2);
rhs[1] = 0x03;
EXPECT_EQ(0x02, (*ByteVectorAnd(lhs, &rhs))[1]);
}
TEST(ByteVectorTest, ByteVectorOr) {
ByteVector lhs(2);
lhs[1] = 0x12;
ByteVector rhs(2);
rhs[1] = 0x03;
EXPECT_EQ(0x13, (*ByteVectorOr(lhs, &rhs))[1]);
}
TEST(ByteVectorTest, ByteVectorMerge) {
ByteVector lhs(2);
lhs[1] = 0x33;
ByteVector rhs(2);
rhs[1] = 0x55;
ByteVector mask(2);
mask[1] = 0x0f;
EXPECT_EQ(0x35, (*ByteVectorMerge(mask, lhs, &rhs))[1]);
}
TEST(ByteVectorTest, ByteVectorGenerator) {
ByteVectorGenerator generator(2u);
ByteVector random_50 = generator.GetWeightedRandomByteVector(PROBABILITY_50);
EXPECT_EQ(random_50.size(), 2u);
ByteVector random_75 = generator.GetWeightedRandomByteVector(PROBABILITY_75);
EXPECT_EQ(random_75.size(), 2u);
}
TEST(ByteVectorTest, HmacByteVectorGenerator) {
HmacByteVectorGenerator generator(1u,
std::string(HmacByteVectorGenerator::kEntropyInputSize, 0x00), "");
ByteVector random_50 = generator.GetWeightedRandomByteVector(PROBABILITY_50);
EXPECT_EQ(random_50.size(), 1u);
EXPECT_EQ(random_50[0], 0x0B);
ByteVector random_75 = generator.GetWeightedRandomByteVector(PROBABILITY_75);
EXPECT_EQ(random_75.size(), 1u);
EXPECT_EQ(random_75[0], 0xdf);
}
TEST(ByteVectorTest, HmacNist) {
// Test case 0 for SHA-256 HMAC_DRBG no reseed tests from
// http://csrc.nist.gov/groups/STM/cavp/
const char entropy[] =
"ca851911349384bffe89de1cbdc46e6831e44d34a4fb935ee285dd14b71a7488";
const char nonce[] = "659ba96c601dc69fc902940805ec0ca8";
const char expected[] =
"e528e9abf2dece54d47c7e75e5fe302149f817ea9fb4bee6f4199697d04d5b89"
"d54fbb978a15b5c443c9ec21036d2460b6f73ebad0dc2aba6e624abf07745bc1"
"07694bb7547bb0995f70de25d6b29e2d3011bb19d27676c07162c8b5ccde0668"
"961df86803482cb37ed6d5c0bb8d50cf1f50d476aa0458bdaba806f48be9dcb8";
std::string entropy_input = HexToString(entropy) + HexToString(nonce);
HmacByteVectorGenerator generator(1024u / 8, entropy_input, "");
generator.GetWeightedRandomByteVector(PROBABILITY_50);
SecondRequest generator2(generator);
ByteVector random_50 = generator2.GetWeightedRandomByteVector(PROBABILITY_50);
EXPECT_EQ(HexToString(expected),
std::string(random_50.begin(), random_50.end()));
}
TEST(ByteVectorTest, WeightedRandomStatistics0) {
ByteVectorGenerator generator(50u);
ByteVector random = generator.GetWeightedRandomByteVector(PROBABILITY_0);
int bit_count = CountBits(random);
EXPECT_EQ(bit_count, 0);
}
TEST(ByteVectorTest, WeightedRandomStatistics100) {
ByteVectorGenerator generator(50u);
ByteVector random = generator.GetWeightedRandomByteVector(PROBABILITY_100);
int bit_count = CountBits(random);
EXPECT_EQ(bit_count, 50 * 8);
}
TEST(ByteVectorTest, WeightedRandomStatistics50) {
ByteVectorGenerator generator(50u);
ByteVector random = generator.GetWeightedRandomByteVector(PROBABILITY_50);
int bit_count = CountBits(random);
// Check bounds on bit counts that are true with 99.999% probability.
EXPECT_GT(bit_count, 155); // Binomial(400, .5) CDF(155) ~= 0.000004
EXPECT_LE(bit_count, 244); // Binomial(400, .5) CDF(244) ~= 0.999996
}
TEST(ByteVectorTest, WeightedRandomStatistics75) {
ByteVectorGenerator generator(50u);
ByteVector random = generator.GetWeightedRandomByteVector(PROBABILITY_75);
int bit_count = CountBits(random);
// Check bounds on bit counts that are true with 99.999% probability.
EXPECT_GT(bit_count, 259); // Binomial(400, .75) CDF(259) ~= 0.000003
EXPECT_LE(bit_count, 337); // Binomial(400, .75) CDF(337) ~= 0.999997
}
TEST(ByteVectorTest, HmacWeightedRandomStatistics50) {
HmacByteVectorGenerator generator(50u,
HmacByteVectorGenerator::GenerateEntropyInput(), "");
ByteVector random = generator.GetWeightedRandomByteVector(PROBABILITY_50);
int bit_count = CountBits(random);
// Check bounds on bit counts that are true with 99.999% probability.
EXPECT_GT(bit_count, 155); // Binomial(400, .5) CDF(155) ~= 0.000004
EXPECT_LE(bit_count, 244); // Binomial(400, .5) CDF(244) ~= 0.999996
}
TEST(ByteVectorTest, HmacWeightedRandomStatistics75) {
HmacByteVectorGenerator generator(50u,
HmacByteVectorGenerator::GenerateEntropyInput(), "");
ByteVector random = generator.GetWeightedRandomByteVector(PROBABILITY_75);
int bit_count = CountBits(random);
// Check bounds on bit counts that are true with 99.999% probability.
EXPECT_GT(bit_count, 259); // Binomial(400, .75) CDF(259) ~= 0.000003
EXPECT_LE(bit_count, 337); // Binomial(400, .75) CDF(337) ~= 0.999997
}
} // namespace rappor

@ -1,231 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/log_uploader.h"
#include <stddef.h>
#include <stdint.h>
#include <utility>
#include "base/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
namespace {
// The delay, in seconds, between uploading when there are queued logs to send.
const int kUnsentLogsIntervalSeconds = 3;
// When uploading metrics to the server fails, we progressively wait longer and
// longer before sending the next log. This backoff process helps reduce load
// on a server that is having issues.
// The following is the multiplier we use to expand that inter-log duration.
const double kBackoffMultiplier = 1.1;
// The maximum backoff multiplier.
const int kMaxBackoffIntervalSeconds = 60 * 60;
// The maximum number of unsent logs we will keep.
// TODO(holte): Limit based on log size instead.
const size_t kMaxQueuedLogs = 10;
enum DiscardReason {
UPLOAD_SUCCESS,
UPLOAD_REJECTED,
QUEUE_OVERFLOW,
NUM_DISCARD_REASONS
};
void RecordDiscardReason(DiscardReason reason) {
UMA_HISTOGRAM_ENUMERATION("Rappor.DiscardReason",
reason,
NUM_DISCARD_REASONS);
}
} // namespace
namespace rappor {
LogUploader::LogUploader(
const GURL& server_url,
const std::string& mime_type,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: server_url_(server_url),
mime_type_(mime_type),
url_loader_factory_(std::move(url_loader_factory)),
is_running_(false),
has_callback_pending_(false),
upload_interval_(
base::TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds)) {}
LogUploader::~LogUploader() {}
void LogUploader::Start() {
is_running_ = true;
StartScheduledUpload();
}
void LogUploader::Stop() {
is_running_ = false;
// Rather than interrupting the current upload, just let it finish/fail and
// then inhibit any retry attempts.
}
void LogUploader::QueueLog(const std::string& log) {
queued_logs_.push(log);
// Don't drop logs yet if an upload is in progress. They will be dropped
// when it finishes.
if (!has_callback_pending_)
DropExcessLogs();
StartScheduledUpload();
}
void LogUploader::DropExcessLogs() {
while (queued_logs_.size() > kMaxQueuedLogs) {
DVLOG(2) << "Dropping excess log.";
RecordDiscardReason(QUEUE_OVERFLOW);
queued_logs_.pop();
}
}
bool LogUploader::IsUploadScheduled() const {
return upload_timer_.IsRunning();
}
void LogUploader::ScheduleNextUpload(base::TimeDelta interval) {
upload_timer_.Start(
FROM_HERE, interval, this, &LogUploader::StartScheduledUpload);
}
bool LogUploader::CanStartUpload() const {
return is_running_ &&
!queued_logs_.empty() &&
!IsUploadScheduled() &&
!has_callback_pending_;
}
void LogUploader::StartScheduledUpload() {
if (!CanStartUpload())
return;
DVLOG(2) << "Upload to " << server_url_.spec() << " starting.";
has_callback_pending_ = true;
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("rappor_report", R"(
semantics {
sender: "RAPPOR"
description:
"This service sends RAPPOR anonymous usage statistics to Google."
trigger:
"Reports are automatically generated on startup and at intervals "
"while Chromium is running."
data: "A protocol buffer with RAPPOR anonymous usage statistics."
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: NO
setting:
"Users can enable or disable this feature by stopping "
"'Automatically send usage statistics and crash reports to Google'"
"in Chromium's settings under Advanced Settings, Privacy. The "
"feature is enabled by default."
chrome_policy {
MetricsReportingEnabled {
policy_options {mode: MANDATORY}
MetricsReportingEnabled: false
}
}
})");
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = server_url_;
// We already drop cookies server-side, but we might as well strip them out
// client-side as well.
resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
resource_request->method = "POST";
simple_url_loader_ = network::SimpleURLLoader::Create(
std::move(resource_request), traffic_annotation);
simple_url_loader_->AttachStringForUpload(queued_logs_.front(), mime_type_);
// TODO re-add data use measurement once SimpleURLLoader supports it.
// ID=data_use_measurement::DataUseUserData::RAPPOR
simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
url_loader_factory_.get(),
base::BindOnce(&LogUploader::OnSimpleLoaderComplete,
base::Unretained(this)));
}
// static
base::TimeDelta LogUploader::BackOffUploadInterval(base::TimeDelta interval) {
DCHECK_GT(kBackoffMultiplier, 1.0);
interval = base::TimeDelta::FromMicroseconds(
static_cast<int64_t>(kBackoffMultiplier * interval.InMicroseconds()));
base::TimeDelta max_interval =
base::TimeDelta::FromSeconds(kMaxBackoffIntervalSeconds);
return interval > max_interval ? max_interval : interval;
}
void LogUploader::OnSimpleLoaderComplete(
std::unique_ptr<std::string> response_body) {
int response_code = -1;
if (simple_url_loader_->ResponseInfo() &&
simple_url_loader_->ResponseInfo()->headers) {
response_code =
simple_url_loader_->ResponseInfo()->headers->response_code();
}
DVLOG(2) << "Upload fetch complete response code: " << response_code;
int net_error = simple_url_loader_->NetError();
if (net_error != net::OK && (response_code == -1 || response_code == 200)) {
base::UmaHistogramSparse("Rappor.FailedUploadErrorCode", -net_error);
DVLOG(1) << "Rappor server upload failed with error: " << net_error << ": "
<< net::ErrorToString(net_error);
} else {
// Log a histogram to track response success vs. failure rates.
base::UmaHistogramSparse("Rappor.UploadResponseCode", response_code);
}
const bool upload_succeeded = !!response_body;
// Determine whether this log should be retransmitted.
DiscardReason reason = NUM_DISCARD_REASONS;
if (upload_succeeded) {
reason = UPLOAD_SUCCESS;
} else if (response_code == 400) {
reason = UPLOAD_REJECTED;
}
if (reason != NUM_DISCARD_REASONS) {
DVLOG(2) << "Log discarded.";
RecordDiscardReason(reason);
queued_logs_.pop();
}
DropExcessLogs();
// Error 400 indicates a problem with the log, not with the server, so
// don't consider that a sign that the server is in trouble.
const bool server_is_healthy = upload_succeeded || response_code == 400;
OnUploadFinished(server_is_healthy);
}
void LogUploader::OnUploadFinished(bool server_is_healthy) {
DCHECK(has_callback_pending_);
has_callback_pending_ = false;
// If the server is having issues, back off. Otherwise, reset to default.
if (!server_is_healthy)
upload_interval_ = BackOffUploadInterval(upload_interval_);
else
upload_interval_ = base::TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds);
if (CanStartUpload())
ScheduleNextUpload(upload_interval_);
}
} // namespace rappor

@ -1,112 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_LOG_UPLOADER_H_
#define COMPONENTS_RAPPOR_LOG_UPLOADER_H_
#include <memory>
#include <string>
#include "base/compiler_specific.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/rappor/log_uploader_interface.h"
#include "url/gurl.h"
namespace network {
class SimpleURLLoader;
class SharedURLLoaderFactory;
} // namespace network
namespace rappor {
// Uploads logs from RapporServiceImpl. Logs are passed in via QueueLog(),
// stored internally, and uploaded one at a time. A queued log will be uploaded
// at a fixed interval after the successful upload of the previous logs. If an
// upload fails, the uploader will keep retrying the upload with an exponential
// backoff interval.
class LogUploader : public LogUploaderInterface {
public:
// Constructor takes the |server_url| that logs should be uploaded to, the
// |mime_type| of the uploaded data, and |request_context| to create uploads
// with.
LogUploader(
const GURL& server_url,
const std::string& mime_type,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
// If the object is destroyed (or the program terminates) while logs are
// queued, the logs are lost.
~LogUploader() override;
// LogUploaderInterface:
void Start() override;
void Stop() override;
void QueueLog(const std::string& log) override;
protected:
// Checks if an upload has been scheduled.
virtual bool IsUploadScheduled() const;
// Schedules a future call to StartScheduledUpload if one isn't already
// pending. Can be overridden for testing.
virtual void ScheduleNextUpload(base::TimeDelta interval);
// Starts transmission of the next log. Exposed for tests.
void StartScheduledUpload();
// Increases the upload interval each time it's called, to handle the case
// where the server is having issues. Exposed for tests.
static base::TimeDelta BackOffUploadInterval(base::TimeDelta);
private:
// Returns true if the uploader is allowed to start another upload.
bool CanStartUpload() const;
// Drops excess logs until we are under the size limit.
void DropExcessLogs();
// Called after transmission completes (whether successful or not).
void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body);
// Called when the upload is completed.
void OnUploadFinished(bool server_is_healthy);
// The server URL to upload logs to.
const GURL server_url_;
// The mime type to specify on uploaded logs.
const std::string mime_type_;
// The URL loader factory used to send uploads.
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
// True if the uploader is currently running.
bool is_running_;
// The outstanding transmission.
std::unique_ptr<network::SimpleURLLoader> simple_url_loader_;
// The logs that still need to be uploaded.
base::queue<std::string> queued_logs_;
// A timer used to delay before attempting another upload.
base::OneShotTimer upload_timer_;
// Indicates that the last triggered upload hasn't resolved yet.
bool has_callback_pending_;
// The interval to wait after an upload's URLFetcher completion before
// starting the next upload attempt.
base::TimeDelta upload_interval_;
DISALLOW_COPY_AND_ASSIGN(LogUploader);
};
} // namespace rappor
#endif // COMPONENTS_RAPPOR_LOG_UPLOADER_H_

@ -1,29 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_LOG_UPLOADER_INTERFACE_H_
#define COMPONENTS_RAPPOR_LOG_UPLOADER_INTERFACE_H_
namespace rappor {
class LogUploaderInterface {
public:
LogUploaderInterface() {}
virtual ~LogUploaderInterface() {}
// Begin uploading logs.
virtual void Start() = 0;
// Stops uploading logs.
virtual void Stop() = 0;
// Adds an entry to the queue of logs to be uploaded to the server. The
// uploader makes no assumptions about the format of |log| and simply sends
// it verbatim to the server.
virtual void QueueLog(const std::string& log) = 0;
};
} // namespace rappor
#endif // COMPONENTS_RAPPOR_LOG_UPLOADER_INTERFACE_H_

@ -1,164 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/log_uploader.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace rappor {
namespace {
const char kTestServerURL[] = "http://a.com/";
const char kTestMimeType[] = "text/plain";
class TestLogUploader : public LogUploader {
public:
explicit TestLogUploader(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: LogUploader(GURL(kTestServerURL), kTestMimeType, url_loader_factory) {
Start();
}
base::TimeDelta last_interval_set() const { return last_interval_set_; }
void StartUpload() {
last_interval_set_ = base::TimeDelta();
StartScheduledUpload();
}
static base::TimeDelta BackOff(base::TimeDelta t) {
return LogUploader::BackOffUploadInterval(t);
}
protected:
bool IsUploadScheduled() const override {
return !last_interval_set().is_zero();
}
// Schedules a future call to StartScheduledUpload if one isn't already
// pending.
void ScheduleNextUpload(base::TimeDelta interval) override {
EXPECT_EQ(last_interval_set(), base::TimeDelta());
last_interval_set_ = interval;
}
base::TimeDelta last_interval_set_;
private:
DISALLOW_COPY_AND_ASSIGN(TestLogUploader);
};
} // namespace
class LogUploaderTest : public testing::Test {
public:
LogUploaderTest()
: task_environment_(
base::test::SingleThreadTaskEnvironment::MainThreadType::UI) {}
protected:
// Required for base::ThreadTaskRunnerHandle::Get().
base::test::SingleThreadTaskEnvironment task_environment_;
network::TestURLLoaderFactory test_url_loader_factory_;
private:
DISALLOW_COPY_AND_ASSIGN(LogUploaderTest);
};
TEST_F(LogUploaderTest, Success) {
TestLogUploader uploader(test_url_loader_factory_.GetSafeWeakWrapper());
test_url_loader_factory_.AddResponse(kTestServerURL, "");
uploader.QueueLog("log1");
base::RunLoop().RunUntilIdle();
// Log should be discarded instead of retransmitted.
EXPECT_EQ(uploader.last_interval_set(), base::TimeDelta());
}
TEST_F(LogUploaderTest, Rejection) {
TestLogUploader uploader(test_url_loader_factory_.GetSafeWeakWrapper());
auto response_head = network::mojom::URLResponseHead::New();
std::string headers("HTTP/1.1 400 Bad Request\nContent-type: text/html\n\n");
response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
net::HttpUtil::AssembleRawHeaders(headers));
response_head->mime_type = "text/html";
test_url_loader_factory_.AddResponse(GURL(kTestServerURL),
std::move(response_head), "",
network::URLLoaderCompletionStatus());
uploader.QueueLog("log1");
base::RunLoop().RunUntilIdle();
// Log should be discarded instead of retransmitted.
EXPECT_EQ(uploader.last_interval_set(), base::TimeDelta());
}
TEST_F(LogUploaderTest, Failure) {
TestLogUploader uploader(test_url_loader_factory_.GetSafeWeakWrapper());
auto response_head = network::mojom::URLResponseHead::New();
std::string headers(
"HTTP/1.1 500 Internal Server Error\nContent-type: text/html\n\n");
response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
net::HttpUtil::AssembleRawHeaders(headers));
response_head->mime_type = "text/html";
test_url_loader_factory_.AddResponse(GURL(kTestServerURL),
std::move(response_head), "",
network::URLLoaderCompletionStatus());
uploader.QueueLog("log1");
base::RunLoop().RunUntilIdle();
// Log should be scheduled for retransmission.
base::TimeDelta error_interval = uploader.last_interval_set();
EXPECT_GT(error_interval, base::TimeDelta());
for (int i = 0; i < 10; i++) {
uploader.QueueLog("logX");
}
// A second failure should lead to a longer interval, and the log should
// be discarded due to full queue.
uploader.StartUpload();
base::RunLoop().RunUntilIdle();
EXPECT_GT(uploader.last_interval_set(), error_interval);
test_url_loader_factory_.AddResponse(kTestServerURL, "");
// A success should revert to base interval while queue is not empty.
for (int i = 0; i < 9; i++) {
uploader.StartUpload();
base::RunLoop().RunUntilIdle();
EXPECT_LT(uploader.last_interval_set(), error_interval);
}
// Queue should be empty.
uploader.StartUpload();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(uploader.last_interval_set(), base::TimeDelta());
}
TEST_F(LogUploaderTest, Backoff) {
base::TimeDelta current = base::TimeDelta();
base::TimeDelta next = base::TimeDelta::FromSeconds(1);
// Backoff until the maximum is reached.
while (next > current) {
current = next;
next = TestLogUploader::BackOff(current);
}
// Maximum backoff should have been reached.
EXPECT_EQ(next, current);
}
} // namespace rappor

@ -1,9 +0,0 @@
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//third_party/protobuf/proto_library.gni")
proto_library("proto") {
sources = [ "rappor_metric.proto" ]
}

@ -1,40 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Contains information collected by the RAPPOR (Randomized Aggregatable
// Privacy-Preserving Ordinal Responses) system.
//
// For a full description of the rappor metrics, see
// http://www.chromium.org/developers/design-documents/rappor
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
package rappor;
// Next tag: 3
message RapporReports {
// Which cohort these reports belong to. The RAPPOR participants are
// partioned into cohorts in different ways, to allow better statistics and
// increased coverage. In particular, the cohort will serve to choose the
// hash functions used for Bloom-filter-based reports. The cohort is
// generated randomly by the client and is currently in the range [0,512).
// Was in range [0,32) in chrome versions before M37.
optional int32 cohort = 1;
// Each Report contains the values generated by the RAPPOR process for one
// metric.
message Report {
// The name of the metric, hashed (first 8 bytes of MD5 hash).
optional fixed64 name_hash = 1;
// The sequence of bits produced by random coin flips in
// RapporMetric::GetReport(). For a complete description of RAPPOR
// metrics, refer to the design document at:
// http://www.chromium.org/developers/design-documents/rappor
optional bytes bits = 2;
}
repeated Report report = 2;
}

@ -1,14 +0,0 @@
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
source_set("public") {
sources = [
"rappor_parameters.h",
"rappor_service.h",
"rappor_utils.h",
"sample.h",
]
deps = [ "//base" ]
}

@ -1,159 +0,0 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_PUBLIC_RAPPOR_PARAMETERS_H_
#define COMPONENTS_RAPPOR_PUBLIC_RAPPOR_PARAMETERS_H_
#include <string>
namespace rappor {
// Levels of noise added to a sample.
enum NoiseLevel {
NO_NOISE = 0,
NORMAL_NOISE,
SPARSE_NOISE,
NUM_NOISE_LEVELS,
};
// The type of data stored in a metric.
// Any use of the LOW_FREQUENCY types must be approved by Chrome Privacy and
// the rappor-dev team.
enum RapporType {
// Generic metrics from UMA opt-in users.
UMA_RAPPOR_TYPE = 0,
// Deprecated: Use UMA_RAPPOR_TYPE for new metrics
ETLD_PLUS_ONE_RAPPOR_TYPE,
// Type for low-frequency metrics from UMA opt-in users.
LOW_FREQUENCY_UMA_RAPPOR_TYPE,
// Type for low-frequency metrics from UMA opt-in users. Do not use for new
// metrics.
LOW_FREQUENCY_ETLD_PLUS_ONE_RAPPOR_TYPE,
NUM_RAPPOR_TYPES,
};
enum Probability {
PROBABILITY_100, // 100%
PROBABILITY_75, // 75%
PROBABILITY_50, // 50%
PROBABILITY_25, // 25%
PROBABILITY_0, // 0%
};
// A metric is reported when its reporting group is in the set of groups
// passed in to RapporServiceImpl::Start()
enum RecordingGroup {
// Metrics for UMA users.
UMA_RAPPOR_GROUP = 1 << 0,
};
// An object describing noise probabilities for a noise level
struct NoiseParameters {
// The probability that a bit will be redacted with fake data. This
// corresponds to the F privacy parameter.
Probability fake_prob;
// The probability that a fake bit will be a one.
Probability fake_one_prob;
// The probability that a one bit in the redacted data reports as one. This
// corresponds to the Q privacy parameter
Probability one_coin_prob;
// The probability that a zero bit in the redacted data reports as one. This
// corresponds to the P privacy parameter.
Probability zero_coin_prob;
};
// An object describing a rappor metric and the parameters used to generate it.
//
// For a full description of the rappor metrics, see
// http://www.chromium.org/developers/design-documents/rappor
struct RapporParameters {
// Get a string representing the parameters, for DCHECK_EQ.
std::string ToString() const;
// The maximum number of cohorts we divide clients into.
static const int kMaxCohorts;
// The number of cohorts to divide the reports for this metric into.
// This should divide kMaxCohorts evenly so that each cohort has an equal
// probability of being assigned users.
int num_cohorts;
// The number of bytes stored in the Bloom filter.
size_t bloom_filter_size_bytes;
// The number of hash functions used in the Bloom filter.
int bloom_filter_hash_function_count;
// The level of noise to use.
NoiseLevel noise_level;
// The reporting level this metric is reported at.
RecordingGroup recording_group;
};
namespace internal {
const NoiseParameters kNoiseParametersForLevel[NUM_NOISE_LEVELS] = {
// NO_NOISE
{
rappor::PROBABILITY_0 /* Fake data probability */,
rappor::PROBABILITY_0 /* Fake one probability */,
rappor::PROBABILITY_100 /* One coin probability */,
rappor::PROBABILITY_0 /* Zero coin probability */,
},
// NORMAL_NOISE
{
rappor::PROBABILITY_50 /* Fake data probability */,
rappor::PROBABILITY_50 /* Fake one probability */,
rappor::PROBABILITY_75 /* One coin probability */,
rappor::PROBABILITY_25 /* Zero coin probability */,
},
// SPARSE_NOISE
{
rappor::PROBABILITY_25 /* Fake data probability */,
rappor::PROBABILITY_50 /* Fake one probability */,
rappor::PROBABILITY_75 /* One coin probability */,
rappor::PROBABILITY_25 /* Zero coin probability */,
},
};
const RapporParameters kRapporParametersForType[NUM_RAPPOR_TYPES] = {
// UMA_RAPPOR_TYPE
{
128 /* Num cohorts */,
4 /* Bloom filter size bytes */,
2 /* Bloom filter hash count */,
rappor::NORMAL_NOISE /* Noise level */,
UMA_RAPPOR_GROUP /* Recording group */
},
// ETLD_PLUS_ONE_RAPPOR_TYPE
{
128 /* Num cohorts */,
16 /* Bloom filter size bytes */,
2 /* Bloom filter hash count */,
rappor::NORMAL_NOISE /* Noise level */,
UMA_RAPPOR_GROUP /* Recording group */
},
// LOW_FREQUENCY_UMA_RAPPOR_TYPE
{
128 /* Num cohorts */,
4 /* Bloom filter size bytes */,
2 /* Bloom filter hash count */,
rappor::SPARSE_NOISE /* Noise level */,
UMA_RAPPOR_GROUP /* Recording group */
},
// LOW_FREQUENCY_ETLD_PLUS_ONE_RAPPOR_TYPE
{
128 /* Num cohorts */,
16 /* Bloom filter size bytes */,
2 /* Bloom filter hash count */,
rappor::SPARSE_NOISE /* Noise level */,
UMA_RAPPOR_GROUP /* Recording group */
},
};
} // namespace internal
} // namespace rappor
#endif // COMPONENTS_RAPPOR_PUBLIC_RAPPOR_PARAMETERS_H_

@ -1,44 +0,0 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_PUBLIC_RAPPOR_SERVICE_H_
#define COMPONENTS_RAPPOR_PUBLIC_RAPPOR_SERVICE_H_
#include <memory>
#include <string>
#include "base/memory/weak_ptr.h"
#include "components/rappor/public/rappor_parameters.h"
#include "components/rappor/public/sample.h"
namespace rappor {
// This class provides a public interface for recording samples for rappor
// metrics, which other components can be depended on.
class RapporService : public base::SupportsWeakPtr<RapporService> {
public:
// Constructs a Sample object for the caller to record fields in.
virtual std::unique_ptr<Sample> CreateSample(RapporType) = 0;
// Records a Sample of rappor metric specified by |metric_name|.
//
// example:
// std::unique_ptr<Sample> sample =
// rappor_service->CreateSample(MY_METRIC_TYPE);
// sample->SetStringField("Field1", "some string");
// sample->SetFlagsValue("Field2", SOME|FLAGS);
// rappor_service->RecordSample("MyMetric", std::move(sample));
virtual void RecordSample(const std::string& metric_name,
std::unique_ptr<Sample> sample) = 0;
// Records a sample of the rappor metric specified by |metric_name|.
// Creates and initializes the metric, if it doesn't yet exist.
virtual void RecordSampleString(const std::string& metric_name,
RapporType type,
const std::string& sample) = 0;
};
} // namespace rappor
#endif // COMPONENTS_RAPPOR_PUBLIC_RAPPOR_SERVICE_H_

@ -1,41 +0,0 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_PUBLIC_RAPPOR_UTILS_H_
#define COMPONENTS_RAPPOR_PUBLIC_RAPPOR_UTILS_H_
#include <string>
#include "components/rappor/public/rappor_service.h"
class GURL;
namespace rappor {
// Records a string to a Rappor metric.
// If |rappor_service| is NULL, this call does nothing.
void SampleString(RapporService* rappor_service,
const std::string& metric,
RapporType type,
const std::string& sample);
// Extract the domain and registry for a sample from a GURL.
// For file:// urls this will just return "file://" and for other special
// schemes like chrome-extension will return the scheme and host.
std::string GetDomainAndRegistrySampleFromGURL(const GURL& gurl);
// Records the domain and registry of a url to a Rappor metric.
// If |rappor_service| is NULL, this call does nothing.
void SampleDomainAndRegistryFromGURL(RapporService* rappor_service,
const std::string& metric,
const GURL& gurl);
// Returns NULL if there is no default service.
RapporService* GetDefaultService();
void SetDefaultServiceAccessor(RapporService* (*getDefaultService)());
} // namespace rappor
#endif // COMPONENTS_RAPPOR_PUBLIC_RAPPOR_UTILS_H_

@ -1,92 +0,0 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_PUBLIC_SAMPLE_H_
#define COMPONENTS_RAPPOR_PUBLIC_SAMPLE_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <string>
#include "base/macros.h"
#include "components/rappor/public/rappor_parameters.h"
namespace rappor {
class RapporReports;
class RapporServiceImpl;
class TestSamplerFactory;
// Sample is a container for information about a single instance of some event
// we are sending Rappor data about. It may contain multiple different fields,
// which describe different details of the event, and they will be sent in the
// same Rappor report, enabling analysis of correlations between those fields.
class Sample {
public:
virtual ~Sample();
// Sets a string value field in this sample.
virtual void SetStringField(const std::string& field_name,
const std::string& value);
// TODO(holte): Move all callers to the version with NoiseLevel.
virtual void SetFlagsField(const std::string& field_name,
uint64_t flags,
size_t num_flags);
// Sets a group of boolean flags as a field in this sample, with the
// specified noise level.
// |flags| should be a set of boolean flags stored in the lowest |num_flags|
// bits of |flags|.
virtual void SetFlagsField(const std::string& field_name,
uint64_t flags,
size_t num_flags,
NoiseLevel noise_level);
// Sets an integer value field in this sample, at the given noise level.
virtual void SetUInt64Field(const std::string& field_name,
uint64_t value,
NoiseLevel noise_level);
// Generate randomized reports and store them in |reports|.
virtual void ExportMetrics(const std::string& secret,
const std::string& metric_name,
RapporReports* reports) const;
const RapporParameters& parameters() { return parameters_; }
private:
friend class TestSamplerFactory;
friend class RapporServiceImpl;
friend class TestSample;
// Constructs a sample. Instead of calling this directly, call
// RapporService::MakeSampleObj to create a sample.
Sample(int32_t cohort_seed, const RapporParameters& parameters);
const RapporParameters parameters_;
// Offset used for bloom filter hash functions.
uint32_t bloom_offset_;
struct FieldInfo {
// Size of the field, in bytes.
size_t size;
// The non-randomized report value for the field.
uint64_t value;
// The noise level to use when creating a report for the field.
NoiseLevel noise_level;
};
// Information about all recorded fields.
std::map<std::string, FieldInfo> field_info_;
DISALLOW_COPY_AND_ASSIGN(Sample);
};
} // namespace rappor
#endif // COMPONENTS_RAPPOR_PUBLIC_SAMPLE_H_

@ -1,49 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/rappor_metric.h"
#include "base/check_op.h"
#include "base/rand_util.h"
#include "components/rappor/public/rappor_parameters.h"
#include "components/rappor/reports.h"
namespace rappor {
RapporMetric::RapporMetric(const std::string& metric_name,
const RapporParameters& parameters,
int32_t cohort_seed)
: metric_name_(metric_name),
parameters_(parameters),
sample_count_(0),
bloom_filter_(parameters.bloom_filter_size_bytes,
parameters.bloom_filter_hash_function_count,
(cohort_seed % parameters.num_cohorts) *
parameters.bloom_filter_hash_function_count) {
DCHECK_GE(cohort_seed, 0);
DCHECK_LT(cohort_seed, RapporParameters::kMaxCohorts);
// Since cohort_seed is in the range [0, kMaxCohorts), num_cohorts should
// divide kMaxCohorts for each cohort to have equal weight.
DCHECK_EQ(0, RapporParameters::kMaxCohorts % parameters.num_cohorts);
}
RapporMetric::~RapporMetric() {}
void RapporMetric::AddSample(const std::string& str) {
++sample_count_;
// Replace the previous sample with a 1 in sample_count_ chance so that each
// sample has equal probability of being reported.
if (base::RandGenerator(sample_count_) == 0) {
bloom_filter_.SetString(str);
}
}
ByteVector RapporMetric::GetReport(const std::string& secret) const {
return internal::GenerateReport(
secret,
internal::kNoiseParametersForLevel[parameters().noise_level],
bytes());
}
} // namespace rappor

@ -1,65 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_RAPPOR_METRIC_H_
#define COMPONENTS_RAPPOR_RAPPOR_METRIC_H_
#include <stdint.h>
#include <string>
#include "base/macros.h"
#include "components/rappor/bloom_filter.h"
#include "components/rappor/byte_vector_utils.h"
#include "components/rappor/public/rappor_parameters.h"
namespace rappor {
// A RapporMetric is an object that collects string samples into a Bloom filter,
// and generates randomized reports about the collected data.
//
// This class should not be used directly by metrics clients. Record metrics
// using RapporServiceImpl::RecordSample or RapporService::RecordSample instead.
//
// For a full description of the rappor metrics, see
// http://www.chromium.org/developers/design-documents/rappor
class RapporMetric {
public:
// Takes the |metric_name| that this will be reported to the server with,
// a |parameters| describing size and probability weights used in recording
// this metric, and a |cohort| value, which determines the hash functions
// used in the Bloom filter.
RapporMetric(const std::string& metric_name,
const RapporParameters& parameters,
int32_t cohort);
~RapporMetric();
// Records an additional sample in the Bloom filter.
// A random sample will be used when reporting this metric when more than one
// sample is collected in the same reporting interval.
void AddSample(const std::string& str);
// Retrieves the current Bloom filter bits.
const ByteVector& bytes() const { return bloom_filter_.bytes(); }
// Gets the parameter values this metric was constructed with.
const RapporParameters& parameters() const { return parameters_; }
// Generates the bits to report for this metric. Using the secret as a seed,
// randomly selects bits for redaction. Then flips coins to generate the
// final report bits.
ByteVector GetReport(const std::string& secret) const;
private:
const std::string metric_name_;
const RapporParameters parameters_;
uint32_t sample_count_;
BloomFilter bloom_filter_;
DISALLOW_COPY_AND_ASSIGN(RapporMetric);
};
} // namespace rappor
#endif // COMPONENTS_RAPPOR_RAPPOR_METRIC_H_

@ -1,38 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/rappor_metric.h"
#include <stdlib.h>
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace rappor {
const RapporParameters kRapporMetricTestParameters = {
1 /* Num cohorts */,
16 /* Bloom filter size bytes */,
4 /* Bloom filter hash count */,
NORMAL_NOISE /* Noise level */,
UMA_RAPPOR_GROUP /* Recording group (not used) */,
};
// Check for basic syntax and use.
TEST(RapporMetricTest, BasicMetric) {
RapporMetric testMetric("MyRappor", kRapporMetricTestParameters, 0);
testMetric.AddSample("Bar");
EXPECT_EQ(0x80, testMetric.bytes()[1]);
}
TEST(RapporMetricTest, GetReport) {
RapporMetric metric("MyRappor", kRapporMetricTestParameters, 0);
const ByteVector report = metric.GetReport(
HmacByteVectorGenerator::GenerateEntropyInput());
EXPECT_EQ(16u, report.size());
}
} // namespace rappor

@ -1,24 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/public/rappor_parameters.h"
#include "base/compiler_specific.h"
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
namespace rappor {
std::string RapporParameters::ToString() const {
return base::StringPrintf("{ %d, %" PRIuS ", %d, %d, %d }",
num_cohorts,
bloom_filter_size_bytes,
bloom_filter_hash_function_count,
noise_level,
recording_group);
}
const int RapporParameters::kMaxCohorts = 512;
} // namespace rappor

@ -1,26 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/rappor_pref_names.h"
namespace rappor {
namespace prefs {
// Deprecated: Old cohort selection pref, should be cleared.
const char kRapporCohortDeprecated[] = "rappor.cohort";
// A randomly generated number, which determines cohorts data is reported for.
const char kRapporCohortSeed[] = "rappor.cohort_seed";
// Timestamp of the last time we sampled daily metrics.
const char kRapporLastDailySample[] = "rappor.last_daily_sample";
// A base-64 encoded, randomly generated byte string, which is used as a seed
// for redacting collected data.
// Important: This value should remain secret at the client, and never be
// reported on the network, or to the server.
const char kRapporSecret[] = "rappor.secret";
} // namespace prefs
} // namespace rappor

@ -1,21 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_RAPPOR_PREF_NAMES_H_
#define COMPONENTS_RAPPOR_RAPPOR_PREF_NAMES_H_
namespace rappor {
namespace prefs {
// Alphabetical list of preference names specific to the Rappor
// component. Keep alphabetized, and document each in the .cc file.
extern const char kRapporCohortDeprecated[];
extern const char kRapporCohortSeed[];
extern const char kRapporLastDailySample[];
extern const char kRapporSecret[];
} // namespace prefs
} // namespace rappor
#endif // COMPONENTS_RAPPOR_RAPPOR_PREF_NAMES_H_

@ -1,99 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/rappor_prefs.h"
#include "base/base64.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "components/metrics/daily_event.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/rappor/byte_vector_utils.h"
#include "components/rappor/public/rappor_parameters.h"
#include "components/rappor/rappor_pref_names.h"
namespace rappor {
namespace internal {
const char kLoadCohortHistogramName[] = "Rappor.LoadCohortResult";
const char kLoadSecretHistogramName[] = "Rappor.LoadSecretResult";
namespace {
void RecordLoadCohortResult(LoadResult reason) {
UMA_HISTOGRAM_ENUMERATION(kLoadCohortHistogramName,
reason,
NUM_LOAD_RESULTS);
}
void RecordLoadSecretResult(LoadResult reason) {
UMA_HISTOGRAM_ENUMERATION(kLoadSecretHistogramName,
reason,
NUM_LOAD_RESULTS);
}
} // namespace
void RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(prefs::kRapporSecret, std::string());
registry->RegisterIntegerPref(prefs::kRapporCohortDeprecated, -1);
registry->RegisterIntegerPref(prefs::kRapporCohortSeed, -1);
metrics::DailyEvent::RegisterPref(registry, prefs::kRapporLastDailySample);
}
int32_t LoadCohort(PrefService* pref_service) {
// Ignore and delete old cohort parameter.
pref_service->ClearPref(prefs::kRapporCohortDeprecated);
int32_t cohort = pref_service->GetInteger(prefs::kRapporCohortSeed);
// If the user is already assigned to a valid cohort, we're done.
if (cohort >= 0 && cohort < RapporParameters::kMaxCohorts) {
RecordLoadCohortResult(LOAD_SUCCESS);
DVLOG(2) << "Rappor cohort loaded.";
return cohort;
}
// This is the first time the client has started the service (or their
// preferences were corrupted). Randomly assign them to a cohort.
RecordLoadCohortResult(cohort == -1 ? LOAD_EMPTY_VALUE : LOAD_CORRUPT_VALUE);
cohort = base::RandGenerator(RapporParameters::kMaxCohorts);
DVLOG(2) << "Selected a new Rappor cohort: " << cohort;
pref_service->SetInteger(prefs::kRapporCohortSeed, cohort);
return cohort;
}
std::string LoadSecret(PrefService* pref_service) {
std::string secret;
std::string secret_base64 = pref_service->GetString(prefs::kRapporSecret);
if (!secret_base64.empty()) {
bool decoded = base::Base64Decode(secret_base64, &secret);
if (decoded &&
secret.size() == HmacByteVectorGenerator::kEntropyInputSize) {
DVLOG(2) << "Rappor secret loaded.";
RecordLoadSecretResult(LOAD_SUCCESS);
return secret;
}
// If the preference fails to decode, or is the wrong size, it must be
// corrupt, so continue as though it didn't exist yet and generate a new
// one.
DVLOG(2) << "Corrupt Rappor secret found.";
RecordLoadSecretResult(LOAD_CORRUPT_VALUE);
} else {
DVLOG(2) << "No Rappor secret found.";
RecordLoadSecretResult(LOAD_EMPTY_VALUE);
}
DVLOG(2) << "Generated a new Rappor secret.";
secret = HmacByteVectorGenerator::GenerateEntropyInput();
base::Base64Encode(secret, &secret_base64);
pref_service->SetString(prefs::kRapporSecret, secret_base64);
return secret;
}
} // namespace internal
} // namespace rappor

@ -1,46 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_RAPPOR_PREFS_H_
#define COMPONENTS_RAPPOR_RAPPOR_PREFS_H_
#include <stdint.h>
#include <string>
class PrefService;
class PrefRegistrySimple;
namespace rappor {
namespace internal {
enum LoadResult {
LOAD_SUCCESS = 0,
LOAD_EMPTY_VALUE,
LOAD_CORRUPT_VALUE,
NUM_LOAD_RESULTS,
};
extern const char kLoadCohortHistogramName[];
extern const char kLoadSecretHistogramName[];
// Registers all rappor preferences.
void RegisterPrefs(PrefRegistrySimple* registry);
// Retrieves the cohort number this client was assigned to, generating it if
// doesn't already exist. The cohort should be persistent.
int32_t LoadCohort(PrefService* pref_service);
// Retrieves the value for secret from preferences, generating it if doesn't
// already exist. The secret should be persistent, so that additional bits
// from the client do not get exposed over time.
std::string LoadSecret(PrefService* pref_service);
} // namespace internal
} // namespace rappor
#endif // COMPONENTS_RAPPOR_RAPPOR_PREFS_H_

@ -1,139 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/rappor_prefs.h"
#include <stdint.h>
#include "base/base64.h"
#include "base/macros.h"
#include "base/test/metrics/histogram_tester.h"
#include "components/prefs/testing_pref_service.h"
#include "components/rappor/byte_vector_utils.h"
#include "components/rappor/proto/rappor_metric.pb.h"
#include "components/rappor/rappor_pref_names.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace rappor {
namespace internal {
namespace {
// Convert a secret to base 64 and store it in preferences.
void StoreSecret(const std::string& secret,
TestingPrefServiceSimple* test_prefs) {
std::string secret_base64;
base::Base64Encode(secret, &secret_base64);
test_prefs->SetString(prefs::kRapporSecret, secret_base64);
}
// Verify that the current value of the secret pref matches the loaded secret.
void ExpectConsistentSecret(const TestingPrefServiceSimple& test_prefs,
const std::string& loaded_secret) {
std::string pref = test_prefs.GetString(prefs::kRapporSecret);
std::string decoded_pref;
EXPECT_TRUE(base::Base64Decode(pref, &decoded_pref));
EXPECT_EQ(loaded_secret, decoded_pref);
}
} // namespace
class RapporPrefsTest : public testing::Test {
public:
RapporPrefsTest() {
RegisterPrefs(test_prefs_.registry());
}
protected:
base::HistogramTester tester_;
TestingPrefServiceSimple test_prefs_;
DISALLOW_COPY_AND_ASSIGN(RapporPrefsTest);
};
TEST_F(RapporPrefsTest, EmptyCohort) {
test_prefs_.ClearPref(prefs::kRapporCohortSeed);
// Loaded cohort should have been rerolled into a valid number.
int32_t cohort = LoadCohort(&test_prefs_);
tester_.ExpectUniqueSample(kLoadCohortHistogramName, LOAD_EMPTY_VALUE, 1);
EXPECT_GE(cohort, 0);
EXPECT_LT(cohort, RapporParameters::kMaxCohorts);
// The preferences should be consistent with the loaded value.
int32_t pref = test_prefs_.GetInteger(prefs::kRapporCohortSeed);
EXPECT_EQ(pref, cohort);
}
TEST_F(RapporPrefsTest, LoadCohort) {
test_prefs_.SetInteger(prefs::kRapporCohortSeed, 1);
// Loading the valid cohort should just retrieve it.
int32_t cohort = LoadCohort(&test_prefs_);
tester_.ExpectUniqueSample(kLoadCohortHistogramName, LOAD_SUCCESS, 1);
EXPECT_EQ(1, cohort);
// The preferences should be consistent with the loaded value.
int32_t pref = test_prefs_.GetInteger(prefs::kRapporCohortSeed);
EXPECT_EQ(pref, cohort);
}
TEST_F(RapporPrefsTest, CorruptCohort) {
// Set an invalid cohort value in the preference.
test_prefs_.SetInteger(prefs::kRapporCohortSeed, -10);
// Loaded cohort should have been rerolled into a valid number.
int32_t cohort = LoadCohort(&test_prefs_);
tester_.ExpectUniqueSample(kLoadCohortHistogramName, LOAD_CORRUPT_VALUE, 1);
EXPECT_GE(cohort, 0);
EXPECT_LT(cohort, RapporParameters::kMaxCohorts);
// The preferences should be consistent with the loaded value.
int32_t pref = test_prefs_.GetInteger(prefs::kRapporCohortSeed);
EXPECT_EQ(pref, cohort);
}
TEST_F(RapporPrefsTest, EmptySecret) {
test_prefs_.ClearPref(prefs::kRapporSecret);
// Loaded secret should be rerolled from empty.
std::string secret2 = LoadSecret(&test_prefs_);
tester_.ExpectUniqueSample(kLoadSecretHistogramName, LOAD_EMPTY_VALUE, 1);
EXPECT_EQ(HmacByteVectorGenerator::kEntropyInputSize, secret2.size());
// The stored preference should also be updated.
ExpectConsistentSecret(test_prefs_, secret2);
}
TEST_F(RapporPrefsTest, LoadSecret) {
std::string secret1 = HmacByteVectorGenerator::GenerateEntropyInput();
StoreSecret(secret1, &test_prefs_);
// Secret should load successfully.
std::string secret2 = LoadSecret(&test_prefs_);
tester_.ExpectUniqueSample(kLoadSecretHistogramName, LOAD_SUCCESS, 1);
EXPECT_EQ(secret1, secret2);
// The stored preference should also be unchanged.
ExpectConsistentSecret(test_prefs_, secret2);
}
TEST_F(RapporPrefsTest, CorruptSecret) {
// Store an invalid secret in the preferences that won't decode as base64.
test_prefs_.SetString(prefs::kRapporSecret, "!!INVALID!!");
// We should have rerolled a new secret.
std::string secret2 = LoadSecret(&test_prefs_);
tester_.ExpectUniqueSample(kLoadSecretHistogramName, LOAD_CORRUPT_VALUE, 1);
EXPECT_EQ(HmacByteVectorGenerator::kEntropyInputSize, secret2.size());
// The stored preference should also be updated.
ExpectConsistentSecret(test_prefs_, secret2);
}
TEST_F(RapporPrefsTest, DecodableCorruptSecret) {
// Store an invalid secret in the preferences that will decode as base64.
std::string secret1 = "!!INVALID!!";
StoreSecret(secret1, &test_prefs_);
// We should have rerolled a new secret.
std::string secret2 = LoadSecret(&test_prefs_);
tester_.ExpectUniqueSample(kLoadSecretHistogramName, LOAD_CORRUPT_VALUE, 1);
EXPECT_NE(secret1, secret2);
EXPECT_EQ(HmacByteVectorGenerator::kEntropyInputSize, secret2.size());
// The stored preference should also be updated.
ExpectConsistentSecret(test_prefs_, secret2);
}
} // namespace internal
} // namespace rappor

@ -1,240 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/rappor_service_impl.h"
#include <memory>
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/metrics/metrics_hashes.h"
#include "base/time/time.h"
#include "components/rappor/log_uploader.h"
#include "components/rappor/proto/rappor_metric.pb.h"
#include "components/rappor/rappor_metric.h"
#include "components/rappor/rappor_pref_names.h"
#include "components/rappor/rappor_prefs.h"
#include "components/variations/variations_associated_data.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace rappor {
namespace {
// Seconds before the initial log is generated.
const int kInitialLogIntervalSeconds = 15;
// Interval between ongoing logs.
const int kLogIntervalSeconds = 30 * 60;
const char kMimeType[] = "application/vnd.chrome.rappor";
const char kRapporDailyEventHistogram[] = "Rappor.DailyEvent.IntervalType";
// The rappor server's URL.
const char kDefaultServerUrl[] = "https://clients4.google.com/rappor";
} // namespace
RapporServiceImpl::RapporServiceImpl(
PrefService* pref_service,
base::RepeatingCallback<bool(void)> is_incognito_callback)
: pref_service_(pref_service),
is_incognito_callback_(std::move(is_incognito_callback)),
cohort_(-1),
daily_event_(pref_service,
prefs::kRapporLastDailySample,
kRapporDailyEventHistogram),
recording_enabled_(false) {}
RapporServiceImpl::~RapporServiceImpl() {}
void RapporServiceImpl::AddDailyObserver(
std::unique_ptr<metrics::DailyEvent::Observer> observer) {
daily_event_.AddObserver(std::move(observer));
}
void RapporServiceImpl::Initialize(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!IsInitialized());
const GURL server_url = GURL(kDefaultServerUrl);
if (!server_url.is_valid()) {
DVLOG(1) << server_url.spec() << " is invalid. "
<< "RapporServiceImpl not started.";
return;
}
DVLOG(1) << "RapporServiceImpl reporting to " << server_url.spec();
InitializeInternal(
std::make_unique<LogUploader>(server_url, kMimeType, url_loader_factory),
internal::LoadCohort(pref_service_), internal::LoadSecret(pref_service_));
}
void RapporServiceImpl::Update(bool may_record, bool may_upload) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(IsInitialized());
if (recording_enabled_ != may_record) {
recording_enabled_ = may_record;
if (!may_record) {
DVLOG(1) << "Rappor service stopped because all groups were disabled.";
CancelNextLogRotation();
} else {
DVLOG(1) << "RapporServiceImpl started.";
ScheduleNextLogRotation(
base::TimeDelta::FromSeconds(kInitialLogIntervalSeconds));
}
}
DVLOG(1) << "RapporServiceImpl recording_groups=" << recording_enabled_
<< " may_upload=" << may_upload;
if (may_upload) {
uploader_->Start();
} else {
uploader_->Stop();
}
}
// static
void RapporServiceImpl::RegisterPrefs(PrefRegistrySimple* registry) {
internal::RegisterPrefs(registry);
}
void RapporServiceImpl::InitializeInternal(
std::unique_ptr<LogUploaderInterface> uploader,
int32_t cohort,
const std::string& secret) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!IsInitialized());
DCHECK(secret_.empty());
uploader_.swap(uploader);
cohort_ = cohort;
secret_ = secret;
}
void RapporServiceImpl::CancelNextLogRotation() {
DCHECK(thread_checker_.CalledOnValidThread());
metrics_map_.clear();
log_rotation_timer_.Stop();
}
void RapporServiceImpl::ScheduleNextLogRotation(base::TimeDelta interval) {
log_rotation_timer_.Start(FROM_HERE, interval, this,
&RapporServiceImpl::OnLogInterval);
}
void RapporServiceImpl::OnLogInterval() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(uploader_);
DVLOG(2) << "RapporServiceImpl::OnLogInterval";
daily_event_.CheckInterval();
RapporReports reports;
if (ExportMetrics(&reports)) {
std::string log_text;
bool success = reports.SerializeToString(&log_text);
DCHECK(success);
DVLOG(1) << "RapporServiceImpl sending a report of "
<< reports.report_size() << " value(s).";
uploader_->QueueLog(log_text);
}
ScheduleNextLogRotation(base::TimeDelta::FromSeconds(kLogIntervalSeconds));
}
bool RapporServiceImpl::ExportMetrics(RapporReports* reports) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_GE(cohort_, 0);
reports->set_cohort(cohort_);
for (const auto& kv : metrics_map_) {
const RapporMetric* metric = kv.second.get();
RapporReports::Report* report = reports->add_report();
report->set_name_hash(base::HashMetricName(kv.first));
ByteVector bytes = metric->GetReport(secret_);
report->set_bits(std::string(bytes.begin(), bytes.end()));
DVLOG(2) << "Exporting metric " << kv.first;
}
metrics_map_.clear();
sampler_.ExportMetrics(secret_, reports);
DVLOG(2) << "Generated a report with " << reports->report_size()
<< " metrics.";
return reports->report_size() > 0;
}
bool RapporServiceImpl::IsInitialized() const {
return cohort_ >= 0;
}
bool RapporServiceImpl::RecordingAllowed(const RapporParameters& parameters) {
// Skip recording in incognito mode.
if (is_incognito_callback_.Run()) {
DVLOG(2) << "Metric not logged due to incognito mode.";
return false;
}
// Skip this metric if its recording_group is not enabled.
if (!recording_enabled_) {
DVLOG(2) << "Metric not logged due to recording_enabled_ = false.";
return false;
}
return true;
}
void RapporServiceImpl::RecordSampleString(const std::string& metric_name,
RapporType type,
const std::string& sample) {
DCHECK(thread_checker_.CalledOnValidThread());
// Ignore the sample if the service hasn't started yet.
if (!IsInitialized())
return;
DCHECK_LT(type, NUM_RAPPOR_TYPES);
const RapporParameters& parameters = internal::kRapporParametersForType[type];
DVLOG(2) << "Recording sample \"" << sample << "\" for metric \""
<< metric_name << "\" of type: " << type;
RecordSampleInternal(metric_name, parameters, sample);
}
void RapporServiceImpl::RecordSampleInternal(const std::string& metric_name,
const RapporParameters& parameters,
const std::string& sample) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(IsInitialized());
if (!RecordingAllowed(parameters))
return;
RapporMetric* metric = LookUpMetric(metric_name, parameters);
metric->AddSample(sample);
}
RapporMetric* RapporServiceImpl::LookUpMetric(
const std::string& metric_name,
const RapporParameters& parameters) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(IsInitialized());
auto it = metrics_map_.find(metric_name);
if (it != metrics_map_.end()) {
RapporMetric* metric = it->second.get();
DCHECK_EQ(parameters.ToString(), metric->parameters().ToString());
return metric;
}
RapporMetric* new_metric = new RapporMetric(metric_name, parameters, cohort_);
metrics_map_[metric_name] = base::WrapUnique(new_metric);
return new_metric;
}
std::unique_ptr<Sample> RapporServiceImpl::CreateSample(RapporType type) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(IsInitialized());
return base::WrapUnique(
new Sample(cohort_, internal::kRapporParametersForType[type]));
}
void RapporServiceImpl::RecordSample(const std::string& metric_name,
std::unique_ptr<Sample> sample) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!RecordingAllowed(sample->parameters()))
return;
DVLOG(1) << "Recording sample of metric \"" << metric_name << "\"";
sampler_.AddSample(metric_name, std::move(sample));
}
} // namespace rappor

@ -1,172 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_RAPPOR_SERVICE_IMPL_H_
#define COMPONENTS_RAPPOR_RAPPOR_SERVICE_IMPL_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "components/metrics/daily_event.h"
#include "components/rappor/public/rappor_parameters.h"
#include "components/rappor/public/rappor_service.h"
#include "components/rappor/public/sample.h"
#include "components/rappor/sampler.h"
class PrefRegistrySimple;
class PrefService;
namespace network {
class SharedURLLoaderFactory;
}
namespace rappor {
class LogUploaderInterface;
class RapporMetric;
class RapporReports;
// This class provides an interface for recording samples for rappor metrics,
// and periodically generates and uploads reports based on the collected data.
class RapporServiceImpl : public RapporService {
public:
// Constructs a RapporServiceImpl.
// Calling code is responsible for ensuring that the lifetime of
// |pref_service| is longer than the lifetime of RapporServiceImpl.
// |is_incognito_callback| will be called to test if incognito mode is active.
RapporServiceImpl(PrefService* pref_service,
base::RepeatingCallback<bool(void)> is_incognito_callback);
virtual ~RapporServiceImpl();
// Add an observer for collecting daily metrics.
void AddDailyObserver(
std::unique_ptr<metrics::DailyEvent::Observer> observer);
// Initializes the rappor service, including loading the cohort and secret
// preferences from disk.
void Initialize(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
// Updates the settings for metric recording and uploading.
// The RapporServiceImpl must be initialized before this method is called.
// If |may_record| is true, data will be recorded and periodic reports will
// be generated and queued for upload.
// If |may_upload| is true, reports will be uploaded from the queue.
void Update(bool may_record, bool may_upload);
// Constructs a Sample object for the caller to record fields in.
std::unique_ptr<Sample> CreateSample(RapporType) override;
// Records a Sample of rappor metric specified by |metric_name|.
//
// example:
// std::unique_ptr<Sample> sample =
// rappor_service->CreateSample(MY_METRIC_TYPE);
// sample->SetStringField("Field1", "some string");
// sample->SetFlagsValue("Field2", SOME|FLAGS);
// rappor_service->RecordSample("MyMetric", std::move(sample));
//
// This will result in a report setting two metrics "MyMetric.Field1" and
// "MyMetric.Field2", and they will both be generated from the same sample,
// to allow for correlations to be computed.
void RecordSample(const std::string& metric_name,
std::unique_ptr<Sample> sample) override;
// Records a sample of the rappor metric specified by |metric_name|.
// Creates and initializes the metric, if it doesn't yet exist.
void RecordSampleString(const std::string& metric_name,
RapporType type,
const std::string& sample) override;
// Registers the names of all of the preferences used by RapporServiceImpl in
// the provided PrefRegistry. This should be called before calling Start().
static void RegisterPrefs(PrefRegistrySimple* registry);
protected:
// Initializes the state of the RapporServiceImpl.
void InitializeInternal(std::unique_ptr<LogUploaderInterface> uploader,
int32_t cohort,
const std::string& secret);
// Cancels the next call to OnLogInterval.
virtual void CancelNextLogRotation();
// Schedules the next call to OnLogInterval.
virtual void ScheduleNextLogRotation(base::TimeDelta interval);
// Logs all of the collected metrics to the reports proto message and clears
// the internal map. Exposed for tests. Returns true if any metrics were
// recorded.
bool ExportMetrics(RapporReports* reports);
private:
// Records a sample of the rappor metric specified by |parameters|.
// Creates and initializes the metric, if it doesn't yet exist.
// Exposed for tests.
void RecordSampleInternal(const std::string& metric_name,
const RapporParameters& parameters,
const std::string& sample);
// Checks if the service has been started successfully.
bool IsInitialized() const;
// Called whenever the logging interval elapses to generate a new log of
// reports and pass it to the uploader.
void OnLogInterval();
// Check if recording of the metric is allowed, given it's parameters.
// This will check that we are not in incognito mode, and that the
// appropriate recording group is enabled.
bool RecordingAllowed(const RapporParameters& parameters);
// Finds a metric in the metrics_map_, creating it if it doesn't already
// exist.
RapporMetric* LookUpMetric(const std::string& metric_name,
const RapporParameters& parameters);
// A weak pointer to the PrefService used to read and write preferences.
PrefService* pref_service_;
// A callback for testing if incognito mode is active;
const base::RepeatingCallback<bool(void)> is_incognito_callback_;
// Client-side secret used to generate fake bits.
std::string secret_;
// The cohort this client is assigned to. -1 is uninitialized.
int32_t cohort_;
// Timer which schedules calls to OnLogInterval().
base::OneShotTimer log_rotation_timer_;
// A daily event for collecting metrics once a day.
metrics::DailyEvent daily_event_;
// A private LogUploader instance for sending reports to the server.
std::unique_ptr<LogUploaderInterface> uploader_;
// Whether new data can be recorded.
bool recording_enabled_;
// We keep all registered metrics in a map, from name to metric.
std::map<std::string, std::unique_ptr<RapporMetric>> metrics_map_;
internal::Sampler sampler_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(RapporServiceImpl);
};
} // namespace rappor
#endif // COMPONENTS_RAPPOR_RAPPOR_SERVICE_IMPL_H_

@ -1,134 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/rappor_service_impl.h"
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <utility>
#include "base/base64.h"
#include "base/metrics/metrics_hashes.h"
#include "components/prefs/testing_pref_service.h"
#include "components/rappor/byte_vector_utils.h"
#include "components/rappor/proto/rappor_metric.pb.h"
#include "components/rappor/public/rappor_parameters.h"
#include "components/rappor/rappor_pref_names.h"
#include "components/rappor/test_log_uploader.h"
#include "components/rappor/test_rappor_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace rappor {
TEST(RapporServiceImplTest, Update) {
// Test rappor service initially has uploading and reporting enabled.
TestRapporServiceImpl rappor_service;
EXPECT_LT(base::TimeDelta(), rappor_service.next_rotation());
EXPECT_TRUE(rappor_service.test_uploader()->is_running());
// Disabling both should stop both uploads and reports.
rappor_service.Update(false, false);
EXPECT_EQ(base::TimeDelta(), rappor_service.next_rotation());
EXPECT_FALSE(rappor_service.test_uploader()->is_running());
// Recording, but no reporting.
rappor_service.Update(true, false);
// Reports generation should still be scheduled.
EXPECT_LT(base::TimeDelta(), rappor_service.next_rotation());
EXPECT_FALSE(rappor_service.test_uploader()->is_running());
// Recording and reporting enabled.
rappor_service.Update(true, true);
EXPECT_LT(base::TimeDelta(), rappor_service.next_rotation());
EXPECT_TRUE(rappor_service.test_uploader()->is_running());
}
// Check that samples can be recorded and exported.
TEST(RapporServiceImplTest, RecordAndExportMetrics) {
TestRapporServiceImpl rappor_service;
// Multiple samples for the same metric should only generate one report.
rappor_service.RecordSampleString("MyMetric", ETLD_PLUS_ONE_RAPPOR_TYPE,
"foo");
rappor_service.RecordSampleString("MyMetric", ETLD_PLUS_ONE_RAPPOR_TYPE,
"bar");
RapporReports reports;
rappor_service.GetReports(&reports);
EXPECT_EQ(1, reports.report_size());
const RapporReports::Report& report = reports.report(0);
EXPECT_TRUE(report.name_hash());
// ETLD_PLUS_ONE_RAPPOR_TYPE has 128 bits
EXPECT_EQ(16u, report.bits().size());
}
// Check that reporting_enabled_ is respected.
TEST(RapporServiceImplTest, UmaRecordingGroup) {
TestRapporServiceImpl rappor_service;
rappor_service.Update(false, false);
// Reporting disabled.
rappor_service.RecordSampleString("UmaMetric", UMA_RAPPOR_TYPE, "foo");
RapporReports reports;
rappor_service.GetReports(&reports);
EXPECT_EQ(0, reports.report_size());
}
// Check that GetRecordedSampleForMetric works as expected.
TEST(RapporServiceImplTest, GetRecordedSampleForMetric) {
TestRapporServiceImpl rappor_service;
// Multiple samples for the same metric; only the latest is remembered.
rappor_service.RecordSampleString("MyMetric", ETLD_PLUS_ONE_RAPPOR_TYPE,
"foo");
rappor_service.RecordSampleString("MyMetric", ETLD_PLUS_ONE_RAPPOR_TYPE,
"bar");
std::string sample;
RapporType type;
EXPECT_FALSE(
rappor_service.GetRecordedSampleForMetric("WrongMetric", &sample, &type));
EXPECT_TRUE(
rappor_service.GetRecordedSampleForMetric("MyMetric", &sample, &type));
EXPECT_EQ("bar", sample);
EXPECT_EQ(ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
// Check that the incognito is respected.
TEST(RapporServiceImplTest, Incognito) {
TestRapporServiceImpl rappor_service;
rappor_service.set_is_incognito(true);
rappor_service.RecordSampleString("MyMetric", UMA_RAPPOR_TYPE, "foo");
RapporReports reports;
rappor_service.GetReports(&reports);
EXPECT_EQ(0, reports.report_size());
}
// Check that Sample objects record correctly.
TEST(RapporServiceImplTest, RecordSample) {
TestRapporServiceImpl rappor_service;
std::unique_ptr<Sample> sample = rappor_service.CreateSample(UMA_RAPPOR_TYPE);
sample->SetStringField("Url", "example.com");
sample->SetFlagsField("Flags1", 0xbcd, 12);
rappor_service.RecordSample("ObjMetric", std::move(sample));
uint64_t url_hash = base::HashMetricName("ObjMetric.Url");
uint64_t flags_hash = base::HashMetricName("ObjMetric.Flags1");
RapporReports reports;
rappor_service.GetReports(&reports);
EXPECT_EQ(2, reports.report_size());
size_t url_index = reports.report(0).name_hash() == url_hash ? 0 : 1;
size_t flags_index = url_index == 0 ? 1 : 0;
EXPECT_EQ(url_hash, reports.report(url_index).name_hash());
EXPECT_EQ(4u, reports.report(url_index).bits().size());
EXPECT_EQ(flags_hash, reports.report(flags_index).name_hash());
EXPECT_EQ(2u, reports.report(flags_index).bits().size());
}
} // namespace rappor

@ -1,56 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/public/rappor_utils.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/base/url_util.h"
#include "url/gurl.h"
namespace rappor {
void SampleString(RapporService* rappor_service,
const std::string& metric,
RapporType type,
const std::string& sample) {
if (!rappor_service)
return;
rappor_service->RecordSampleString(metric, type, sample);
}
std::string GetDomainAndRegistrySampleFromGURL(const GURL& gurl) {
if (gurl.SchemeIsHTTPOrHTTPS()) {
if (net::IsLocalhost(gurl))
return "localhost";
if (gurl.HostIsIPAddress())
return "ip_address";
return net::registry_controlled_domains::GetDomainAndRegistry(
gurl, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
}
if (gurl.SchemeIsFile())
return gurl.scheme() + "://";
return gurl.scheme() + "://" + gurl.host();
}
void SampleDomainAndRegistryFromGURL(RapporService* rappor_service,
const std::string& metric,
const GURL& gurl) {
if (!rappor_service)
return;
rappor_service->RecordSampleString(metric, rappor::ETLD_PLUS_ONE_RAPPOR_TYPE,
GetDomainAndRegistrySampleFromGURL(gurl));
}
RapporService* (*g_GetDefaultService)() = nullptr;
RapporService* GetDefaultService() {
return (g_GetDefaultService != nullptr) ? g_GetDefaultService() : nullptr;
}
void SetDefaultServiceAccessor(RapporService* (*getDefaultService)()) {
DCHECK(g_GetDefaultService == nullptr);
g_GetDefaultService = getDefaultService;
}
} // namespace rappor

@ -1,44 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/public/rappor_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace rappor {
// Test that extracting the sample works correctly for different schemes.
TEST(RapporSamplingTest, GetDomainAndRegistrySampleFromGURLTest) {
EXPECT_EQ("google.com", GetDomainAndRegistrySampleFromGURL(
GURL("https://www.GoOgLe.com:80/blah")));
EXPECT_EQ("file://", GetDomainAndRegistrySampleFromGURL(
GURL("file://foo/bar/baz")));
EXPECT_EQ("chrome-extension://abc1234", GetDomainAndRegistrySampleFromGURL(
GURL("chrome-extension://abc1234/foo.html")));
EXPECT_EQ("chrome-search://local-ntp", GetDomainAndRegistrySampleFromGURL(
GURL("chrome-search://local-ntp/local-ntp.html")));
EXPECT_EQ("localhost", GetDomainAndRegistrySampleFromGURL(
GURL("http://localhost:8000/foo.html")));
EXPECT_EQ("localhost", GetDomainAndRegistrySampleFromGURL(
GURL("http://127.0.0.1/foo.html")));
EXPECT_EQ("localhost",
GetDomainAndRegistrySampleFromGURL(GURL("http://[::1]/foo.html")));
EXPECT_EQ("ip_address", GetDomainAndRegistrySampleFromGURL(
GURL("http://192.168.0.1/foo.html")));
EXPECT_EQ("ip_address", GetDomainAndRegistrySampleFromGURL(
GURL("http://[2001:db8::1]/")));
EXPECT_EQ("", GetDomainAndRegistrySampleFromGURL(
GURL("http://www/")));
EXPECT_EQ("www.corp", GetDomainAndRegistrySampleFromGURL(
GURL("http://www.corp/")));
}
// Make sure recording a sample during tests, when the Rappor service is NULL,
// doesn't cause a crash.
TEST(RapporSamplingTest, SmokeTest) {
SampleDomainAndRegistryFromGURL(nullptr, std::string(), GURL());
}
} // namespace rappor

@ -1,52 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/reports.h"
#include "base/rand_util.h"
#include "base/strings/string_piece.h"
#include "components/rappor/byte_vector_utils.h"
#include "components/rappor/public/rappor_parameters.h"
namespace rappor {
namespace internal {
ByteVector GenerateReport(const std::string& secret,
const NoiseParameters& parameters,
const ByteVector& value) {
// Generate a deterministically random mask of fake data using the
// client's secret key + real data as a seed. The inclusion of the secret
// in the seed avoids correlations between real and fake data.
// The seed isn't a human-readable string.
const base::StringPiece personalization_string(
reinterpret_cast<const char*>(&value[0]), value.size());
HmacByteVectorGenerator hmac_generator(value.size(), secret,
personalization_string);
const ByteVector fake_mask =
hmac_generator.GetWeightedRandomByteVector(parameters.fake_prob);
ByteVector fake_bits =
hmac_generator.GetWeightedRandomByteVector(parameters.fake_one_prob);
// Redact most of the real data by replacing it with the fake data, hiding
// and limiting the amount of information an individual client reports on.
const ByteVector* fake_and_redacted_bits =
ByteVectorMerge(fake_mask, value, &fake_bits);
// Generate biased coin flips for each bit.
ByteVectorGenerator coin_generator(value.size());
const ByteVector zero_coins =
coin_generator.GetWeightedRandomByteVector(parameters.zero_coin_prob);
ByteVector one_coins =
coin_generator.GetWeightedRandomByteVector(parameters.one_coin_prob);
// Create a randomized response report on the fake and redacted data, sending
// the outcome of flipping a zero coin for the zero bits in that data, and of
// flipping a one coin for the one bits in that data, as the final report.
return *ByteVectorMerge(*fake_and_redacted_bits, zero_coins, &one_coins);
}
} // namespace internal
} // namespace rappor

@ -1,25 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_REPORTS_H_
#define COMPONENTS_RAPPOR_REPORTS_H_
#include "components/rappor/reports.h"
#include "components/rappor/byte_vector_utils.h"
namespace rappor {
namespace internal {
// Generate a randomized report for a single metric/field.
ByteVector GenerateReport(const std::string& secret,
const NoiseParameters& parameters,
const ByteVector& value);
} // namespace internal
} // namespace rappor
#endif // COMPONENTS_RAPPOR_REPORTS_H_

@ -1,72 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/reports.h"
#include <stdlib.h>
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace rappor {
const NoiseParameters kTestNoiseParameters = {
PROBABILITY_75 /* Fake data probability */,
PROBABILITY_50 /* Fake one probability */,
PROBABILITY_75 /* One coin probability */,
PROBABILITY_50 /* Zero coin probability */,
};
TEST(RapporMetricTest, GetReportStatistics) {
ByteVector real_bits(50);
// Set 152 bits (19 bytes)
for (char i = 0; i < 19; i++) {
real_bits[i] = 0xff;
}
const int real_bit_count = CountBits(real_bits);
EXPECT_EQ(real_bit_count, 152);
const std::string secret = HmacByteVectorGenerator::GenerateEntropyInput();
const ByteVector report =
internal::GenerateReport(secret, kTestNoiseParameters, real_bits);
// For the bits we actually set in the Bloom filter, get a count of how
// many of them reported true.
ByteVector from_true_reports = report;
// Real bits AND report bits.
ByteVectorMerge(real_bits, real_bits, &from_true_reports);
const int true_from_true_count = CountBits(from_true_reports);
// For the bits we didn't set in the Bloom filter, get a count of how
// many of them reported true.
ByteVector from_false_reports = report;
ByteVectorOr(real_bits, &from_false_reports);
const int true_from_false_count =
CountBits(from_false_reports) - real_bit_count;
// The probability of a true bit being true after redaction =
// [fake_prob]*[fake_true_prob] + (1-[fake_prob]) =
// .75 * .5 + (1-.75) = .625
// The probablity of a false bit being true after redaction =
// [fake_prob]*[fake_true_prob] = .375
// The probability of a bit reporting true =
// [redacted_prob] * [one_coin_prob:.75] +
// (1-[redacted_prob]) * [zero_coin_prob:.5] =
// 0.65625 for true bits
// 0.59375 for false bits
// stats.binom(152, 0.65625).ppf(0.000005) = 73
EXPECT_GT(true_from_true_count, 73);
// stats.binom(152, 0.65625).ppf(0.999995) = 124
EXPECT_LE(true_from_true_count, 124);
// stats.binom(248, 0.59375).ppf(.000005) = 113
EXPECT_GT(true_from_false_count, 113);
// stats.binom(248, 0.59375).ppf(.999995) = 181
EXPECT_LE(true_from_false_count, 181);
}
} // namespace rappor

@ -1,113 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/public/sample.h"
#include <map>
#include <string>
#include "base/logging.h"
#include "base/metrics/metrics_hashes.h"
#include "components/rappor/bloom_filter.h"
#include "components/rappor/byte_vector_utils.h"
#include "components/rappor/proto/rappor_metric.pb.h"
#include "components/rappor/reports.h"
namespace rappor {
Sample::Sample(int32_t cohort_seed, const RapporParameters& parameters)
: parameters_(parameters),
bloom_offset_((cohort_seed % parameters_.num_cohorts) *
parameters_.bloom_filter_hash_function_count) {
// Must use bloom filter size that fits in uint64_t.
DCHECK_LE(parameters_.bloom_filter_size_bytes, 8u);
}
Sample::~Sample() {
}
void Sample::SetStringField(const std::string& field_name,
const std::string& value) {
DVLOG(2) << "Recording sample \"" << value
<< "\" for sample metric field \"" << field_name << "\"";
DCHECK_EQ(0u, field_info_[field_name].size);
uint64_t bloom_bits = internal::GetBloomBits(
parameters_.bloom_filter_size_bytes,
parameters_.bloom_filter_hash_function_count,
bloom_offset_,
value);
field_info_[field_name] = Sample::FieldInfo{
parameters_.bloom_filter_size_bytes /* size */,
bloom_bits /* value */,
parameters_.noise_level,
};
}
void Sample::SetFlagsField(const std::string& field_name,
uint64_t flags,
size_t num_flags) {
SetFlagsField(field_name, flags, num_flags, parameters_.noise_level);
}
void Sample::SetFlagsField(const std::string& field_name,
uint64_t flags,
size_t num_flags,
NoiseLevel noise_level) {
if (noise_level == NO_NOISE) {
// Non-noised fields can only be recorded for UMA rappor metrics.
DCHECK_EQ(UMA_RAPPOR_GROUP, parameters_.recording_group);
if (parameters_.recording_group != UMA_RAPPOR_GROUP)
return;
}
DVLOG(2) << "Recording flags " << flags
<< " for sample metric field \"" << field_name << "\"";
DCHECK_EQ(0u, field_info_[field_name].size);
DCHECK_GT(num_flags, 0u);
DCHECK_LE(num_flags, 64u);
DCHECK(num_flags == 64u || flags >> num_flags == 0);
field_info_[field_name] = Sample::FieldInfo{
(num_flags + 7) / 8 /* size */,
flags /* value */,
noise_level,
};
}
void Sample::SetUInt64Field(const std::string& field_name,
uint64_t value,
NoiseLevel noise_level) {
// Noised integers not supported yet.
DCHECK_EQ(NO_NOISE, noise_level);
// Non-noised fields can only be recorded for UMA rappor metrics.
DCHECK_EQ(UMA_RAPPOR_GROUP, parameters_.recording_group);
if (parameters_.recording_group != UMA_RAPPOR_GROUP)
return;
DCHECK_EQ(0u, field_info_[field_name].size);
field_info_[field_name] = Sample::FieldInfo{
8,
value,
noise_level,
};
}
void Sample::ExportMetrics(const std::string& secret,
const std::string& metric_name,
RapporReports* reports) const {
for (const auto& kv : field_info_) {
FieldInfo field_info = kv.second;
ByteVector value_bytes(field_info.size);
Uint64ToByteVector(field_info.value, field_info.size, &value_bytes);
ByteVector report_bytes = internal::GenerateReport(
secret,
internal::kNoiseParametersForLevel[field_info.noise_level],
value_bytes);
RapporReports::Report* report = reports->add_report();
report->set_name_hash(base::HashMetricName(
metric_name + "." + kv.first));
report->set_bits(std::string(report_bytes.begin(), report_bytes.end()));
DVLOG(2) << "Exporting sample " << metric_name << "." << kv.first;
}
}
} // namespace rappor

@ -1,40 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/sampler.h"
#include <map>
#include <string>
#include <utility>
#include "base/rand_util.h"
namespace rappor {
namespace internal {
Sampler::Sampler() {}
Sampler::~Sampler() {}
void Sampler::AddSample(const std::string& metric_name,
std::unique_ptr<Sample> sample) {
++sample_counts_[metric_name];
// Replace the previous sample with a 1 in sample_count_ chance so that each
// sample has equal probability of being reported.
if (base::RandGenerator(sample_counts_[metric_name]) == 0)
samples_[metric_name] = std::move(sample);
}
void Sampler::ExportMetrics(const std::string& secret, RapporReports* reports) {
for (const auto& kv : samples_) {
kv.second->ExportMetrics(secret, kv.first, reports);
}
samples_.clear();
sample_counts_.clear();
}
} // namespace internal
} // namespace rappor

@ -1,54 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_SAMPLER_H_
#define COMPONENTS_RAPPOR_SAMPLER_H_
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include "base/macros.h"
#include "components/rappor/public/rappor_parameters.h"
#include "components/rappor/public/sample.h"
namespace rappor {
class RapporReports;
namespace internal {
// Sampler manages the collection and storage of Sample objects.
// For each metric name, it will randomly select one Sample to store and
// use when generating RapporReports.
class Sampler {
public:
Sampler();
~Sampler();
// Store this sample for metric name, randomly selecting a sample if
// others have already been recorded.
void AddSample(const std::string& metric_name,
std::unique_ptr<Sample> sample);
// Generate randomized reports for all stored samples and store them
// in |reports|, then discard the samples.
void ExportMetrics(const std::string& secret, RapporReports* reports);
private:
// The number of samples recorded for each metric since the last export.
std::map<std::string, int> sample_counts_;
// Stores a Sample for each metric, by metric name.
std::unordered_map<std::string, std::unique_ptr<Sample>> samples_;
DISALLOW_COPY_AND_ASSIGN(Sampler);
};
} // namespace internal
} // namespace rappor
#endif // COMPONENTS_RAPPOR_SAMPLER_H_

@ -1,81 +0,0 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/sampler.h"
#include <memory>
#include <utility>
#include "base/metrics/metrics_hashes.h"
#include "components/rappor/byte_vector_utils.h"
#include "components/rappor/proto/rappor_metric.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace rappor {
const RapporParameters kRapporSamplerTestParameters = {
1 /* Num cohorts */, 1 /* Bloom filter size bytes */,
4 /* Bloom filter hash count */, NORMAL_NOISE /* Noise level */,
UMA_RAPPOR_GROUP /* Recording group (not used) */};
class TestSamplerFactory {
public:
static std::unique_ptr<Sample> CreateSample() {
return std::unique_ptr<Sample>(new Sample(0, kRapporSamplerTestParameters));
}
};
namespace internal {
// Test that exporting deletes samples.
TEST(RapporSamplerTest, TestExport) {
Sampler sampler;
std::unique_ptr<Sample> sample1 = TestSamplerFactory::CreateSample();
sample1->SetStringField("Foo", "Junk");
sampler.AddSample("Metric1", std::move(sample1));
std::unique_ptr<Sample> sample2 = TestSamplerFactory::CreateSample();
sample2->SetStringField("Foo", "Junk2");
sampler.AddSample("Metric1", std::move(sample2));
// Since the two samples were for one metric, we should randomly get one
// of the two.
RapporReports reports;
std::string secret = HmacByteVectorGenerator::GenerateEntropyInput();
sampler.ExportMetrics(secret, &reports);
EXPECT_EQ(1, reports.report_size());
EXPECT_EQ(1u, reports.report(0).bits().size());
// First export should clear the metric.
RapporReports reports2;
sampler.ExportMetrics(secret, &reports2);
EXPECT_EQ(0, reports2.report_size());
}
// Test exporting fields with NO_NOISE.
TEST(RapporSamplerTest, TestNoNoise) {
Sampler sampler;
std::unique_ptr<Sample> sample1 = TestSamplerFactory::CreateSample();
sample1->SetFlagsField("Foo", 0xde, 8, NO_NOISE);
sample1->SetUInt64Field("Bar", 0x0011223344aabbccdd, NO_NOISE);
sampler.AddSample("Metric1", std::move(sample1));
RapporReports reports;
std::string secret = HmacByteVectorGenerator::GenerateEntropyInput();
sampler.ExportMetrics(secret, &reports);
EXPECT_EQ(2, reports.report_size());
uint64_t hash1 = base::HashMetricName("Metric1.Foo");
bool order = reports.report(0).name_hash() == hash1;
const RapporReports::Report& report1 = reports.report(order ? 0 : 1);
EXPECT_EQ("\xde", report1.bits());
const RapporReports::Report& report2 = reports.report(order ? 1 : 0);
EXPECT_EQ("\xdd\xcc\xbb\xaa\x44\x33\x22\x11\x00", report2.bits());
}
} // namespace internal
} // namespace rappor

@ -1,24 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/test_log_uploader.h"
namespace rappor {
TestLogUploader::TestLogUploader() : is_running_(false) {}
TestLogUploader::~TestLogUploader() {}
void TestLogUploader::Start() {
is_running_ = true;
}
void TestLogUploader::Stop() {
is_running_ = false;
}
void TestLogUploader::QueueLog(const std::string& string) {
}
} // namespace rappor

@ -1,37 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_TEST_LOG_UPLOADER_H_
#define COMPONENTS_RAPPOR_TEST_LOG_UPLOADER_H_
#include <string>
#include "base/macros.h"
#include "components/rappor/log_uploader_interface.h"
namespace rappor {
class TestLogUploader : public LogUploaderInterface {
public:
TestLogUploader();
~TestLogUploader() override;
// LogUploaderInterface:
void Start() override;
void Stop() override;
void QueueLog(const std::string& log) override;
// Get if the uploader is running.
bool is_running() { return is_running_; }
private:
// True if Start was called since the last Stop.
bool is_running_;
DISALLOW_COPY_AND_ASSIGN(TestLogUploader);
};
} // namespace rappor
#endif // COMPONENTS_RAPPOR_LOG_UPLOADER_INTERFACE_H_

@ -1,147 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/rappor/test_rappor_service.h"
#include <utility>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "components/rappor/byte_vector_utils.h"
#include "components/rappor/proto/rappor_metric.pb.h"
#include "components/rappor/public/rappor_parameters.h"
#include "components/rappor/rappor_prefs.h"
#include "components/rappor/test_log_uploader.h"
namespace rappor {
namespace {
bool MockIsIncognito(bool* is_incognito) {
return *is_incognito;
}
} // namespace
TestSample::TestSample(RapporType type)
: Sample(0, internal::kRapporParametersForType[type]), shadow_(type) {}
TestSample::~TestSample() {}
void TestSample::SetStringField(const std::string& field_name,
const std::string& value) {
shadow_.string_fields[field_name] = value;
Sample::SetStringField(field_name, value);
}
void TestSample::SetFlagsField(const std::string& field_name,
uint64_t flags,
size_t num_flags) {
shadow_.flag_fields[field_name] = flags;
Sample::SetFlagsField(field_name, flags, num_flags);
}
void TestSample::SetUInt64Field(const std::string& field_name,
uint64_t value,
NoiseLevel noise_level) {
shadow_.uint64_fields[field_name] =
std::pair<std::uint64_t, NoiseLevel>(value, noise_level);
Sample::SetUInt64Field(field_name, value, noise_level);
}
TestSample::Shadow::Shadow(RapporType type) : type(type) {}
TestSample::Shadow::Shadow(const TestSample::Shadow& other) {
type = other.type;
flag_fields = other.flag_fields;
string_fields = other.string_fields;
uint64_fields = other.uint64_fields;
}
TestSample::Shadow::~Shadow() = default;
TestRapporServiceImpl::TestRapporServiceImpl()
: RapporServiceImpl(&test_prefs_,
base::BindRepeating(&MockIsIncognito, &is_incognito_)),
next_rotation_(base::TimeDelta()),
is_incognito_(false) {
RegisterPrefs(test_prefs_.registry());
test_uploader_ = new TestLogUploader();
InitializeInternal(base::WrapUnique(test_uploader_), 0,
HmacByteVectorGenerator::GenerateEntropyInput());
Update(true, true);
}
TestRapporServiceImpl::~TestRapporServiceImpl() {}
std::unique_ptr<Sample> TestRapporServiceImpl::CreateSample(RapporType type) {
std::unique_ptr<TestSample> test_sample(new TestSample(type));
return std::move(test_sample);
}
// Intercepts the sample being recorded and saves it in a test structure.
void TestRapporServiceImpl::RecordSample(const std::string& metric_name,
std::unique_ptr<Sample> sample) {
TestSample* test_sample = static_cast<TestSample*>(sample.get());
// Erase the previous sample if we logged one.
shadows_.erase(metric_name);
shadows_.insert(std::pair<std::string, TestSample::Shadow>(
metric_name, test_sample->GetShadow()));
// Original version is still called.
RapporServiceImpl::RecordSample(metric_name, std::move(sample));
}
void TestRapporServiceImpl::RecordSampleString(const std::string& metric_name,
RapporType type,
const std::string& sample) {
// Save the recorded sample to the local structure.
RapporSample rappor_sample;
rappor_sample.type = type;
rappor_sample.value = sample;
samples_[metric_name] = rappor_sample;
// Original version is still called.
RapporServiceImpl::RecordSampleString(metric_name, type, sample);
}
int TestRapporServiceImpl::GetReportsCount() {
RapporReports reports;
ExportMetrics(&reports);
return reports.report_size();
}
void TestRapporServiceImpl::GetReports(RapporReports* reports) {
ExportMetrics(reports);
}
TestSample::Shadow* TestRapporServiceImpl::GetRecordedSampleForMetric(
const std::string& metric_name) {
auto it = shadows_.find(metric_name);
if (it == shadows_.end())
return nullptr;
return &it->second;
}
bool TestRapporServiceImpl::GetRecordedSampleForMetric(
const std::string& metric_name,
std::string* sample,
RapporType* type) {
auto it = samples_.find(metric_name);
if (it == samples_.end())
return false;
*sample = it->second.value;
*type = it->second.type;
return true;
}
// Cancel the next call to OnLogInterval.
void TestRapporServiceImpl::CancelNextLogRotation() {
next_rotation_ = base::TimeDelta();
}
// Schedule the next call to OnLogInterval.
void TestRapporServiceImpl::ScheduleNextLogRotation(base::TimeDelta interval) {
next_rotation_ = interval;
}
} // namespace rappor

@ -1,142 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_RAPPOR_TEST_RAPPOR_SERVICE_H_
#define COMPONENTS_RAPPOR_TEST_RAPPOR_SERVICE_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <string>
#include "base/macros.h"
#include "components/prefs/testing_pref_service.h"
#include "components/rappor/rappor_service_impl.h"
#include "components/rappor/test_log_uploader.h"
namespace rappor {
// This class duplicates the functionality of Sample, with a cohort initialized
// always to 0. It keeps a shadow object around which copies every flag field
// and string field set on the Sample.
class TestSample : public Sample {
public:
TestSample(RapporType type);
~TestSample() override;
// Sample:
void SetStringField(const std::string& field_name,
const std::string& value) override;
void SetFlagsField(const std::string& field_name,
uint64_t flags,
size_t num_flags) override;
void SetUInt64Field(const std::string& field_name,
uint64_t value,
NoiseLevel noise_level) override;
struct Shadow {
explicit Shadow(RapporType type);
Shadow(const Shadow& other);
~Shadow();
RapporType type;
std::map<std::string, uint64_t> flag_fields;
std::map<std::string, std::string> string_fields;
std::map<std::string, std::pair<std::uint64_t, NoiseLevel>> uint64_fields;
};
Shadow GetShadow() { return shadow_; }
private:
Shadow shadow_;
};
// This class provides a simple instance that can be instantiated by tests
// and examined to check that metrics were recorded. It assumes the most
// permissive settings so that any metric can be recorded.
class TestRapporServiceImpl : public RapporServiceImpl {
public:
TestRapporServiceImpl();
~TestRapporServiceImpl() override;
// RapporServiceImpl:
std::unique_ptr<Sample> CreateSample(RapporType type) override;
void RecordSample(const std::string& metric_name,
std::unique_ptr<Sample> sample) override;
void RecordSampleString(const std::string& metric_name,
RapporType type,
const std::string& sample) override;
// Gets the number of reports that would be uploaded by this service.
// This also clears the internal map of metrics as a biproduct, so if
// comparing numbers of reports, the comparison should be from the last time
// GetReportsCount() was called (not from the beginning of the test).
int GetReportsCount();
// Gets the reports proto that would be uploaded.
// This clears the internal map of metrics.
void GetReports(RapporReports* reports);
// Gets the recorded sample for |metric_name|. This returns the shadow object
// for the sample, which contains the string fields, flag fields, and type.
// Limitation: if the metric was logged more than once, this will return the
// latest sample that was logged.
TestSample::Shadow* GetRecordedSampleForMetric(
const std::string& metric_name);
// Gets the recorded sample/type for a |metric_name|, and returns whether the
// recorded metric was found. Limitation: if the metric was logged more than
// once, this will return the latest sample that was logged.
bool GetRecordedSampleForMetric(const std::string& metric_name,
std::string* sample,
RapporType* type);
void set_is_incognito(bool is_incognito) { is_incognito_ = is_incognito; }
TestingPrefServiceSimple* test_prefs() { return &test_prefs_; }
rappor::TestLogUploader* test_uploader() { return test_uploader_; }
base::TimeDelta next_rotation() { return next_rotation_; }
protected:
// Cancels the next call to OnLogInterval.
void CancelNextLogRotation() override;
// Schedules the next call to OnLogInterval.
void ScheduleNextLogRotation(base::TimeDelta interval) override;
private:
// Used to keep track of recorded RAPPOR samples.
struct RapporSample {
RapporType type;
std::string value;
};
typedef std::map<std::string, RapporSample> SamplesMap;
SamplesMap samples_;
// Recording a TestSample inserts its shadow into this map, which has all of
// its fields copied.
typedef std::map<std::string, TestSample::Shadow> ShadowMap;
ShadowMap shadows_;
TestingPrefServiceSimple test_prefs_;
// Holds a weak ref to the uploader_ object.
rappor::TestLogUploader* test_uploader_;
// The last scheduled log rotation.
base::TimeDelta next_rotation_;
// Sets this to true to mock incognito state.
bool is_incognito_;
DISALLOW_COPY_AND_ASSIGN(TestRapporServiceImpl);
};
} // namespace rappor
#endif // COMPONENTS_RAPPOR_TEST_RAPPOR_SERVICE_H_

@ -3,7 +3,6 @@ include_rules = [
"+components/history/core/browser",
"+components/metrics",
"+components/prefs",
"+components/rappor",
"+components/safe_browsing/core/common",
"+components/safe_browsing/core/db",
"+components/ssl_errors",

@ -78,7 +78,6 @@ source_set("browser") {
"//components/payments/core:error_strings",
"//components/payments/mojom",
"//components/power_scheduler",
"//components/rappor",
"//components/services/filesystem:lib",
"//components/services/quarantine:quarantine",
"//components/services/storage",

@ -28,7 +28,6 @@ include_rules = [
"+components/offline_pages/buildflags/buildflags.h",
"+components/offline_pages/core/request_header",
"+components/payments",
"+components/rappor/public",
"+components/services/heap_profiling/public",
"+components/system_media_controls",
"+components/tracing",

@ -19,7 +19,6 @@ include_rules = [
specific_include_rules = {
".*_(unit|browser)test\.(cc|mm)": [
"+components/rappor/test_rappor_service.h",
"+content/browser/web_contents",
"+content/public/browser/web_contents.h",
"+content/public/browser/web_contents_delegate.h",

@ -5,7 +5,6 @@
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "build/build_config.h"
#include "components/rappor/public/sample.h"
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
#include "content/public/browser/keyboard_event_processing_result.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
@ -126,12 +125,6 @@ bool RenderWidgetHostDelegate::IsWidgetForMainFrame(RenderWidgetHostImpl*) {
return false;
}
bool RenderWidgetHostDelegate::AddDomainInfoToRapporSample(
rappor::Sample* sample) {
sample->SetStringField("Domain", "Unknown");
return false;
}
ukm::SourceId RenderWidgetHostDelegate::GetCurrentPageUkmSourceId() {
return ukm::kInvalidSourceId;
}

@ -34,10 +34,6 @@ class Rect;
class Size;
}
namespace rappor {
class Sample;
}
namespace content {
class BrowserAccessibilityManager;
@ -287,11 +283,6 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
virtual void FocusOwningWebContents(
RenderWidgetHostImpl* render_widget_host) {}
// Augment a Rappor sample with eTLD+1 context. The caller is still
// responsible for logging the sample to the RapporService. Returns false
// if the eTLD+1 is not known for |render_widget_host|.
virtual bool AddDomainInfoToRapporSample(rappor::Sample* sample);
// Return this object cast to a WebContents, if it is one. If the object is
// not a WebContents, returns nullptr.
virtual WebContents* GetAsWebContents();

@ -47,7 +47,6 @@
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/download/public/common/download_stats.h"
#include "components/rappor/public/rappor_utils.h"
#include "components/url_formatter/url_formatter.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/bad_message.h"
@ -8408,16 +8407,6 @@ void WebContentsImpl::RemoveReceiverSet(const std::string& interface_name) {
receiver_sets_.erase(it);
}
bool WebContentsImpl::AddDomainInfoToRapporSample(rappor::Sample* sample) {
OPTIONAL_TRACE_EVENT0("content",
"WebContentsImpl::AddDomainInfoToRapporSample");
// Here we associate this metric to the main frame URL regardless of what
// caused it.
sample->SetStringField("Domain", ::rappor::GetDomainAndRegistrySampleFromGURL(
GetLastCommittedURL()));
return true;
}
void WebContentsImpl::ShowInsecureLocalhostWarningIfNeeded() {
OPTIONAL_TRACE_EVENT0(
"content", "WebContentsImpl::ShowInsecureLocalhostWarningIfNeeded");

@ -961,7 +961,6 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
void SendScreenRects() override;
TextInputManager* GetTextInputManager() override;
bool IsWidgetForMainFrame(RenderWidgetHostImpl* render_widget_host) override;
bool AddDomainInfoToRapporSample(rappor::Sample* sample) override;
bool IsShowingContextMenuOnPage() const override;
void DidChangeScreenOrientation() override;
// The following function is already listed under RenderViewHostDelegate

@ -2203,7 +2203,6 @@ test("content_unittests") {
"//components/network_session_configurator/common",
"//components/offline_pages/buildflags",
"//components/payments/mojom",
"//components/rappor:test_support",
"//components/services/quarantine/public/mojom",
"//components/services/storage",
"//components/services/storage:test_support",

@ -203,7 +203,6 @@ source_set("browser_impl") {
"//components/network_time",
"//components/open_from_clipboard",
"//components/prefs",
"//components/rappor",
"//components/safe_browsing/core:features",
"//components/sessions",
"//components/translate/core/browser",

@ -71,7 +71,6 @@ include_rules = [
"+components/profile_metrics",
"+components/proxy_config",
"+components/query_parser",
"+components/rappor",
"+components/reading_list",
"+components/rlz",
"+components/safe_browsing",

@ -51,10 +51,6 @@ namespace network_time {
class NetworkTimeTracker;
}
namespace rappor {
class RapporServiceImpl;
}
namespace ukm {
class UkmRecorder;
}
@ -125,9 +121,6 @@ class ApplicationContext {
// Gets the VariationsService used by this application.
virtual variations::VariationsService* GetVariationsService() = 0;
// Gets the RapporServiceImpl. May return null.
virtual rappor::RapporServiceImpl* GetRapporServiceImpl() = 0;
// Gets the NetLog.
virtual net::NetLog* GetNetLog() = 0;

Some files were not shown because too many files have changed in this diff Show More