/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef Telemetry_Comms_h_ #define Telemetry_Comms_h_ #include #include "ipc/IPCMessageUtils.h" #include "ipc/IPCMessageUtilsSpecializations.h" #include "mozilla/Telemetry.h" #include "mozilla/TelemetryProcessEnums.h" #include "mozilla/TelemetryHistogramEnums.h" #include "mozilla/TimeStamp.h" #include "mozilla/Variant.h" #include "mozilla/ParamTraits_TiedFields.h" #include "nsITelemetry.h" namespace mozilla { namespace Telemetry { struct HistogramAccumulation { mozilla::Telemetry::HistogramID mId; uint32_t mSample; }; struct KeyedHistogramAccumulation { mozilla::Telemetry::HistogramID mId; uint32_t mSample; nsCString mKey; }; // Scalar accumulation types. enum class ScalarID : uint32_t; enum class ScalarActionType : uint32_t { eSet = 0, eAdd = 1, eSetMaximum = 2 }; typedef mozilla::Variant ScalarVariant; struct ScalarAction { uint32_t mId; bool mDynamic; ScalarActionType mActionType; // We need to wrap mData in a Maybe otherwise the IPC system // is unable to instantiate a ScalarAction. Maybe mData; // The process type this scalar should be recorded for. // The IPC system will determine the process this action was coming from // later. mozilla::Telemetry::ProcessID mProcessType; }; struct KeyedScalarAction : public ScalarAction { nsCString mKey; }; // Dynamic scalars support. struct DynamicScalarDefinition { uint32_t type; uint32_t dataset; bool expired; bool keyed; nsCString name; bool operator==(const DynamicScalarDefinition& rhs) const { return type == rhs.type && dataset == rhs.dataset && expired == rhs.expired && keyed == rhs.keyed && name.Equals(rhs.name); } }; struct ChildEventData { mozilla::TimeStamp timestamp; nsCString category; nsCString method; nsCString object; mozilla::Maybe value; CopyableTArray extra; }; struct DiscardedData { uint32_t mDiscardedHistogramAccumulations; uint32_t mDiscardedKeyedHistogramAccumulations; uint32_t mDiscardedScalarActions; uint32_t mDiscardedKeyedScalarActions; uint32_t mDiscardedChildEvents; auto MutTiedFields() { return std::tie(mDiscardedHistogramAccumulations, mDiscardedKeyedHistogramAccumulations, mDiscardedScalarActions, mDiscardedKeyedScalarActions, mDiscardedChildEvents); } }; } // namespace Telemetry } // namespace mozilla namespace IPC { template <> struct ParamTraits : public ContiguousEnumSerializer< mozilla::Telemetry::HistogramID, mozilla::Telemetry::HistogramID::A11Y_CONSUMERS, mozilla::Telemetry::HistogramID::HistogramCount> {}; static_assert( static_cast>( mozilla::Telemetry::HistogramID::A11Y_CONSUMERS) == 0, "Update ParamTraits implementation"); template <> struct ParamTraits : public ContiguousEnumSerializerInclusive< mozilla::Telemetry::ScalarActionType, mozilla::Telemetry::ScalarActionType::eSet, mozilla::Telemetry::ScalarActionType::eSetMaximum> {}; template <> struct ParamTraits { typedef mozilla::Telemetry::HistogramAccumulation paramType; static void Write(MessageWriter* aWriter, const paramType& aParam) { WriteParam(aWriter, aParam.mId); WriteParam(aWriter, aParam.mSample); } static bool Read(MessageReader* aReader, paramType* aResult) { if (!ReadParam(aReader, &aResult->mId) || !ReadParam(aReader, &aResult->mSample)) { return false; } return true; } }; template <> struct ParamTraits { typedef mozilla::Telemetry::KeyedHistogramAccumulation paramType; static void Write(MessageWriter* aWriter, const paramType& aParam) { WriteParam(aWriter, aParam.mId); WriteParam(aWriter, aParam.mSample); WriteParam(aWriter, aParam.mKey); } static bool Read(MessageReader* aReader, paramType* aResult) { if (!ReadParam(aReader, &aResult->mId) || !ReadParam(aReader, &aResult->mSample) || !ReadParam(aReader, &aResult->mKey)) { return false; } return true; } }; /** * IPC scalar data message serialization and de-serialization. */ template <> struct ParamTraits { typedef mozilla::Telemetry::ScalarAction paramType; static void Write(MessageWriter* aWriter, const paramType& aParam) { // Write the message type WriteParam(aWriter, aParam.mId); WriteParam(aWriter, aParam.mDynamic); WriteParam(aWriter, aParam.mActionType); if (aParam.mData.isNothing()) { MOZ_CRASH("There is no data in the ScalarAction."); return; } if (aParam.mData->is()) { // That's a nsITelemetry::SCALAR_TYPE_COUNT. WriteParam(aWriter, static_cast(nsITelemetry::SCALAR_TYPE_COUNT)); WriteParam(aWriter, aParam.mData->as()); } else if (aParam.mData->is()) { // That's a nsITelemetry::SCALAR_TYPE_STRING. WriteParam(aWriter, static_cast(nsITelemetry::SCALAR_TYPE_STRING)); WriteParam(aWriter, aParam.mData->as()); } else if (aParam.mData->is()) { // That's a nsITelemetry::SCALAR_TYPE_BOOLEAN. WriteParam(aWriter, static_cast(nsITelemetry::SCALAR_TYPE_BOOLEAN)); WriteParam(aWriter, aParam.mData->as()); } else { MOZ_CRASH("Unknown scalar type."); } } static bool Read(MessageReader* aReader, paramType* aResult) { // Read the scalar ID and the scalar type. uint32_t scalarType = 0; if (!ReadParam(aReader, &aResult->mId) || !ReadParam(aReader, &aResult->mDynamic) || !ReadParam(aReader, &aResult->mActionType) || !ReadParam(aReader, &scalarType)) { return false; } // De-serialize the data based on the scalar type. switch (scalarType) { case nsITelemetry::SCALAR_TYPE_COUNT: { uint32_t data = 0; // De-serialize the data. if (!ReadParam(aReader, &data)) { return false; } aResult->mData = mozilla::Some(mozilla::AsVariant(data)); break; } case nsITelemetry::SCALAR_TYPE_STRING: { nsString data; // De-serialize the data. if (!ReadParam(aReader, &data)) { return false; } aResult->mData = mozilla::Some(mozilla::AsVariant(data)); break; } case nsITelemetry::SCALAR_TYPE_BOOLEAN: { bool data = false; // De-serialize the data. if (!ReadParam(aReader, &data)) { return false; } aResult->mData = mozilla::Some(mozilla::AsVariant(data)); break; } default: MOZ_ASSERT(false, "Unknown scalar type."); return false; } return true; } }; /** * IPC keyed scalar data message serialization and de-serialization. */ template <> struct ParamTraits { typedef mozilla::Telemetry::KeyedScalarAction paramType; static void Write(MessageWriter* aWriter, const paramType& aParam) { // Write the message type WriteParam(aWriter, aParam.mId); WriteParam(aWriter, aParam.mDynamic); WriteParam(aWriter, aParam.mActionType); WriteParam(aWriter, aParam.mKey); if (aParam.mData.isNothing()) { MOZ_CRASH("There is no data in the KeyedScalarAction."); return; } if (aParam.mData->is()) { // That's a nsITelemetry::SCALAR_TYPE_COUNT. WriteParam(aWriter, static_cast(nsITelemetry::SCALAR_TYPE_COUNT)); WriteParam(aWriter, aParam.mData->as()); } else if (aParam.mData->is()) { // That's a nsITelemetry::SCALAR_TYPE_STRING. // Keyed string scalars are not supported. MOZ_ASSERT(false, "Keyed String Scalar unable to be write from child process. " "Not supported."); } else if (aParam.mData->is()) { // That's a nsITelemetry::SCALAR_TYPE_BOOLEAN. WriteParam(aWriter, static_cast(nsITelemetry::SCALAR_TYPE_BOOLEAN)); WriteParam(aWriter, aParam.mData->as()); } else { MOZ_CRASH("Unknown keyed scalar type."); } } static bool Read(MessageReader* aReader, paramType* aResult) { // Read the scalar ID and the scalar type. uint32_t scalarType = 0; if (!ReadParam(aReader, &aResult->mId) || !ReadParam(aReader, &aResult->mDynamic) || !ReadParam(aReader, &aResult->mActionType) || !ReadParam(aReader, &aResult->mKey) || !ReadParam(aReader, &scalarType)) { return false; } // De-serialize the data based on the scalar type. switch (scalarType) { case nsITelemetry::SCALAR_TYPE_COUNT: { uint32_t data = 0; // De-serialize the data. if (!ReadParam(aReader, &data)) { return false; } aResult->mData = mozilla::Some(mozilla::AsVariant(data)); break; } case nsITelemetry::SCALAR_TYPE_STRING: { // Keyed string scalars are not supported. MOZ_ASSERT(false, "Keyed String Scalar unable to be read from child process. " "Not supported."); return false; } case nsITelemetry::SCALAR_TYPE_BOOLEAN: { bool data = false; // De-serialize the data. if (!ReadParam(aReader, &data)) { return false; } aResult->mData = mozilla::Some(mozilla::AsVariant(data)); break; } default: MOZ_ASSERT(false, "Unknown keyed scalar type."); return false; } return true; } }; template <> struct ParamTraits { typedef mozilla::Telemetry::DynamicScalarDefinition paramType; static void Write(MessageWriter* aWriter, const paramType& aParam) { nsCString name; WriteParam(aWriter, aParam.type); WriteParam(aWriter, aParam.dataset); WriteParam(aWriter, aParam.expired); WriteParam(aWriter, aParam.keyed); WriteParam(aWriter, aParam.name); } static bool Read(MessageReader* aReader, paramType* aResult) { if (!ReadParam(aReader, &aResult->type) || !ReadParam(aReader, &aResult->dataset) || !ReadParam(aReader, &aResult->expired) || !ReadParam(aReader, &aResult->keyed) || !ReadParam(aReader, &aResult->name)) { return false; } return true; } }; template <> struct ParamTraits { typedef mozilla::Telemetry::ChildEventData paramType; static void Write(MessageWriter* aWriter, const paramType& aParam) { WriteParam(aWriter, aParam.timestamp); WriteParam(aWriter, aParam.category); WriteParam(aWriter, aParam.method); WriteParam(aWriter, aParam.object); WriteParam(aWriter, aParam.value); WriteParam(aWriter, aParam.extra); } static bool Read(MessageReader* aReader, paramType* aResult) { if (!ReadParam(aReader, &(aResult->timestamp)) || !ReadParam(aReader, &(aResult->category)) || !ReadParam(aReader, &(aResult->method)) || !ReadParam(aReader, &(aResult->object)) || !ReadParam(aReader, &(aResult->value)) || !ReadParam(aReader, &(aResult->extra))) { return false; } return true; } }; template <> struct ParamTraits { typedef mozilla::Telemetry::EventExtraEntry paramType; static void Write(MessageWriter* aWriter, const paramType& aParam) { WriteParam(aWriter, aParam.key); WriteParam(aWriter, aParam.value); } static bool Read(MessageReader* aReader, paramType* aResult) { if (!ReadParam(aReader, &(aResult->key)) || !ReadParam(aReader, &(aResult->value))) { return false; } return true; } }; template <> struct ParamTraits : public ParamTraits_TiedFields {}; } // namespace IPC #endif // Telemetry_Comms_h_