diff --git a/api/stats/rtc_stats.h b/api/stats/rtc_stats.h index 535e6fb345..e22043df5c 100644 --- a/api/stats/rtc_stats.h +++ b/api/stats/rtc_stats.h @@ -215,6 +215,17 @@ enum class NonStandardGroupId { kRtcStatsRelativePacketArrivalDelay, }; +// Certain stat members should only be exposed to the JavaScript API in +// certain circumstances as to avoid passive fingerprinting. +enum class StatExposureCriteria : uint8_t { + // The stat should always be exposed. This is the default. + kAlways, + // The stat exposes hardware capabilities and thus should has limited exposure + // to JavaScript. The requirements for exposure are written in the spec at + // https://w3c.github.io/webrtc-stats/#limiting-exposure-of-hardware-capabilities. + kHardwareCapability, +}; + // Interface for `RTCStats` members, which have a name and a value of a type // defined in a subclass. Only the types listed in `Type` are supported, these // are implemented by `RTCStatsMember`. The value of a member may be @@ -256,6 +267,12 @@ class RTCStatsMemberInterface { // Non-standard stats members can have group IDs in order to be exposed in // JavaScript through experiments. Standardized stats have no group IDs. virtual std::vector group_ids() const { return {}; } + // The conditions for exposing the statistic to JavaScript. Stats with + // criteria that is not kAlways has some restriction and should be filtered + // in accordance to the spec. + virtual StatExposureCriteria exposure_criteria() const { + return StatExposureCriteria::kAlways; + } // Type and value comparator. The names are not compared. These operators are // exposed for testing. bool operator==(const RTCStatsMemberInterface& other) const { @@ -295,16 +312,21 @@ template class RTCStatsMember : public RTCStatsMemberInterface { public: explicit RTCStatsMember(const char* name) - : RTCStatsMemberInterface(name, /*is_defined=*/false), value_() {} + : RTCStatsMemberInterface(name, + /*is_defined=*/false), + value_() {} RTCStatsMember(const char* name, const T& value) - : RTCStatsMemberInterface(name, /*is_defined=*/true), value_(value) {} + : RTCStatsMemberInterface(name, + /*is_defined=*/true), + value_(value) {} RTCStatsMember(const char* name, T&& value) - : RTCStatsMemberInterface(name, /*is_defined=*/true), + : RTCStatsMemberInterface(name, + /*is_defined=*/true), value_(std::move(value)) {} - explicit RTCStatsMember(const RTCStatsMember& other) + RTCStatsMember(const RTCStatsMember& other) : RTCStatsMemberInterface(other.name_, other.is_defined_), value_(other.value_) {} - explicit RTCStatsMember(RTCStatsMember&& other) + RTCStatsMember(RTCStatsMember&& other) : RTCStatsMemberInterface(other.name_, other.is_defined_), value_(std::move(other.value_)) {} @@ -358,7 +380,9 @@ class RTCStatsMember : public RTCStatsMemberInterface { protected: bool IsEqual(const RTCStatsMemberInterface& other) const override { - if (type() != other.type() || is_standardized() != other.is_standardized()) + if (type() != other.type() || + is_standardized() != other.is_standardized() || + exposure_criteria() != other.exposure_criteria()) return false; const RTCStatsMember& other_t = static_cast&>(other); @@ -411,6 +435,81 @@ WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector); WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64); WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble); +// For stats with restricted exposure. +template +class RTCRestrictedStatsMember : public RTCStatsMember { + public: + explicit RTCRestrictedStatsMember(const char* name) + : RTCStatsMember(name) {} + RTCRestrictedStatsMember(const char* name, const T& value) + : RTCStatsMember(name, value) {} + RTCRestrictedStatsMember(const char* name, T&& value) + : RTCStatsMember(name, std::move(value)) {} + RTCRestrictedStatsMember(const RTCRestrictedStatsMember& other) + : RTCStatsMember(other) {} + RTCRestrictedStatsMember(RTCRestrictedStatsMember&& other) + : RTCStatsMember(std::move(other)) {} + + StatExposureCriteria exposure_criteria() const override { return E; } + + T& operator=(const T& value) { return RTCStatsMember::operator=(value); } + T& operator=(const T&& value) { + return RTCStatsMember::operator=(std::move(value)); + } + + private: + static_assert(E != StatExposureCriteria::kAlways, + "kAlways is the default exposure criteria. Use " + "RTCStatMember instead."); +}; + +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; + // Using inheritance just so that it's obvious from the member's declaration // whether it's standardized or not. template diff --git a/stats/rtc_stats.cc b/stats/rtc_stats.cc index e6eb51e55c..375e1f75c0 100644 --- a/stats/rtc_stats.cc +++ b/stats/rtc_stats.cc @@ -289,6 +289,54 @@ WEBRTC_DEFINE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble, MapToString(value_), MapToStringAsDouble(value_)); +// Restricted members that expose hardware capabilites. +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; +template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) + RTCRestrictedStatsMember, + StatExposureCriteria::kHardwareCapability>; + template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) diff --git a/stats/rtc_stats_unittest.cc b/stats/rtc_stats_unittest.cc index 36d0a4fa0e..5d3857f327 100644 --- a/stats/rtc_stats_unittest.cc +++ b/stats/rtc_stats_unittest.cc @@ -503,6 +503,20 @@ TEST(RTCStatsTest, ValueToString) { EXPECT_EQ("{bar:0.25,foo:0.5}", stats.m_map_string_double.ValueToString()); } +TEST(RTCStatsTest, RestrictedStatsTest) { + RTCStatsMember unrestricted("unrestricted"); + EXPECT_EQ(unrestricted.exposure_criteria(), StatExposureCriteria::kAlways); + RTCRestrictedStatsMember + restricted("restricted"); + EXPECT_EQ(restricted.exposure_criteria(), + StatExposureCriteria::kHardwareCapability); + + unrestricted = true; + restricted = true; + EXPECT_NE(unrestricted, restricted) + << "These can not be equal as they have different exposure criteria."; +} + TEST(RTCStatsTest, NonStandardGroupId) { auto group_id = NonStandardGroupId::kGroupIdForTesting; RTCNonStandardStatsMember with_group_id("stat", {group_id});