Commit ffec7f66 authored by Matt Menke's avatar Matt Menke Committed by Commit Bot

Instrument userAgentData for identifiability study.

This CL instruments [Worker]Navigator.userAgentData for the
identifiability study. In particular, it logs a hash of the mobile bool
and brand information as WebFeature::kNavigatorUserAgent, and adds a
new IdentifiableSurface::Type for logging hint/value information for
getHighEntropyValues() calls. Each individual passed in hint value is
recorded with the corresponding returned value, so one
getHighEntropyValues() call may log multiple values.

Bug: 973801
Change-Id: Ia548d2a7698809339e06e1eb32d4caf741bffb9d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2443497Reviewed-by: default avatarDavid Bokan <bokan@chromium.org>
Reviewed-by: default avatarAsanka Herath <asanka@chromium.org>
Reviewed-by: default avatarAaron Tagliaboschi <aarontag@chromium.org>
Commit-Queue: Matt Menke <mmenke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#813323}
parent de9cdec9
......@@ -187,6 +187,11 @@ class IdentifiableSurface {
// Represents a call to GPU.requestAdapter. Input is the options filter.
kGPU_RequestAdapter = 20,
// NavigatorUAData.getHighEntropyValues() is, shockingly, a high entropy
// API to provide more detailed User-Agent data. The output is keyed on
// the hint parameter.
kNavigatorUAData_GetHighEntropyValues = 24,
// We can use values up to and including |kMax|.
kMax = (1 << kTypeBits) - 1
};
......
......@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABLE_TOKEN_BUILDER_H_
#include "base/containers/span.h"
#include "base/strings/string_piece.h"
#include "base/sys_byteorder.h"
#include "third_party/blink/public/common/common_export.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_internal_templates.h"
......@@ -73,6 +74,9 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder {
// adding the contents of the buffer. Doing so will achieve the same ends as
// AddAtomic().
IdentifiableTokenBuilder& AddAtomic(ByteBuffer buffer);
IdentifiableTokenBuilder& AddAtomic(base::StringPiece string) {
return AddAtomic(base::as_bytes(base::make_span(string)));
}
// Feeds the underlying value of the |token| itself to the digest. Use this
// when |token| is computed in parallel in order to preserve the ordering of
......
......@@ -4,6 +4,16 @@
#include "third_party/blink/renderer/core/frame/navigator_ua.h"
#include "base/compiler_specific.h"
#include "base/containers/span.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
namespace blink {
NavigatorUAData* NavigatorUA::userAgentData() {
......@@ -19,7 +29,36 @@ NavigatorUAData* NavigatorUA::userAgentData() {
ua_data->SetModel(String::FromUTF8(metadata.model));
ua_data->SetUAFullVersion(String::FromUTF8(metadata.full_version));
MaybeRecordMetrics(*ua_data);
return ua_data;
}
// Records identifiability study metrics if the user is in the study.
void NavigatorUA::MaybeRecordMetrics(const NavigatorUAData& ua_data) {
constexpr auto identifiable_surface = IdentifiableSurface::FromTypeAndToken(
IdentifiableSurface::Type::kWebFeature, WebFeature::kNavigatorUserAgent);
if (LIKELY(!IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(
identifiable_surface))) {
return;
}
// Only instrument low-entropy fields here. The other fields are
// instrumented separately in NavigatorUAData::getHighEntropyValues().
IdentifiableTokenBuilder token_builder;
token_builder.AddValue(ua_data.mobile());
for (const auto& brand : ua_data.brands()) {
token_builder.AddValue(brand->hasBrand());
if (brand->hasBrand())
token_builder.AddAtomic(brand->brand().Utf8());
token_builder.AddValue(brand->hasVersion());
if (brand->hasVersion())
token_builder.AddAtomic(brand->version().Utf8());
}
ExecutionContext* context = GetUAExecutionContext();
IdentifiabilityMetricBuilder(context->UkmSourceID())
.Set(identifiable_surface, token_builder.GetToken())
.Record(context->UkmRecorder());
}
} // namespace blink
......@@ -19,6 +19,10 @@ class CORE_EXPORT NavigatorUA {
protected:
virtual UserAgentMetadata GetUserAgentMetadata() const = 0;
virtual ExecutionContext* GetUAExecutionContext() const = 0;
// Record identifiability study metrics for NavigatorUAData if the user is in
// the study.
void MaybeRecordMetrics(const NavigatorUAData& ua_data);
};
} // namespace blink
......
......@@ -4,13 +4,41 @@
#include "third_party/blink/renderer/core/frame/navigator_ua_data.h"
#include "base/compiler_specific.h"
#include "base/single_thread_task_runner.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_token.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_ua_data_values.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/page/page.h"
namespace blink {
namespace {
// Record identifiability study metrics for a single field requested by a
// getHighEntropyValues() call if the user is in the study.
void MaybeRecordMetric(bool record_identifiability,
const String& hint,
const String& value,
ExecutionContext* execution_context) {
if (LIKELY(!record_identifiability))
return;
auto identifiable_surface = IdentifiableSurface::FromTypeAndToken(
IdentifiableSurface::Type::kNavigatorUAData_GetHighEntropyValues,
IdentifiableToken(hint.Utf8()));
IdentifiabilityMetricBuilder(execution_context->UkmSourceID())
.Set(identifiable_surface, IdentifiableToken(value.Utf8()))
.Record(execution_context->UkmRecorder());
}
} // namespace
NavigatorUAData::NavigatorUAData(ExecutionContext* context)
: ExecutionContextClient(context) {
NavigatorUABrandVersion* dict = NavigatorUABrandVersion::Create();
......@@ -76,25 +104,39 @@ ScriptPromise NavigatorUAData::getHighEntropyValues(
Vector<String>& hints) const {
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
auto* executionContext =
auto* execution_context =
ExecutionContext::From(script_state); // GetExecutionContext();
DCHECK(execution_context);
bool record_identifiability =
IdentifiabilityStudySettings::Get()->IsTypeAllowed(
IdentifiableSurface::Type::kNavigatorUAData_GetHighEntropyValues);
UADataValues* values = MakeGarbageCollected<UADataValues>();
for (const String& hint : hints) {
if (hint == "platform") {
values->setPlatform(platform_);
MaybeRecordMetric(record_identifiability, hint, platform_,
execution_context);
} else if (hint == "platformVersion") {
values->setPlatformVersion(platform_version_);
MaybeRecordMetric(record_identifiability, hint, platform_version_,
execution_context);
} else if (hint == "architecture") {
values->setArchitecture(architecture_);
MaybeRecordMetric(record_identifiability, hint, architecture_,
execution_context);
} else if (hint == "model") {
values->setModel(model_);
MaybeRecordMetric(record_identifiability, hint, model_,
execution_context);
} else if (hint == "uaFullVersion") {
values->setUaFullVersion(ua_full_version_);
MaybeRecordMetric(record_identifiability, hint, ua_full_version_,
execution_context);
}
}
DCHECK(executionContext);
executionContext->GetTaskRunner(TaskType::kPermission)
execution_context->GetTaskRunner(TaskType::kPermission)
->PostTask(
FROM_HERE,
WTF::Bind([](ScriptPromiseResolver* resolver,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment