blob: 27c8578b2d2507c72d3d0953178ca849cc021106 [file] [log] [blame]
// Copyright 2020 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 THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_METRIC_BUILDER_H_
#define THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_METRIC_BUILDER_H_
#include <cstdint>
#include <vector>
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/common/common_export.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_sample.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/mojom/web_feature/web_feature.mojom-forward.h"
namespace blink {
// IdentifiabilityMetricBuilder builds an identifiability metric encoded into a
// UkmEntry.
//
// This UkmEntry can be recorded via a UkmRecorder.
//
// # Encoding
//
// All identifiability metrics are represented using the tuple
//
// < identifiable_surface_type, input, output >.
//
// A typical URL-Keyed-Metrics (UKM) entry looks like the following:
//
// struct UkmEntry {
// int64 source_id;
// uint64 event_hash;
// map<uint64,int64> metrics;
// };
//
// (From //services/metrics/public/mojom/ukm_interface.mojom)
//
// This class encodes the former into the latter.
//
// The |source_id| is one that is known to UKM. Follow UKM guidelines for how to
// generate or determine the |source_id| corresponding to a document or URL.
//
// The |event_hash| is a digest of the UKM event name via
// |base::HashMetricName()|. For identifiability metrics, this is always
// UINT64_C(287024497009309687) which corresponds to 'Identifiability'.
//
// Metrics for *regular* UKM consist of a mapping from a metric ID to a metric
// value. The metric ID is a digest of the metric name as determined by
// base::IdentifiabilityDigestOfBytes(), similar to how an |event_hash| is
// derived from the event name.
//
// However, for identifiability metrics, the method for generating metric IDs
// is:
//
// metrics_hash = (input << 8) | identifiable_surface_type;
//
// The |identifiable_surface_type| is an enumeration identifying the input
// identifier defined in |IdentifiableSurface::Type|.
//
// We lose the 8 MSBs of |input|. Retaining the lower bits allow us to use small
// (i.e. under 56-bits) numbers as-is without losing information.
//
// The |IdentifiableSurface| class encapsulates this translation.
//
// The |metrics| field in |UkmEntry| thus contains a mapping from the resulting
// |metric_hash| to the output of the identifiable surface encoded into 64-bits.
//
// To generate a 64-bit hash of a random binary blob, use
// |blink::IdentifiabilityDigestOfBytes()|. For numbers with fewer than 56
// significant bits, you can use the number itself as the input hash.
//
// As mentioned in |identifiability_metrics.h|, this function is **not** a
// cryptographic hash function. While it is expected to have a reasonable
// distribution for a uniform input, it should be assumed that finding
// collisions is trivial.
//
// E.g.:
//
// 1. A simple web exposed API that's represented using a |WebFeature|
// constant. Values are defined in
// blink/public/mojom/web_feature/web_feature.mojom.
//
// identifiable_surface = IdentifiableSurface::FromTypeAndToken(
// IdentifiableSurface::Type::kWebFeature,
// blink::mojom::WebFeature::kDeviceOrientationSecureOrigin);
// output = IdentifiabilityDigestOfBytes(result_as_binary_blob);
//
// 2. A surface that takes a non-trivial input represented as a binary blob:
//
// identifiable_surface = IdentifiableSurface::FromTypeAndToken(
// IdentifiableSurface::Type::kFancySurface,
// IdentifiabilityDigestOfBytes(input_as_binary_blob));
// output = IdentifiabilityDigestOfBytes(result_as_binary_blob);
class BLINK_COMMON_EXPORT IdentifiabilityMetricBuilder {
public:
// Construct a metrics builder for the given |source_id|. The source must be
// known to UKM.
explicit IdentifiabilityMetricBuilder(ukm::SourceIdObj source_id);
// This has the same effect as the previous constructor but takes the
// deprecated ukm::SourceId for convenience. Doing so allows callsites to use
// methods like Document::GetUkmSourceId() without an extra conversion. In
// addition, when Document::GetUkmSourceId() migrates to returning a
// ukm::SourceIdObj, callsites won't need to change.
explicit IdentifiabilityMetricBuilder(ukm::SourceId source_id)
: IdentifiabilityMetricBuilder(ukm::SourceIdObj::FromInt64(source_id)) {}
~IdentifiabilityMetricBuilder();
// Set the metric using a previously constructed |IdentifiableSurface|.
IdentifiabilityMetricBuilder& Set(IdentifiableSurface surface,
IdentifiableToken sample);
// Convenience method for recording the result of invoking a simple API
// surface with a |UseCounter|.
IdentifiabilityMetricBuilder& SetWebfeature(mojom::WebFeature feature,
IdentifiableToken sample) {
return Set(IdentifiableSurface::FromTypeAndToken(
IdentifiableSurface::Type::kWebFeature, feature),
sample);
}
// Record collected metrics to `recorder`.
void Record(ukm::UkmRecorder* recorder);
private:
std::vector<IdentifiableSample> metrics_;
const ukm::SourceIdObj source_id_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_METRIC_BUILDER_H_