1 // Copyright 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_METRIC_BUILDER_H_ 6 #define THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_METRIC_BUILDER_H_ 7 8 #include <cstdint> 9 #include <vector> 10 11 #include "services/metrics/public/cpp/ukm_recorder.h" 12 #include "services/metrics/public/cpp/ukm_source_id.h" 13 #include "third_party/blink/public/common/common_export.h" 14 #include "third_party/blink/public/common/privacy_budget/identifiable_sample.h" 15 #include "third_party/blink/public/common/privacy_budget/identifiable_surface.h" 16 #include "third_party/blink/public/common/privacy_budget/identifiable_token.h" 17 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-forward.h" 18 19 namespace blink { 20 21 // IdentifiabilityMetricBuilder builds an identifiability metric encoded into a 22 // UkmEntry. 23 // 24 // This UkmEntry can be recorded via a UkmRecorder. 25 // 26 // # Encoding 27 // 28 // All identifiability metrics are represented using the tuple 29 // 30 // < identifiable_surface_type, input, output >. 31 // 32 // A typical URL-Keyed-Metrics (UKM) entry looks like the following: 33 // 34 // struct UkmEntry { 35 // int64 source_id; 36 // uint64 event_hash; 37 // map<uint64,int64> metrics; 38 // }; 39 // 40 // (From //services/metrics/public/mojom/ukm_interface.mojom) 41 // 42 // This class encodes the former into the latter. 43 // 44 // The |source_id| is one that is known to UKM. Follow UKM guidelines for how to 45 // generate or determine the |source_id| corresponding to a document or URL. 46 // 47 // The |event_hash| is a digest of the UKM event name via 48 // |base::HashMetricName()|. For identifiability metrics, this is always 49 // UINT64_C(287024497009309687) which corresponds to 'Identifiability'. 50 // 51 // Metrics for *regular* UKM consist of a mapping from a metric ID to a metric 52 // value. The metric ID is a digest of the metric name as determined by 53 // base::IdentifiabilityDigestOfBytes(), similar to how an |event_hash| is 54 // derived from the event name. 55 // 56 // However, for identifiability metrics, the method for generating metric IDs 57 // is: 58 // 59 // metrics_hash = (input << 8) | identifiable_surface_type; 60 // 61 // The |identifiable_surface_type| is an enumeration identifying the input 62 // identifier defined in |IdentifiableSurface::Type|. 63 // 64 // We lose the 8 MSBs of |input|. Retaining the lower bits allow us to use small 65 // (i.e. under 56-bits) numbers as-is without losing information. 66 // 67 // The |IdentifiableSurface| class encapsulates this translation. 68 // 69 // The |metrics| field in |UkmEntry| thus contains a mapping from the resulting 70 // |metric_hash| to the output of the identifiable surface encoded into 64-bits. 71 // 72 // To generate a 64-bit hash of a random binary blob, use 73 // |blink::IdentifiabilityDigestOfBytes()|. For numbers with fewer than 56 74 // significant bits, you can use the number itself as the input hash. 75 // 76 // As mentioned in |identifiability_metrics.h|, this function is **not** a 77 // cryptographic hash function. While it is expected to have a reasonable 78 // distribution for a uniform input, it should be assumed that finding 79 // collisions is trivial. 80 // 81 // E.g.: 82 // 83 // 1. A simple web exposed API that's represented using a |WebFeature| 84 // constant. Values are defined in 85 // blink/public/mojom/web_feature/web_feature.mojom. 86 // 87 // identifiable_surface = IdentifiableSurface::FromTypeAndToken( 88 // IdentifiableSurface::Type::kWebFeature, 89 // blink::mojom::WebFeature::kDeviceOrientationSecureOrigin); 90 // output = IdentifiabilityDigestOfBytes(result_as_binary_blob); 91 // 92 // 2. A surface that takes a non-trivial input represented as a binary blob: 93 // 94 // identifiable_surface = IdentifiableSurface::FromTypeAndToken( 95 // IdentifiableSurface::Type::kFancySurface, 96 // IdentifiabilityDigestOfBytes(input_as_binary_blob)); 97 // output = IdentifiabilityDigestOfBytes(result_as_binary_blob); 98 class BLINK_COMMON_EXPORT IdentifiabilityMetricBuilder { 99 public: 100 // Construct a metrics builder for the given |source_id|. The source must be 101 // known to UKM. 102 explicit IdentifiabilityMetricBuilder(ukm::SourceIdObj source_id); 103 104 // This has the same effect as the previous constructor but takes the 105 // deprecated ukm::SourceId for convenience. Doing so allows callsites to use 106 // methods like Document::GetUkmSourceId() without an extra conversion. In 107 // addition, when Document::GetUkmSourceId() migrates to returning a 108 // ukm::SourceIdObj, callsites won't need to change. IdentifiabilityMetricBuilder(ukm::SourceId source_id)109 explicit IdentifiabilityMetricBuilder(ukm::SourceId source_id) 110 : IdentifiabilityMetricBuilder(ukm::SourceIdObj::FromInt64(source_id)) {} 111 112 ~IdentifiabilityMetricBuilder(); 113 114 // Set the metric using a previously constructed |IdentifiableSurface|. 115 IdentifiabilityMetricBuilder& Set(IdentifiableSurface surface, 116 IdentifiableToken sample); 117 118 // Convenience method for recording the result of invoking a simple API 119 // surface with a |UseCounter|. SetWebfeature(mojom::WebFeature feature,IdentifiableToken sample)120 IdentifiabilityMetricBuilder& SetWebfeature(mojom::WebFeature feature, 121 IdentifiableToken sample) { 122 return Set(IdentifiableSurface::FromTypeAndToken( 123 IdentifiableSurface::Type::kWebFeature, feature), 124 sample); 125 } 126 127 // Record collected metrics to `recorder`. 128 void Record(ukm::UkmRecorder* recorder); 129 130 private: 131 std::vector<IdentifiableSample> metrics_; 132 const ukm::SourceIdObj source_id_; 133 }; 134 135 } // namespace blink 136 137 #endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABILITY_METRIC_BUILDER_H_ 138