summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/core/TelemetryScalar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/core/TelemetryScalar.cpp')
-rw-r--r--toolkit/components/telemetry/core/TelemetryScalar.cpp794
1 files changed, 14 insertions, 780 deletions
diff --git a/toolkit/components/telemetry/core/TelemetryScalar.cpp b/toolkit/components/telemetry/core/TelemetryScalar.cpp
index 8a121e8f3f..312e25ddc4 100644
--- a/toolkit/components/telemetry/core/TelemetryScalar.cpp
+++ b/toolkit/components/telemetry/core/TelemetryScalar.cpp
@@ -6,7 +6,6 @@
#include "TelemetryScalar.h"
-#include "geckoview/streaming/GeckoViewStreamingTelemetry.h"
#include "ipc/TelemetryIPCAccumulator.h"
#include "js/Array.h" // JS::GetArrayLength, JS::IsArrayObject
#include "js/PropertyAndElement.h" // JS_DefineProperty, JS_DefineUCProperty, JS_Enumerate, JS_GetElement, JS_GetProperty, JS_GetPropertyById, JS_HasProperty
@@ -27,6 +26,7 @@
#include "nsJSUtils.h"
#include "nsPrintfCString.h"
#include "nsVariant.h"
+#include "TelemetryCommon.h"
#include "TelemetryScalarData.h"
using mozilla::MakeUnique;
@@ -112,11 +112,6 @@ const uint32_t kMaximumScalarNameLength = 40;
const uint32_t kScalarCount =
static_cast<uint32_t>(mozilla::Telemetry::ScalarID::ScalarCount);
-// To stop growing unbounded in memory while waiting for scalar deserialization
-// to finish, we immediately apply pending operations if the array reaches
-// a certain high water mark of elements.
-const size_t kScalarActionsArrayHighWaterMark = 10000;
-
const char* TEST_SCALAR_PREFIX = "telemetry.test.";
// The max offset supported by gScalarStoresTable for static scalars' stores.
@@ -284,45 +279,6 @@ ScalarResult GetVariantFromIVariant(nsIVariant* aInput, uint32_t aScalarKind,
return ScalarResult::Ok;
}
-/**
- * Write a nsIVariant with a JSONWriter, used for GeckoView persistence.
- */
-nsresult WriteVariantToJSONWriter(
- uint32_t aScalarType, nsIVariant* aInputValue,
- const mozilla::Span<const char>& aPropertyName,
- mozilla::JSONWriter& aWriter) {
- MOZ_ASSERT(aInputValue);
-
- switch (aScalarType) {
- case nsITelemetry::SCALAR_TYPE_COUNT: {
- uint32_t val = 0;
- nsresult rv = aInputValue->GetAsUint32(&val);
- NS_ENSURE_SUCCESS(rv, rv);
- aWriter.IntProperty(aPropertyName, val);
- break;
- }
- case nsITelemetry::SCALAR_TYPE_STRING: {
- nsCString val;
- nsresult rv = aInputValue->GetAsACString(val);
- NS_ENSURE_SUCCESS(rv, rv);
- aWriter.StringProperty(aPropertyName, val);
- break;
- }
- case nsITelemetry::SCALAR_TYPE_BOOLEAN: {
- bool val = false;
- nsresult rv = aInputValue->GetAsBool(&val);
- NS_ENSURE_SUCCESS(rv, rv);
- aWriter.BoolProperty(aPropertyName, val);
- break;
- }
- default:
- MOZ_ASSERT(false, "Unknown scalar kind.");
- return NS_ERROR_FAILURE;
- }
-
- return NS_OK;
-}
-
// Implements the methods for ScalarInfo.
const char* ScalarInfo::name() const {
return &gScalarsStringTable[this->name_offset];
@@ -517,10 +473,6 @@ ScalarResult ScalarUnsigned::SetValue(nsIVariant* aValue) {
}
void ScalarUnsigned::SetValue(uint32_t aValue) {
- if (GetCurrentProduct() == SupportedProduct::GeckoviewStreaming) {
- GeckoViewStreamingTelemetry::UintScalarSet(mName, aValue);
- return;
- }
for (auto& val : mStorage) {
val = aValue;
}
@@ -544,7 +496,6 @@ ScalarResult ScalarUnsigned::AddValue(nsIVariant* aValue) {
}
void ScalarUnsigned::AddValue(uint32_t aValue) {
- MOZ_ASSERT(GetCurrentProduct() != SupportedProduct::GeckoviewStreaming);
for (auto& val : mStorage) {
val += aValue;
}
@@ -552,7 +503,6 @@ void ScalarUnsigned::AddValue(uint32_t aValue) {
}
ScalarResult ScalarUnsigned::SetMaximum(nsIVariant* aValue) {
- MOZ_ASSERT(GetCurrentProduct() != SupportedProduct::GeckoviewStreaming);
ScalarResult sr = CheckInput(aValue);
if (sr == ScalarResult::UnsignedNegativeValue) {
return sr;
@@ -678,13 +628,6 @@ ScalarResult ScalarString::SetValue(nsIVariant* aValue) {
ScalarResult ScalarString::SetValue(const nsAString& aValue) {
auto str = Substring(aValue, 0, kMaximumStringValueLength);
- if (GetCurrentProduct() == SupportedProduct::GeckoviewStreaming) {
- GeckoViewStreamingTelemetry::StringScalarSet(mName,
- NS_ConvertUTF16toUTF8(str));
- return aValue.Length() > kMaximumStringValueLength
- ? ScalarResult::StringTooLong
- : ScalarResult::Ok;
- }
for (auto& val : mStorage) {
val.Assign(str);
}
@@ -779,10 +722,6 @@ ScalarResult ScalarBoolean::SetValue(nsIVariant* aValue) {
};
void ScalarBoolean::SetValue(bool aValue) {
- if (GetCurrentProduct() == SupportedProduct::GeckoviewStreaming) {
- GeckoViewStreamingTelemetry::BoolScalarSet(mName, aValue);
- return;
- }
for (auto& val : mStorage) {
val = aValue;
}
@@ -1208,20 +1147,6 @@ ProcessesKeyedScalarsMapType gKeyedScalarStorageMap;
// needed to support "build faster" in local developer builds.
ProcessesScalarsMapType gDynamicBuiltinScalarStorageMap;
ProcessesKeyedScalarsMapType gDynamicBuiltinKeyedScalarStorageMap;
-
-// Whether or not the deserialization of persisted scalars is still in progress.
-// This is never the case on Desktop or Fennec.
-// Only GeckoView restores persisted scalars.
-bool gIsDeserializing = false;
-// This batches scalar accumulations that should be applied once loading
-// finished.
-StaticAutoPtr<nsTArray<ScalarAction>> gScalarsActions;
-StaticAutoPtr<nsTArray<KeyedScalarAction>> gKeyedScalarsActions;
-
-bool internal_IsScalarDeserializing(const StaticMutexAutoLock& lock) {
- return gIsDeserializing;
-}
-
} // namespace
////////////////////////////////////////////////////////////////////////
@@ -1402,8 +1327,6 @@ bool internal_CanRecordForScalarID(const StaticMutexAutoLock& lock,
* @param aKeyed Are we attempting to write a keyed scalar?
* @param aForce Whether to allow recording even if the probe is not allowed on
* the current process.
- * This must only be true for GeckoView persistence and recorded
- * actions.
* @return ScalarResult::Ok if we can record, an error code otherwise.
*/
ScalarResult internal_CanRecordScalar(const StaticMutexAutoLock& lock,
@@ -1546,108 +1469,6 @@ nsresult internal_GetScalarByEnum(const StaticMutexAutoLock& lock,
return NS_OK;
}
-void internal_ApplyPendingOperations(const StaticMutexAutoLock& lock);
-
-/**
- * Record the given action on a scalar into the pending actions list.
- *
- * If the pending actions list overflows the high water mark length
- * all operations are immediately applied, including the passed action.
- *
- * @param aScalarAction The action to record.
- */
-void internal_RecordScalarAction(const StaticMutexAutoLock& lock,
- const ScalarAction& aScalarAction) {
- // Make sure to have the storage.
- if (!gScalarsActions) {
- gScalarsActions = new nsTArray<ScalarAction>();
- }
-
- // Store the action.
- gScalarsActions->AppendElement(aScalarAction);
-
- // If this action overflows the pending actions array, we immediately apply
- // pending operations and assume loading is over. If loading still happens
- // afterwards, some scalar values might be overwritten and inconsistent, but
- // we won't lose operations on otherwise untouched probes.
- if (gScalarsActions->Length() > kScalarActionsArrayHighWaterMark) {
- internal_ApplyPendingOperations(lock);
- return;
- }
-}
-
-/**
- * Record the given action on a scalar on the main process into the pending
- * actions list.
- *
- * If the pending actions list overflows the high water mark length
- * all operations are immediately applied, including the passed action.
- *
- * @param aId The scalar's ID this action applies to
- * @param aDynamic Determines if the scalar is dynamic
- * @param aAction The action to record
- * @param aValue The additional data for the recorded action
- */
-void internal_RecordScalarAction(const StaticMutexAutoLock& lock, uint32_t aId,
- bool aDynamic, ScalarActionType aAction,
- const ScalarVariant& aValue) {
- internal_RecordScalarAction(
- lock,
- ScalarAction{aId, aDynamic, aAction, Some(aValue), ProcessID::Parent});
-}
-
-/**
- * Record the given action on a keyed scalar into the pending actions list.
- *
- * If the pending actions list overflows the high water mark length
- * all operations are immediately applied, including the passed action.
- *
- * @param aScalarAction The action to record.
- */
-void internal_RecordKeyedScalarAction(const StaticMutexAutoLock& lock,
- const KeyedScalarAction& aScalarAction) {
- // Make sure to have the storage.
- if (!gKeyedScalarsActions) {
- gKeyedScalarsActions = new nsTArray<KeyedScalarAction>();
- }
-
- // Store the action.
- gKeyedScalarsActions->AppendElement(aScalarAction);
-
- // If this action overflows the pending actions array, we immediately apply
- // pending operations and assume loading is over. If loading still happens
- // afterwards, some scalar values might be overwritten and inconsistent, but
- // we won't lose operations on otherwise untouched probes.
- if (gKeyedScalarsActions->Length() > kScalarActionsArrayHighWaterMark) {
- internal_ApplyPendingOperations(lock);
- return;
- }
-}
-
-/**
- * Record the given action on a keyed scalar on the main process into the
- * pending actions list.
- *
- * If the pending actions list overflows the high water mark length
- * all operations are immediately applied, including the passed action.
- *
- * @param aId The scalar's ID this action applies to
- * @param aDynamic Determines if the scalar is dynamic
- * @param aKey The scalar's key
- * @param aAction The action to record
- * @param aValue The additional data for the recorded action
- */
-void internal_RecordKeyedScalarAction(const StaticMutexAutoLock& lock,
- uint32_t aId, bool aDynamic,
- const nsAString& aKey,
- ScalarActionType aAction,
- const ScalarVariant& aValue) {
- internal_RecordKeyedScalarAction(
- lock,
- KeyedScalarAction{aId, aDynamic, aAction, NS_ConvertUTF16toUTF8(aKey),
- Some(aValue), ProcessID::Parent});
-}
-
/**
* Update the scalar with the provided value. This is used by the JS API.
*
@@ -1655,16 +1476,11 @@ void internal_RecordKeyedScalarAction(const StaticMutexAutoLock& lock,
* @param aName The scalar name.
* @param aType The action type for updating the scalar.
* @param aValue The value to use for updating the scalar.
- * @param aProcessOverride The process for which the scalar must be updated.
- * This must only be used for GeckoView persistence. It must be
- * set to the ProcessID::Parent for all the other cases.
- * @param aForce Whether to force updating even if load is in progress.
* @return a ScalarResult error value.
*/
-ScalarResult internal_UpdateScalar(
- const StaticMutexAutoLock& lock, const nsACString& aName,
- ScalarActionType aType, nsIVariant* aValue,
- ProcessID aProcessOverride = ProcessID::Parent, bool aForce = false) {
+ScalarResult internal_UpdateScalar(const StaticMutexAutoLock& lock,
+ const nsACString& aName,
+ ScalarActionType aType, nsIVariant* aValue) {
ScalarKey uniqueId;
nsresult rv = internal_GetEnumByScalarName(lock, aName, &uniqueId);
if (NS_FAILED(rv)) {
@@ -1672,7 +1488,7 @@ ScalarResult internal_UpdateScalar(
: ScalarResult::UnknownScalar;
}
- ScalarResult sr = internal_CanRecordScalar(lock, uniqueId, false, aForce);
+ ScalarResult sr = internal_CanRecordScalar(lock, uniqueId, false, false);
if (sr != ScalarResult::Ok) {
if (sr == ScalarResult::CannotRecordDataset) {
return ScalarResult::Ok;
@@ -1695,23 +1511,9 @@ ScalarResult internal_UpdateScalar(
return ScalarResult::Ok;
}
- if (!aForce && internal_IsScalarDeserializing(lock)) {
- const BaseScalarInfo& info = internal_GetScalarInfo(lock, uniqueId);
- // Convert the nsIVariant to a Variant.
- mozilla::Maybe<ScalarVariant> variantValue;
- sr = GetVariantFromIVariant(aValue, info.kind, variantValue);
- if (sr != ScalarResult::Ok) {
- MOZ_ASSERT(false, "Unable to convert nsIVariant to mozilla::Variant.");
- return sr;
- }
- internal_RecordScalarAction(lock, uniqueId.id, uniqueId.dynamic, aType,
- variantValue.ref());
- return ScalarResult::Ok;
- }
-
// Finally get the scalar.
ScalarBase* scalar = nullptr;
- rv = internal_GetScalarByEnum(lock, uniqueId, aProcessOverride, &scalar);
+ rv = internal_GetScalarByEnum(lock, uniqueId, ProcessID::Parent, &scalar);
if (NS_FAILED(rv)) {
// Don't throw on expired scalars.
if (rv == NS_ERROR_NOT_AVAILABLE) {
@@ -1823,15 +1625,13 @@ nsresult internal_GetKeyedScalarByEnum(const StaticMutexAutoLock& lock,
* @param aKey The key name.
* @param aType The action type for updating the scalar.
* @param aValue The value to use for updating the scalar.
- * @param aProcessOverride The process for which the scalar must be updated.
- * This must only be used for GeckoView persistence. It must be
- * set to the ProcessID::Parent for all the other cases.
* @return a ScalarResult error value.
*/
-ScalarResult internal_UpdateKeyedScalar(
- const StaticMutexAutoLock& lock, const nsACString& aName,
- const nsAString& aKey, ScalarActionType aType, nsIVariant* aValue,
- ProcessID aProcessOverride = ProcessID::Parent, bool aForce = false) {
+ScalarResult internal_UpdateKeyedScalar(const StaticMutexAutoLock& lock,
+ const nsACString& aName,
+ const nsAString& aKey,
+ ScalarActionType aType,
+ nsIVariant* aValue) {
ScalarKey uniqueId;
nsresult rv = internal_GetEnumByScalarName(lock, aName, &uniqueId);
if (NS_FAILED(rv)) {
@@ -1839,7 +1639,7 @@ ScalarResult internal_UpdateKeyedScalar(
: ScalarResult::UnknownScalar;
}
- ScalarResult sr = internal_CanRecordScalar(lock, uniqueId, true, aForce);
+ ScalarResult sr = internal_CanRecordScalar(lock, uniqueId, true, false);
if (sr != ScalarResult::Ok) {
if (sr == ScalarResult::CannotRecordDataset) {
return ScalarResult::Ok;
@@ -1862,23 +1662,10 @@ ScalarResult internal_UpdateKeyedScalar(
return ScalarResult::Ok;
}
- if (!aForce && internal_IsScalarDeserializing(lock)) {
- const BaseScalarInfo& info = internal_GetScalarInfo(lock, uniqueId);
- // Convert the nsIVariant to a Variant.
- mozilla::Maybe<ScalarVariant> variantValue;
- sr = GetVariantFromIVariant(aValue, info.kind, variantValue);
- if (sr != ScalarResult::Ok) {
- MOZ_ASSERT(false, "Unable to convert nsIVariant to mozilla::Variant.");
- return sr;
- }
- internal_RecordKeyedScalarAction(lock, uniqueId.id, uniqueId.dynamic, aKey,
- aType, variantValue.ref());
- return ScalarResult::Ok;
- }
-
// Finally get the scalar.
KeyedScalar* scalar = nullptr;
- rv = internal_GetKeyedScalarByEnum(lock, uniqueId, aProcessOverride, &scalar);
+ rv =
+ internal_GetKeyedScalarByEnum(lock, uniqueId, ProcessID::Parent, &scalar);
if (NS_FAILED(rv)) {
// Don't throw on expired scalars.
if (rv == NS_ERROR_NOT_AVAILABLE) {
@@ -2392,21 +2179,6 @@ void internal_ApplyKeyedScalarActions(
}
}
-void internal_ApplyPendingOperations(const StaticMutexAutoLock& lock) {
- if (gScalarsActions && gScalarsActions->Length() > 0) {
- internal_ApplyScalarActions(lock, *gScalarsActions);
- gScalarsActions->Clear();
- }
-
- if (gKeyedScalarsActions && gKeyedScalarsActions->Length() > 0) {
- internal_ApplyKeyedScalarActions(lock, *gKeyedScalarsActions);
- gKeyedScalarsActions->Clear();
- }
-
- // After all pending operations are applied deserialization is done
- gIsDeserializing = false;
-}
-
} // namespace
////////////////////////////////////////////////////////////////////////
@@ -2477,16 +2249,6 @@ void TelemetryScalar::DeInitializeGlobalState() {
gInitDone = false;
}
-void TelemetryScalar::DeserializationStarted() {
- StaticMutexAutoLock locker(gTelemetryScalarsMutex);
- gIsDeserializing = true;
-}
-
-void TelemetryScalar::ApplyPendingOperations() {
- StaticMutexAutoLock locker(gTelemetryScalarsMutex);
- internal_ApplyPendingOperations(locker);
-}
-
void TelemetryScalar::SetCanRecordBase(bool b) {
StaticMutexAutoLock locker(gTelemetryScalarsMutex);
gCanRecordBase = b;
@@ -2596,12 +2358,6 @@ void TelemetryScalar::Add(mozilla::Telemetry::ScalarID aId, uint32_t aValue) {
return;
}
- if (internal_IsScalarDeserializing(locker)) {
- internal_RecordScalarAction(locker, uniqueId.id, uniqueId.dynamic,
- ScalarActionType::eAdd, ScalarVariant(aValue));
- return;
- }
-
ScalarBase* scalar = nullptr;
nsresult rv =
internal_GetScalarByEnum(locker, uniqueId, ProcessID::Parent, &scalar);
@@ -2642,13 +2398,6 @@ void TelemetryScalar::Add(mozilla::Telemetry::ScalarID aId,
return;
}
- if (internal_IsScalarDeserializing(locker)) {
- internal_RecordKeyedScalarAction(locker, uniqueId.id, uniqueId.dynamic,
- aKey, ScalarActionType::eAdd,
- ScalarVariant(aValue));
- return;
- }
-
KeyedScalar* scalar = nullptr;
nsresult rv = internal_GetKeyedScalarByEnum(locker, uniqueId,
ProcessID::Parent, &scalar);
@@ -2758,12 +2507,6 @@ void TelemetryScalar::Set(mozilla::Telemetry::ScalarID aId, uint32_t aValue) {
return;
}
- if (internal_IsScalarDeserializing(locker)) {
- internal_RecordScalarAction(locker, uniqueId.id, uniqueId.dynamic,
- ScalarActionType::eSet, ScalarVariant(aValue));
- return;
- }
-
ScalarBase* scalar = nullptr;
nsresult rv =
internal_GetScalarByEnum(locker, uniqueId, ProcessID::Parent, &scalar);
@@ -2803,13 +2546,6 @@ void TelemetryScalar::Set(mozilla::Telemetry::ScalarID aId,
return;
}
- if (internal_IsScalarDeserializing(locker)) {
- internal_RecordScalarAction(locker, uniqueId.id, uniqueId.dynamic,
- ScalarActionType::eSet,
- ScalarVariant(nsString(aValue)));
- return;
- }
-
ScalarBase* scalar = nullptr;
nsresult rv =
internal_GetScalarByEnum(locker, uniqueId, ProcessID::Parent, &scalar);
@@ -2848,12 +2584,6 @@ void TelemetryScalar::Set(mozilla::Telemetry::ScalarID aId, bool aValue) {
return;
}
- if (internal_IsScalarDeserializing(locker)) {
- internal_RecordScalarAction(locker, uniqueId.id, uniqueId.dynamic,
- ScalarActionType::eSet, ScalarVariant(aValue));
- return;
- }
-
ScalarBase* scalar = nullptr;
nsresult rv =
internal_GetScalarByEnum(locker, uniqueId, ProcessID::Parent, &scalar);
@@ -2894,13 +2624,6 @@ void TelemetryScalar::Set(mozilla::Telemetry::ScalarID aId,
return;
}
- if (internal_IsScalarDeserializing(locker)) {
- internal_RecordKeyedScalarAction(locker, uniqueId.id, uniqueId.dynamic,
- aKey, ScalarActionType::eSet,
- ScalarVariant(aValue));
- return;
- }
-
KeyedScalar* scalar = nullptr;
nsresult rv = internal_GetKeyedScalarByEnum(locker, uniqueId,
ProcessID::Parent, &scalar);
@@ -2941,13 +2664,6 @@ void TelemetryScalar::Set(mozilla::Telemetry::ScalarID aId,
return;
}
- if (internal_IsScalarDeserializing(locker)) {
- internal_RecordKeyedScalarAction(locker, uniqueId.id, uniqueId.dynamic,
- aKey, ScalarActionType::eSet,
- ScalarVariant(aValue));
- return;
- }
-
KeyedScalar* scalar = nullptr;
nsresult rv = internal_GetKeyedScalarByEnum(locker, uniqueId,
ProcessID::Parent, &scalar);
@@ -3061,13 +2777,6 @@ void TelemetryScalar::SetMaximum(mozilla::Telemetry::ScalarID aId,
return;
}
- if (internal_IsScalarDeserializing(locker)) {
- internal_RecordScalarAction(locker, uniqueId.id, uniqueId.dynamic,
- ScalarActionType::eSetMaximum,
- ScalarVariant(aValue));
- return;
- }
-
ScalarBase* scalar = nullptr;
nsresult rv =
internal_GetScalarByEnum(locker, uniqueId, ProcessID::Parent, &scalar);
@@ -3108,13 +2817,6 @@ void TelemetryScalar::SetMaximum(mozilla::Telemetry::ScalarID aId,
return;
}
- if (internal_IsScalarDeserializing(locker)) {
- internal_RecordKeyedScalarAction(locker, uniqueId.id, uniqueId.dynamic,
- aKey, ScalarActionType::eSetMaximum,
- ScalarVariant(aValue));
- return;
- }
-
KeyedScalar* scalar = nullptr;
nsresult rv = internal_GetKeyedScalarByEnum(locker, uniqueId,
ProcessID::Parent, &scalar);
@@ -3538,8 +3240,6 @@ void TelemetryScalar::ClearScalars() {
gKeyedScalarStorageMap.Clear();
gDynamicBuiltinScalarStorageMap.Clear();
gDynamicBuiltinKeyedScalarStorageMap.Clear();
- gScalarsActions = nullptr;
- gKeyedScalarsActions = nullptr;
}
size_t TelemetryScalar::GetMapShallowSizesOfExcludingThis(
@@ -3580,20 +3280,6 @@ void TelemetryScalar::UpdateChildData(
"parent process.");
StaticMutexAutoLock locker(gTelemetryScalarsMutex);
- // If scalars are still being deserialized, we need to record the incoming
- // operations as well.
- if (internal_IsScalarDeserializing(locker)) {
- for (const ScalarAction& action : aScalarActions) {
- // We're only getting immutable access, so let's copy it
- ScalarAction copy = action;
- // Fix up the process type
- copy.mProcessType = aProcessType;
- internal_RecordScalarAction(locker, copy);
- }
-
- return;
- }
-
internal_ApplyScalarActions(locker, aScalarActions, Some(aProcessType));
}
@@ -3605,20 +3291,6 @@ void TelemetryScalar::UpdateChildKeyedData(
"from the parent process.");
StaticMutexAutoLock locker(gTelemetryScalarsMutex);
- // If scalars are still being deserialized, we need to record the incoming
- // operations as well.
- if (internal_IsScalarDeserializing(locker)) {
- for (const KeyedScalarAction& action : aScalarActions) {
- // We're only getting immutable access, so let's copy it
- KeyedScalarAction copy = action;
- // Fix up the process type
- copy.mProcessType = aProcessType;
- internal_RecordKeyedScalarAction(locker, copy);
- }
-
- return;
- }
-
internal_ApplyKeyedScalarActions(locker, aScalarActions, Some(aProcessType));
}
@@ -3632,10 +3304,6 @@ void TelemetryScalar::RecordDiscardedData(
return;
}
- if (GetCurrentProduct() == SupportedProduct::GeckoviewStreaming) {
- return;
- }
-
ScalarBase* scalar = nullptr;
mozilla::DebugOnly<nsresult> rv;
@@ -3754,437 +3422,3 @@ nsresult TelemetryScalar::GetAllStores(StringHashSet& set) {
return NS_OK;
}
-
-////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////
-//
-// PUBLIC: GeckoView serialization/deserialization functions.
-
-/**
- * Write the scalar data to the provided Json object, for
- * GeckoView measurement persistence. The output format is the same one used
- * for snapshotting the scalars.
- *
- * @param {aWriter} The JSON object to write to.
- * @returns NS_OK or a failure value explaining why persistence failed.
- */
-nsresult TelemetryScalar::SerializeScalars(mozilla::JSONWriter& aWriter) {
- // Get a copy of the data, without clearing.
- ScalarSnapshotTable scalarsToReflect;
- {
- StaticMutexAutoLock locker(gTelemetryScalarsMutex);
- // For persistence, we care about all the datasets. Worst case, they
- // will be empty.
- nsresult rv = internal_GetScalarSnapshot(
- locker, scalarsToReflect, nsITelemetry::DATASET_PRERELEASE_CHANNELS,
- false, /*aClearScalars*/
- "main"_ns);
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
-
- // Persist the scalars to the JSON object.
- for (const auto& entry : scalarsToReflect) {
- const ScalarTupleArray& processScalars = entry.GetData();
- const char* processName = GetNameForProcessID(ProcessID(entry.GetKey()));
-
- aWriter.StartObjectProperty(mozilla::MakeStringSpan(processName));
-
- for (const ScalarDataTuple& scalar : processScalars) {
- nsresult rv = WriteVariantToJSONWriter(
- std::get<2>(scalar) /*aScalarType*/,
- std::get<1>(scalar) /*aInputValue*/,
- mozilla::MakeStringSpan(std::get<0>(scalar)) /*aPropertyName*/,
- aWriter /*aWriter*/);
- if (NS_FAILED(rv)) {
- // Skip this scalar if we failed to write it. We don't bail out just
- // yet as we may salvage other scalars. We eventually need to call
- // EndObject.
- continue;
- }
- }
-
- aWriter.EndObject();
- }
-
- return NS_OK;
-}
-
-/**
- * Write the keyed scalar data to the provided Json object, for
- * GeckoView measurement persistence. The output format is the same
- * one used for snapshotting the keyed scalars.
- *
- * @param {aWriter} The JSON object to write to.
- * @returns NS_OK or a failure value explaining why persistence failed.
- */
-nsresult TelemetryScalar::SerializeKeyedScalars(mozilla::JSONWriter& aWriter) {
- // Get a copy of the data, without clearing.
- KeyedScalarSnapshotTable keyedScalarsToReflect;
- {
- StaticMutexAutoLock locker(gTelemetryScalarsMutex);
- // For persistence, we care about all the datasets. Worst case, they
- // will be empty.
- nsresult rv = internal_GetKeyedScalarSnapshot(
- locker, keyedScalarsToReflect,
- nsITelemetry::DATASET_PRERELEASE_CHANNELS, false, /*aClearScalars*/
- "main"_ns);
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
-
- // Persist the scalars to the JSON object.
- for (const auto& entry : keyedScalarsToReflect) {
- const KeyedScalarTupleArray& processScalars = entry.GetData();
- const char* processName = GetNameForProcessID(ProcessID(entry.GetKey()));
-
- aWriter.StartObjectProperty(mozilla::MakeStringSpan(processName));
-
- for (const KeyedScalarDataTuple& keyedScalarData : processScalars) {
- aWriter.StartObjectProperty(
- mozilla::MakeStringSpan(std::get<0>(keyedScalarData)));
-
- // Define a property for each scalar key, then add it to the keyed scalar
- // object.
- const nsTArray<KeyedScalar::KeyValuePair>& keyProps =
- std::get<1>(keyedScalarData);
- for (const KeyedScalar::KeyValuePair& keyData : keyProps) {
- nsresult rv = WriteVariantToJSONWriter(
- std::get<2>(keyedScalarData) /*aScalarType*/,
- keyData.second /*aInputValue*/,
- PromiseFlatCString(keyData.first) /*aOutKey*/, aWriter /*aWriter*/);
- if (NS_FAILED(rv)) {
- // Skip this scalar if we failed to write it. We don't bail out just
- // yet as we may salvage other scalars. We eventually need to call
- // EndObject.
- continue;
- }
- }
- aWriter.EndObject();
- }
- aWriter.EndObject();
- }
-
- return NS_OK;
-}
-
-/**
- * Load the persisted measurements from a Json object and inject them
- * in the relevant process storage.
- *
- * @param {aData} The input Json object.
- * @returns NS_OK if loading was performed, an error code explaining the
- * failure reason otherwise.
- */
-nsresult TelemetryScalar::DeserializePersistedScalars(
- JSContext* aCx, JS::Handle<JS::Value> aData) {
- MOZ_ASSERT(XRE_IsParentProcess(), "Only load scalars in the parent process");
- if (!XRE_IsParentProcess()) {
- return NS_ERROR_FAILURE;
- }
-
- typedef std::pair<nsCString, nsCOMPtr<nsIVariant>> PersistedScalarPair;
- typedef nsTArray<PersistedScalarPair> PersistedScalarArray;
- typedef nsTHashMap<ProcessIDHashKey, PersistedScalarArray>
- PeristedScalarStorage;
-
- PeristedScalarStorage scalarsToUpdate;
-
- // Before updating the scalars, we need to get the data out of the JS
- // wrappers. We can't hold the scalars mutex while handling JS stuff.
- // Build a <scalar name, value> map.
- JS::Rooted<JSObject*> scalarDataObj(aCx, &aData.toObject());
- JS::Rooted<JS::IdVector> processes(aCx, JS::IdVector(aCx));
- if (!JS_Enumerate(aCx, scalarDataObj, &processes)) {
- // We can't even enumerate the processes in the loaded data, so
- // there is nothing we could recover from the persistence file. Bail out.
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
-
- // The following block of code attempts to extract as much data as possible
- // from the serialized JSON, even in case of light data corruptions: if, for
- // example, the data for a single process is corrupted or is in an unexpected
- // form, we press on and attempt to load the data for the other processes.
- JS::Rooted<JS::PropertyKey> process(aCx);
- for (auto& processVal : processes) {
- // This is required as JS API calls require an Handle<jsid> and not a
- // plain jsid.
- process = processVal;
- // Get the process name.
- nsAutoJSString processNameJS;
- if (!processNameJS.init(aCx, process)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Make sure it's valid. Note that this is safe to call outside
- // of a locked section.
- NS_ConvertUTF16toUTF8 processName(processNameJS);
- ProcessID processID = GetIDForProcessName(processName.get());
- if (processID == ProcessID::Count) {
- NS_WARNING(
- nsPrintfCString("Failed to get process ID for %s", processName.get())
- .get());
- continue;
- }
-
- // And its probes.
- JS::Rooted<JS::Value> processData(aCx);
- if (!JS_GetPropertyById(aCx, scalarDataObj, process, &processData)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- if (!processData.isObject()) {
- // |processData| should be an object containing scalars. If this is
- // not the case, silently skip and try to load the data for the other
- // processes.
- continue;
- }
-
- // Iterate through each scalar.
- JS::Rooted<JSObject*> processDataObj(aCx, &processData.toObject());
- JS::Rooted<JS::IdVector> scalars(aCx, JS::IdVector(aCx));
- if (!JS_Enumerate(aCx, processDataObj, &scalars)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- JS::Rooted<JS::PropertyKey> scalar(aCx);
- for (auto& scalarVal : scalars) {
- scalar = scalarVal;
- // Get the scalar name.
- nsAutoJSString scalarName;
- if (!scalarName.init(aCx, scalar)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Get the scalar value as a JS value.
- JS::Rooted<JS::Value> scalarValue(aCx);
- if (!JS_GetPropertyById(aCx, processDataObj, scalar, &scalarValue)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- if (scalarValue.isNullOrUndefined()) {
- // We can't set scalars to null or undefined values, skip this
- // and try to load other scalars.
- continue;
- }
-
- // Unpack the aVal to nsIVariant.
- nsCOMPtr<nsIVariant> unpackedVal;
- nsresult rv = nsContentUtils::XPConnect()->JSToVariant(
- aCx, scalarValue, getter_AddRefs(unpackedVal));
- if (NS_FAILED(rv)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Add the scalar to the map.
- PersistedScalarArray& processScalars =
- scalarsToUpdate.LookupOrInsert(static_cast<uint32_t>(processID));
- processScalars.AppendElement(std::make_pair(
- nsCString(NS_ConvertUTF16toUTF8(scalarName)), unpackedVal));
- }
- }
-
- // Now that all the JS specific operations are finished, update the scalars.
- {
- StaticMutexAutoLock lock(gTelemetryScalarsMutex);
-
- for (const auto& entry : scalarsToUpdate) {
- const PersistedScalarArray& processScalars = entry.GetData();
- for (PersistedScalarArray::size_type i = 0; i < processScalars.Length();
- i++) {
- mozilla::Unused << internal_UpdateScalar(
- lock, processScalars[i].first, ScalarActionType::eSet,
- processScalars[i].second, ProcessID(entry.GetKey()),
- true /* aForce */);
- }
- }
- }
-
- return NS_OK;
-}
-
-/**
- * Load the persisted measurements from a Json object and injects them
- * in the relevant process storage.
- *
- * @param {aData} The input Json object.
- * @returns NS_OK if loading was performed, an error code explaining the
- * failure reason otherwise.
- */
-nsresult TelemetryScalar::DeserializePersistedKeyedScalars(
- JSContext* aCx, JS::Handle<JS::Value> aData) {
- MOZ_ASSERT(XRE_IsParentProcess(), "Only load scalars in the parent process");
- if (!XRE_IsParentProcess()) {
- return NS_ERROR_FAILURE;
- }
-
- typedef std::tuple<nsCString, nsString, nsCOMPtr<nsIVariant>>
- PersistedKeyedScalarTuple;
- typedef nsTArray<PersistedKeyedScalarTuple> PersistedKeyedScalarArray;
- typedef nsTHashMap<ProcessIDHashKey, PersistedKeyedScalarArray>
- PeristedKeyedScalarStorage;
-
- PeristedKeyedScalarStorage scalarsToUpdate;
-
- // Before updating the keyed scalars, we need to get the data out of the JS
- // wrappers. We can't hold the scalars mutex while handling JS stuff.
- // Build a <scalar name, value> map.
- JS::Rooted<JSObject*> scalarDataObj(aCx, &aData.toObject());
- JS::Rooted<JS::IdVector> processes(aCx, JS::IdVector(aCx));
- if (!JS_Enumerate(aCx, scalarDataObj, &processes)) {
- // We can't even enumerate the processes in the loaded data, so
- // there is nothing we could recover from the persistence file. Bail out.
- JS_ClearPendingException(aCx);
- return NS_ERROR_FAILURE;
- }
-
- // The following block of code attempts to extract as much data as possible
- // from the serialized JSON, even in case of light data corruptions: if, for
- // example, the data for a single process is corrupted or is in an unexpected
- // form, we press on and attempt to load the data for the other processes.
- JS::Rooted<JS::PropertyKey> process(aCx);
- for (auto& processVal : processes) {
- process = processVal;
- // Get the process name.
- nsAutoJSString processNameJS;
- if (!processNameJS.init(aCx, process)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Make sure it's valid. Note that this is safe to call outside
- // of a locked section.
- NS_ConvertUTF16toUTF8 processName(processNameJS);
- ProcessID processID = GetIDForProcessName(processName.get());
- if (processID == ProcessID::Count) {
- NS_WARNING(
- nsPrintfCString("Failed to get process ID for %s", processName.get())
- .get());
- continue;
- }
-
- // And its probes.
- JS::Rooted<JS::Value> processData(aCx);
- if (!JS_GetPropertyById(aCx, scalarDataObj, process, &processData)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- if (!processData.isObject()) {
- // |processData| should be an object containing scalars. If this is
- // not the case, silently skip and try to load the data for the other
- // processes.
- continue;
- }
-
- // Iterate through each keyed scalar.
- JS::Rooted<JSObject*> processDataObj(aCx, &processData.toObject());
- JS::Rooted<JS::IdVector> keyedScalars(aCx, JS::IdVector(aCx));
- if (!JS_Enumerate(aCx, processDataObj, &keyedScalars)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- JS::Rooted<JS::PropertyKey> keyedScalar(aCx);
- for (auto& keyedScalarVal : keyedScalars) {
- keyedScalar = keyedScalarVal;
- // Get the scalar name.
- nsAutoJSString scalarName;
- if (!scalarName.init(aCx, keyedScalar)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Get the data for this keyed scalar.
- JS::Rooted<JS::Value> keyedScalarData(aCx);
- if (!JS_GetPropertyById(aCx, processDataObj, keyedScalar,
- &keyedScalarData)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- if (!keyedScalarData.isObject()) {
- // Keyed scalar data need to be an object. If that's not the case, skip
- // it and try to load the rest of the data.
- continue;
- }
-
- // Get the keys in the keyed scalar.
- JS::Rooted<JSObject*> keyedScalarDataObj(aCx,
- &keyedScalarData.toObject());
- JS::Rooted<JS::IdVector> keys(aCx, JS::IdVector(aCx));
- if (!JS_Enumerate(aCx, keyedScalarDataObj, &keys)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- JS::Rooted<JS::PropertyKey> key(aCx);
- for (auto keyVal : keys) {
- key = keyVal;
- // Get the process name.
- nsAutoJSString keyName;
- if (!keyName.init(aCx, key)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Get the scalar value as a JS value.
- JS::Rooted<JS::Value> scalarValue(aCx);
- if (!JS_GetPropertyById(aCx, keyedScalarDataObj, key, &scalarValue)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- if (scalarValue.isNullOrUndefined()) {
- // We can't set scalars to null or undefined values, skip this
- // and try to load other scalars.
- continue;
- }
-
- // Unpack the aVal to nsIVariant.
- nsCOMPtr<nsIVariant> unpackedVal;
- nsresult rv = nsContentUtils::XPConnect()->JSToVariant(
- aCx, scalarValue, getter_AddRefs(unpackedVal));
- if (NS_FAILED(rv)) {
- JS_ClearPendingException(aCx);
- continue;
- }
-
- // Add the scalar to the map.
- PersistedKeyedScalarArray& processScalars =
- scalarsToUpdate.LookupOrInsert(static_cast<uint32_t>(processID));
- processScalars.AppendElement(
- std::make_tuple(nsCString(NS_ConvertUTF16toUTF8(scalarName)),
- nsString(keyName), unpackedVal));
- }
- }
- }
-
- // Now that all the JS specific operations are finished, update the scalars.
- {
- StaticMutexAutoLock lock(gTelemetryScalarsMutex);
-
- for (const auto& entry : scalarsToUpdate) {
- const PersistedKeyedScalarArray& processScalars = entry.GetData();
- for (PersistedKeyedScalarArray::size_type i = 0;
- i < processScalars.Length(); i++) {
- mozilla::Unused << internal_UpdateKeyedScalar(
- lock, std::get<0>(processScalars[i]),
- std::get<1>(processScalars[i]), ScalarActionType::eSet,
- std::get<2>(processScalars[i]), ProcessID(entry.GetKey()),
- true /* aForce */);
- }
- }
- }
-
- return NS_OK;
-}