Expose libstatspull as a stable C API
Libstatspull will ship as a part of the statsd apex in R.
Also update libstatssocket to have version 30 to align with api level,
as per native api council feedback.
Change both libraries to use NDK style naming conventions (AStatsEvent,
AStatsManager), and remove unneeded APIs in libstatssocket.
Remove KeyValuePairs from libstatssocket. KeyValuePairs will not be
supported in native code.
Bug: 147499386
Test: make libstatspull
Test: make libstatssocket
Test: atest libstatssocket_test
Change-Id: Ie79771461215a057529aaac91db95e4334c3960e
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
index 72eb0e9..2171aa4 100644
--- a/libstats/pull/Android.bp
+++ b/libstats/pull/Android.bp
@@ -32,7 +32,7 @@
],
export_include_dirs: ["include"],
shared_libs: [
- //TODO: use libbinder_ndk.
+ //TODO: use libbinder_ndk. Remove libservices.
"libbinder",
"libstatssocket",
"libservices",
@@ -40,5 +40,12 @@
static_libs: [
"liblog",
"libutils",
- ]
+ ],
+ // enumerate stable entry points for APEX use
+ stubs: {
+ symbol_file: "libstatspull.map.txt",
+ versions: [
+ "30",
+ ],
+ },
}
diff --git a/libstats/pull/include/stats_pull_atom_callback.h b/libstats/pull/include/stats_pull_atom_callback.h
index b779ac9..ad9b04e 100644
--- a/libstats/pull/include/stats_pull_atom_callback.h
+++ b/libstats/pull/include/stats_pull_atom_callback.h
@@ -15,41 +15,122 @@
*/
#pragma once
+#include <stats_event.h>
+
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
-/*
- * Metadata for registering a stats_pull_atom_callback.
+
+/**
+ * Opaque struct representing the metadata for registering an AStatsManager_PullAtomCallback.
*/
-typedef struct pull_atom_metadata {
- int64_t cool_down_ns;
- int64_t timeout_ns;
- int32_t* additive_fields;
- int32_t additive_fields_size;
-} pull_atom_metadata;
+struct AStatsManager_PullAtomMetadata;
+typedef struct AStatsManager_PullAtomMetadata AStatsManager_PullAtomMetadata;
-typedef struct pulled_stats_event_list pulled_stats_event_list;
+/**
+ * Allocate and initialize new PullAtomMetadata.
+ *
+ * Must call AStatsManager_PullAtomMetadata_release to free the memory.
+ */
+AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain();
-typedef int32_t status_pull_atom_return_t;
+/**
+ * Frees the memory held by this PullAtomMetadata
+ *
+ * After calling this, the PullAtomMetadata must not be used or modified in any way.
+ */
+void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata);
+/**
+ * Set the cool down time of the pull in nanoseconds. If two successive pulls are issued
+ * within the cool down, a cached version of the first will be used for the second.
+ */
+void AStatsManager_PullAtomMetadata_setCoolDownNs(AStatsManager_PullAtomMetadata* metadata,
+ int64_t cool_down_ns);
+
+/**
+ * Set the maximum time the pull can take in nanoseconds.
+ */
+void AStatsManager_PullAtomMetadata_setTimeoutNs(AStatsManager_PullAtomMetadata* metadata,
+ int64_t timeout_ns);
+
+/**
+ * Set the additive fields of this pulled atom.
+ *
+ * This is only applicable for atoms which have a uid field. When tasks are run in
+ * isolated processes, the data will be attributed to the host uid. Additive fields
+ * will be combined when the non-additive fields are the same.
+ */
+void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+ int* additive_fields, int num_fields);
+
+/**
+ * Return codes for the result of a pull.
+ */
+typedef int32_t AStatsManager_PullAtomCallbackReturn;
enum {
- STATS_PULL_SUCCESS = 0,
- STATS_PULL_SKIP = 1,
+ // Value indicating that this pull was successful and that the result should be used.
+ AStatsManager_PULL_SUCCESS = 0,
+ // Value indicating that this pull was unsuccessful and that the result should not be used.
+ AStatsManager_PULL_SKIP = 1,
};
-typedef status_pull_atom_return_t (*stats_pull_atom_callback_t)(int32_t atom_tag,
- pulled_stats_event_list* data,
- void* cookie);
+/**
+ * Opaque struct representing a list of AStatsEvent objects.
+ */
+struct AStatsEventList;
+typedef struct AStatsEventList AStatsEventList;
-struct stats_event* add_stats_event_to_pull_data(pulled_stats_event_list* pull_data);
+/**
+ * Appends and returns an AStatsEvent to the end of the AStatsEventList.
+ *
+ * If an AStatsEvent is obtained in this manner, the memory is internally managed and
+ * AStatsEvent_release does not need to be called. The lifetime of the AStatsEvent is that of the
+ * AStatsEventList.
+ *
+ * The AStatsEvent does still need to be built by calling AStatsEvent_build.
+ */
+AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data);
-void register_stats_pull_atom_callback(int32_t atom_tag, stats_pull_atom_callback_t callback,
- pull_atom_metadata* metadata, void* cookie);
+/**
+ * Callback interface for pulling atoms requested by the stats service.
+ *
+ * \param atom_tag the tag of the atom to pull.
+ * \param data an output parameter in which the caller should fill the results of the pull. This
+ * param cannot be NULL and it's lifetime is as long as the execution of the callback.
+ * It must not be accessed or modified after returning from the callback.
+ * \param cookie the opaque pointer passed in AStatsManager_registerPullAtomCallback.
+ * \return AStatsManager_PULL_SUCCESS if the pull was successful, or AStatsManager_PULL_SKIP if not.
+ */
+typedef AStatsManager_PullAtomCallbackReturn (*AStatsManager_PullAtomCallback)(
+ int32_t atom_tag, AStatsEventList* data, void* cookie);
+/**
+ * Registers a callback for an atom when that atom is to be pulled. The stats service will
+ * invoke the callback when the stats service determines that this atom needs to be
+ * pulled.
+ *
+ * \param atom_tag The tag of the atom for this pull atom callback.
+ * \param metadata Optional metadata specifying the timeout, cool down time, and
+ * additive fields for mapping isolated to host uids.
+ * This param is nullable, in which case defaults will be used.
+ * \param callback The callback to be invoked when the stats service pulls the atom.
+ * \param cookie A pointer that will be passed back to the callback.
+ * It has no meaning to statsd.
+ */
+void AStatsManager_registerPullAtomCallback(int32_t atom_tag,
+ AStatsManager_PullAtomCallback callback,
+ AStatsManager_PullAtomMetadata* metadata, void* cookie);
-void unregister_stats_pull_atom_callback(int32_t atom_tag);
+/**
+ * Unregisters a callback for an atom when that atom is to be pulled. Note that any ongoing
+ * pulls will still occur.
+ *
+ * \param atomTag The tag of the atom of which to unregister
+ */
+void AStatsManager_unregisterPullAtomCallback(int32_t atom_tag);
#ifdef __cplusplus
}
diff --git a/libstats/pull/libstatspull.map.txt b/libstats/pull/libstatspull.map.txt
new file mode 100644
index 0000000..dc3fd8b
--- /dev/null
+++ b/libstats/pull/libstatspull.map.txt
@@ -0,0 +1,13 @@
+LIBSTATSPULL {
+ global:
+ AStatsManager_PullAtomMetadata_obtain; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_release; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_setCoolDownNs; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_setTimeoutNs; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_setAdditiveFields; # apex # introduced=30
+ AStatsEventList_addStatsEvent; # apex # introduced=30
+ AStatsManager_registerPullAtomCallback; # apex # introduced=30
+ AStatsManager_unregisterPullAtomCallback; # apex # introduced=30
+ local:
+ *;
+};
diff --git a/libstats/pull/stats_pull_atom_callback.cpp b/libstats/pull/stats_pull_atom_callback.cpp
index e8fc2ea..9c497b8 100644
--- a/libstats/pull/stats_pull_atom_callback.cpp
+++ b/libstats/pull/stats_pull_atom_callback.cpp
@@ -28,12 +28,12 @@
#include <thread>
-struct pulled_stats_event_list {
- std::vector<stats_event*> data;
+struct AStatsEventList {
+ std::vector<AStatsEvent*> data;
};
-struct stats_event* add_stats_event_to_pull_data(pulled_stats_event_list* pull_data) {
- struct stats_event* event = stats_event_obtain();
+AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data) {
+ AStatsEvent* event = AStatsEvent_obtain();
pull_data->data.push_back(event);
return event;
}
@@ -41,9 +41,42 @@
static const int64_t DEFAULT_COOL_DOWN_NS = 1000000000LL; // 1 second.
static const int64_t DEFAULT_TIMEOUT_NS = 10000000000LL; // 10 seconds.
+struct AStatsManager_PullAtomMetadata {
+ int64_t cool_down_ns;
+ int64_t timeout_ns;
+ std::vector<int32_t> additive_fields;
+};
+
+AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain() {
+ AStatsManager_PullAtomMetadata* metadata = new AStatsManager_PullAtomMetadata();
+ metadata->cool_down_ns = DEFAULT_COOL_DOWN_NS;
+ metadata->timeout_ns = DEFAULT_TIMEOUT_NS;
+ metadata->additive_fields = std::vector<int32_t>();
+ return metadata;
+}
+
+void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata) {
+ delete metadata;
+}
+
+void AStatsManager_PullAtomMetadata_setCoolDownNs(AStatsManager_PullAtomMetadata* metadata,
+ int64_t cool_down_ns) {
+ metadata->cool_down_ns = cool_down_ns;
+}
+
+void AStatsManager_PullAtomMetadata_setTimeoutNs(AStatsManager_PullAtomMetadata* metadata,
+ int64_t timeout_ns) {
+ metadata->timeout_ns = timeout_ns;
+}
+
+void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+ int* additive_fields, int num_fields) {
+ metadata->additive_fields.assign(additive_fields, additive_fields + num_fields);
+}
+
class StatsPullAtomCallbackInternal : public android::os::BnPullAtomCallback {
public:
- StatsPullAtomCallbackInternal(const stats_pull_atom_callback_t callback, void* cookie,
+ StatsPullAtomCallbackInternal(const AStatsManager_PullAtomCallback callback, void* cookie,
const int64_t coolDownNs, const int64_t timeoutNs,
const std::vector<int32_t> additiveFields)
: mCallback(callback),
@@ -55,15 +88,16 @@
::android::binder::Status onPullAtom(
int32_t atomTag,
const ::android::sp<::android::os::IPullAtomResultReceiver>& resultReceiver) override {
- pulled_stats_event_list statsEventList;
+ AStatsEventList statsEventList;
+ statsEventList.data.clear();
int successInt = mCallback(atomTag, &statsEventList, mCookie);
- bool success = successInt == STATS_PULL_SUCCESS;
+ bool success = successInt == AStatsManager_PULL_SUCCESS;
// Convert stats_events into StatsEventParcels.
std::vector<android::util::StatsEventParcel> parcels;
for (int i = 0; i < statsEventList.data.size(); i++) {
size_t size;
- uint8_t* buffer = stats_event_get_buffer(statsEventList.data[i], &size);
+ uint8_t* buffer = AStatsEvent_getBuffer(statsEventList.data[i], &size);
android::util::StatsEventParcel p;
// vector.assign() creates a copy, but this is inevitable unless
@@ -74,7 +108,7 @@
resultReceiver->pullFinished(atomTag, success, parcels);
for (int i = 0; i < statsEventList.data.size(); i++) {
- stats_event_release(statsEventList.data[i]);
+ AStatsEvent_release(statsEventList.data[i]);
}
return android::binder::Status::ok();
}
@@ -84,7 +118,7 @@
const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; }
private:
- const stats_pull_atom_callback_t mCallback;
+ const AStatsManager_PullAtomCallback mCallback;
void* mCookie;
const int64_t mCoolDownNs;
const int64_t mTimeoutNs;
@@ -165,15 +199,16 @@
statsService->unregisterNativePullAtomCallback(atomTag);
}
-void register_stats_pull_atom_callback(int32_t atom_tag, stats_pull_atom_callback_t callback,
- pull_atom_metadata* metadata, void* cookie) {
+void AStatsManager_registerPullAtomCallback(int32_t atom_tag,
+ AStatsManager_PullAtomCallback callback,
+ AStatsManager_PullAtomMetadata* metadata,
+ void* cookie) {
int64_t coolDownNs = metadata == nullptr ? DEFAULT_COOL_DOWN_NS : metadata->cool_down_ns;
int64_t timeoutNs = metadata == nullptr ? DEFAULT_TIMEOUT_NS : metadata->timeout_ns;
std::vector<int32_t> additiveFields;
- if (metadata != nullptr && metadata->additive_fields != nullptr) {
- additiveFields.assign(metadata->additive_fields,
- metadata->additive_fields + metadata->additive_fields_size);
+ if (metadata != nullptr) {
+ additiveFields = metadata->additive_fields;
}
android::sp<StatsPullAtomCallbackInternal> callbackBinder = new StatsPullAtomCallbackInternal(
@@ -189,7 +224,7 @@
registerThread.detach();
}
-void unregister_stats_pull_atom_callback(int32_t atom_tag) {
+void AStatsManager_unregisterPullAtomCallback(int32_t atom_tag) {
{
std::lock_guard<std::mutex> lg(pullAtomMutex);
// Always remove the puller from our map.
diff --git a/libstats/push_compat/StatsEventCompat.cpp b/libstats/push_compat/StatsEventCompat.cpp
index edfa070..de458b3 100644
--- a/libstats/push_compat/StatsEventCompat.cpp
+++ b/libstats/push_compat/StatsEventCompat.cpp
@@ -38,7 +38,7 @@
// definitions of static class variables
bool StatsEventCompat::mAttemptedLoad = false;
-struct stats_event_api_table* StatsEventCompat::mStatsEventApi = nullptr;
+void* StatsEventCompat::mStatsEventApi = nullptr;
std::mutex StatsEventCompat::mLoadLock;
StatsEventCompat::StatsEventCompat() : mEventQ(kStatsEventTag) {
@@ -49,7 +49,8 @@
if (!mAttemptedLoad) {
void* handle = dlopen("libstatssocket.so", RTLD_NOW);
if (handle) {
- mStatsEventApi = (struct stats_event_api_table*)dlsym(handle, "table");
+ // mStatsEventApi = (struct AStatsEvent_apiTable*)dlsym(handle,
+ // "table");
} else {
ALOGE("dlopen failed: %s\n", dlerror());
}
@@ -58,19 +59,19 @@
}
if (mStatsEventApi) {
- mEventR = mStatsEventApi->obtain();
+ // mEventR = mStatsEventApi->obtain();
} else if (!mPlatformAtLeastR) {
mEventQ << android::elapsedRealtimeNano();
}
}
StatsEventCompat::~StatsEventCompat() {
- if (mStatsEventApi) mStatsEventApi->release(mEventR);
+ // if (mStatsEventApi) mStatsEventApi->release(mEventR);
}
void StatsEventCompat::setAtomId(int32_t atomId) {
if (mStatsEventApi) {
- mStatsEventApi->set_atom_id(mEventR, (uint32_t)atomId);
+ // mStatsEventApi->setAtomId(mEventR, (uint32_t)atomId);
} else if (!mPlatformAtLeastR) {
mEventQ << atomId;
}
@@ -78,7 +79,7 @@
void StatsEventCompat::writeInt32(int32_t value) {
if (mStatsEventApi) {
- mStatsEventApi->write_int32(mEventR, value);
+ // mStatsEventApi->writeInt32(mEventR, value);
} else if (!mPlatformAtLeastR) {
mEventQ << value;
}
@@ -86,7 +87,7 @@
void StatsEventCompat::writeInt64(int64_t value) {
if (mStatsEventApi) {
- mStatsEventApi->write_int64(mEventR, value);
+ // mStatsEventApi->writeInt64(mEventR, value);
} else if (!mPlatformAtLeastR) {
mEventQ << value;
}
@@ -94,7 +95,7 @@
void StatsEventCompat::writeFloat(float value) {
if (mStatsEventApi) {
- mStatsEventApi->write_float(mEventR, value);
+ // mStatsEventApi->writeFloat(mEventR, value);
} else if (!mPlatformAtLeastR) {
mEventQ << value;
}
@@ -102,7 +103,7 @@
void StatsEventCompat::writeBool(bool value) {
if (mStatsEventApi) {
- mStatsEventApi->write_bool(mEventR, value);
+ // mStatsEventApi->writeBool(mEventR, value);
} else if (!mPlatformAtLeastR) {
mEventQ << value;
}
@@ -110,7 +111,7 @@
void StatsEventCompat::writeByteArray(const char* buffer, size_t length) {
if (mStatsEventApi) {
- mStatsEventApi->write_byte_array(mEventR, (const uint8_t*)buffer, length);
+ // mStatsEventApi->writeByteArray(mEventR, (const uint8_t*)buffer, length);
} else if (!mPlatformAtLeastR) {
mEventQ.AppendCharArray(buffer, length);
}
@@ -120,7 +121,7 @@
if (value == nullptr) value = "";
if (mStatsEventApi) {
- mStatsEventApi->write_string8(mEventR, value);
+ // mStatsEventApi->writeString(mEventR, value);
} else if (!mPlatformAtLeastR) {
mEventQ << value;
}
@@ -129,8 +130,8 @@
void StatsEventCompat::writeAttributionChain(const int32_t* uids, size_t numUids,
const vector<const char*>& tags) {
if (mStatsEventApi) {
- mStatsEventApi->write_attribution_chain(mEventR, (const uint32_t*)uids, tags.data(),
- (uint8_t)numUids);
+ // mStatsEventApi->writeAttributionChain(mEventR, (const uint32_t*)uids, tags.data(),
+ // (uint8_t)numUids);
} else if (!mPlatformAtLeastR) {
mEventQ.begin();
for (size_t i = 0; i < numUids; i++) {
@@ -148,26 +149,8 @@
const map<int, int64_t>& int64Map,
const map<int, const char*>& stringMap,
const map<int, float>& floatMap) {
- if (mStatsEventApi) {
- vector<struct key_value_pair> pairs;
-
- for (const auto& it : int32Map) {
- pairs.push_back({.key = it.first, .valueType = INT32_TYPE, .int32Value = it.second});
- }
- for (const auto& it : int64Map) {
- pairs.push_back({.key = it.first, .valueType = INT64_TYPE, .int64Value = it.second});
- }
- for (const auto& it : stringMap) {
- pairs.push_back({.key = it.first, .valueType = STRING_TYPE, .stringValue = it.second});
- }
- for (const auto& it : floatMap) {
- pairs.push_back({.key = it.first, .valueType = FLOAT_TYPE, .floatValue = it.second});
- }
-
- mStatsEventApi->write_key_value_pairs(mEventR, pairs.data(), (uint8_t)pairs.size());
- }
-
- else if (!mPlatformAtLeastR) {
+ // Key value pairs are not supported with AStatsEvent.
+ if (!mPlatformAtLeastR) {
mEventQ.begin();
writeKeyValuePairMap(int32Map);
writeKeyValuePairMap(int64Map);
@@ -194,19 +177,25 @@
template void StatsEventCompat::writeKeyValuePairMap<const char*>(const map<int, const char*>&);
void StatsEventCompat::addBoolAnnotation(uint8_t annotationId, bool value) {
- if (mStatsEventApi) mStatsEventApi->add_bool_annotation(mEventR, annotationId, value);
+ // Workaround for unused params.
+ (void)annotationId;
+ (void)value;
+ // if (mStatsEventApi) mStatsEventApi->addBoolAnnotation(mEventR, annotationId, value);
// Don't do anything if on Q.
}
void StatsEventCompat::addInt32Annotation(uint8_t annotationId, int32_t value) {
- if (mStatsEventApi) mStatsEventApi->add_int32_annotation(mEventR, annotationId, value);
+ // Workaround for unused params.
+ (void)annotationId;
+ (void)value;
+ // if (mStatsEventApi) mStatsEventApi->addInt32Annotation(mEventR, annotationId, value);
// Don't do anything if on Q.
}
int StatsEventCompat::writeToSocket() {
if (mStatsEventApi) {
- mStatsEventApi->build(mEventR);
- return mStatsEventApi->write(mEventR);
+ // mStatsEventApi->build(mEventR);
+ // return mStatsEventApi->write(mEventR);
}
if (!mPlatformAtLeastR) return mEventQ.write(LOG_ID_STATS);
diff --git a/libstats/push_compat/include/StatsEventCompat.h b/libstats/push_compat/include/StatsEventCompat.h
index a8cde68..ad423a1 100644
--- a/libstats/push_compat/include/StatsEventCompat.h
+++ b/libstats/push_compat/include/StatsEventCompat.h
@@ -57,10 +57,11 @@
const static bool mPlatformAtLeastR;
static bool mAttemptedLoad;
static std::mutex mLoadLock;
- static struct stats_event_api_table* mStatsEventApi;
+ // static struct AStatsEvent_apiTable* mStatsEventApi;
+ static void* mStatsEventApi;
// non-static member variables
- struct stats_event* mEventR = nullptr;
+ AStatsEvent* mEventR = nullptr;
stats_event_list mEventQ;
template <class T>
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index 9fd9fbc..d76a5e7 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -45,7 +45,7 @@
stubs: {
symbol_file: "libstatssocket.map.txt",
versions: [
- "1",
+ "30",
],
}
}
diff --git a/libstats/socket/benchmark/stats_event_benchmark.cpp b/libstats/socket/benchmark/stats_event_benchmark.cpp
index 9488168..3fc6e55 100644
--- a/libstats/socket/benchmark/stats_event_benchmark.cpp
+++ b/libstats/socket/benchmark/stats_event_benchmark.cpp
@@ -17,14 +17,14 @@
#include "benchmark/benchmark.h"
#include "stats_event.h"
-static struct stats_event* constructStatsEvent() {
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, 100);
+static AStatsEvent* constructStatsEvent() {
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, 100);
// randomly sample atom size
int numElements = rand() % 800;
for (int i = 0; i < numElements; i++) {
- stats_event_write_int32(event, i);
+ AStatsEvent_writeInt32(event, i);
}
return event;
@@ -32,10 +32,10 @@
static void BM_stats_event_truncate_buffer(benchmark::State& state) {
while (state.KeepRunning()) {
- struct stats_event* event = constructStatsEvent();
- stats_event_build(event);
- stats_event_write(event);
- stats_event_release(event);
+ AStatsEvent* event = constructStatsEvent();
+ AStatsEvent_build(event);
+ AStatsEvent_write(event);
+ AStatsEvent_release(event);
}
}
@@ -43,11 +43,11 @@
static void BM_stats_event_full_buffer(benchmark::State& state) {
while (state.KeepRunning()) {
- struct stats_event* event = constructStatsEvent();
- stats_event_truncate_buffer(event, false);
- stats_event_build(event);
- stats_event_write(event);
- stats_event_release(event);
+ AStatsEvent* event = constructStatsEvent();
+ AStatsEvent_truncateBuffer(event, false);
+ AStatsEvent_build(event);
+ AStatsEvent_write(event);
+ AStatsEvent_release(event);
}
}
diff --git a/libstats/socket/include/stats_event.h b/libstats/socket/include/stats_event.h
index 080e957..6a2d9cd 100644
--- a/libstats/socket/include/stats_event.h
+++ b/libstats/socket/include/stats_event.h
@@ -26,17 +26,17 @@
* This code defines and encapsulates the socket protocol.
*
* Usage:
- * struct stats_event* event = stats_event_obtain();
+ * AStatsEvent* event = AStatsEvent_obtain();
*
- * stats_event_set_atom_id(event, atomId);
- * stats_event_write_int32(event, 24);
- * stats_event_add_bool_annotation(event, 1, true); // annotations apply to the previous field
- * stats_event_add_int32_annotation(event, 2, 128);
- * stats_event_write_float(event, 2.0);
+ * AStatsEvent_setAtomId(event, atomId);
+ * AStatsEvent_writeInt32(event, 24);
+ * AStatsEvent_addBoolAnnotation(event, 1, true); // annotations apply to the previous field
+ * AStatsEvent_addInt32Annotation(event, 2, 128);
+ * AStatsEvent_writeFloat(event, 2.0);
*
- * stats_event_build(event);
- * stats_event_write(event);
- * stats_event_release(event);
+ * AStatsEvent_build(event);
+ * AStatsEvent_write(event);
+ * AStatsEvent_release(event);
*
* Notes:
* (a) write_<type>() and add_<type>_annotation() should be called in the order that fields
@@ -47,115 +47,118 @@
* (e) All strings should be encoded using UTF8.
*/
-/* ERRORS */
-#define ERROR_NO_TIMESTAMP 0x1
-#define ERROR_NO_ATOM_ID 0x2
-#define ERROR_OVERFLOW 0x4
-#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
-#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
-#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
-#define ERROR_INVALID_ANNOTATION_ID 0x40
-#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
-#define ERROR_TOO_MANY_ANNOTATIONS 0x100
-#define ERROR_TOO_MANY_FIELDS 0x200
-#define ERROR_INVALID_VALUE_TYPE 0x400
-#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
-
-/* TYPE IDS */
-#define INT32_TYPE 0x00
-#define INT64_TYPE 0x01
-#define STRING_TYPE 0x02
-#define LIST_TYPE 0x03
-#define FLOAT_TYPE 0x04
-#define BOOL_TYPE 0x05
-#define BYTE_ARRAY_TYPE 0x06
-#define OBJECT_TYPE 0x07
-#define KEY_VALUE_PAIRS_TYPE 0x08
-#define ATTRIBUTION_CHAIN_TYPE 0x09
-#define ERROR_TYPE 0x0F
-
#ifdef __cplusplus
extern "C" {
#endif // __CPLUSPLUS
-struct stats_event;
-
-/* SYSTEM API */
-struct stats_event* stats_event_obtain();
-// The build function can be called multiple times without error. If the event
-// has been built before, this function is a no-op.
-void stats_event_build(struct stats_event* event);
-int stats_event_write(struct stats_event* event);
-void stats_event_release(struct stats_event* event);
-
-void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId);
-
-void stats_event_write_int32(struct stats_event* event, int32_t value);
-void stats_event_write_int64(struct stats_event* event, int64_t value);
-void stats_event_write_float(struct stats_event* event, float value);
-void stats_event_write_bool(struct stats_event* event, bool value);
-
-void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes);
-
-// Buf must be null-terminated.
-void stats_event_write_string8(struct stats_event* event, const char* value);
-
-// Tags must be null-terminated.
-void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
- const char* const* tags, uint8_t numNodes);
-
-/* key_value_pair struct can be constructed as follows:
- * struct key_value_pair pair = {.key = key, .valueType = STRING_TYPE,
- * .stringValue = buf};
+/**
+ * Opaque struct use to represent a StatsEvent. It builds and stores the data that is sent to
+ * statsd.
*/
-struct key_value_pair {
- int32_t key;
- uint8_t valueType; // expected to be INT32_TYPE, INT64_TYPE, FLOAT_TYPE, or STRING_TYPE
- union {
- int32_t int32Value;
- int64_t int64Value;
- float floatValue;
- const char* stringValue; // must be null terminated
- };
-};
+struct AStatsEvent;
+typedef struct AStatsEvent AStatsEvent;
-void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
- uint8_t numPairs);
+/**
+ * Returns a new AStatsEvent. If you call this function, you must call AStatsEvent_release to free
+ * the allocated memory.
+ */
+AStatsEvent* AStatsEvent_obtain();
-void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value);
-void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
- int32_t value);
+/**
+ * Builds and finalizes the StatsEvent.
+ *
+ * After this function, the StatsEvent must not be modified in any way other than calling release or
+ * write. Build must be always be called before AStatsEvent_write.
+ *
+ * Build can be called multiple times without error.
+ * If the event has been built before, this function is a no-op.
+ */
+void AStatsEvent_build(AStatsEvent* event);
-uint32_t stats_event_get_atom_id(struct stats_event* event);
+/**
+ * Writes the StatsEvent to the stats log.
+ *
+ * After calling this, AStatsEvent_release must be called,
+ * and is the only function that can be safely called.
+ */
+int AStatsEvent_write(AStatsEvent* event);
+
+/**
+ * Frees the memory held by this StatsEvent
+ *
+ * After calling this, the StatsEvent must not be used or modified in any way.
+ */
+void AStatsEvent_release(AStatsEvent* event);
+
+/**
+ * Sets the atom id for this StatsEvent.
+ **/
+void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId);
+
+/**
+ * Writes an int32_t field to this StatsEvent.
+ **/
+void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value);
+
+/**
+ * Writes an int64_t field to this StatsEvent.
+ **/
+void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value);
+
+/**
+ * Writes a float field to this StatsEvent.
+ **/
+void AStatsEvent_writeFloat(AStatsEvent* event, float value);
+
+/**
+ * Write a bool field to this StatsEvent.
+ **/
+void AStatsEvent_writeBool(AStatsEvent* event, bool value);
+
+/**
+ * Write a byte array field to this StatsEvent.
+ **/
+void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes);
+
+/**
+ * Write a string field to this StatsEvent.
+ *
+ * The string must be null-terminated.
+ **/
+void AStatsEvent_writeString(AStatsEvent* event, const char* value);
+
+/**
+ * Write an attribution chain field to this StatsEvent.
+ *
+ * The sizes of uids and tags must be equal. The AttributionNode at position i is
+ * made up of uids[i] and tags[i].
+ *
+ * \param uids array of uids in the attribution chain.
+ * \param tags array of tags in the attribution chain. Each tag must be null-terminated.
+ * \param numNodes the number of AttributionNodes in the attribution chain. This is the length of
+ * the uids and the tags.
+ **/
+void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
+ const char* const* tags, uint8_t numNodes);
+
+/**
+ * Write a bool annotation for the previous field written.
+ **/
+void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value);
+
+/**
+ * Write an integer annotation for the previous field written.
+ **/
+void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value);
+
+// Internal/test APIs. Should not be exposed outside of the APEX.
+uint32_t AStatsEvent_getAtomId(AStatsEvent* event);
// Size is an output parameter.
-uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size);
-uint32_t stats_event_get_errors(struct stats_event* event);
-
-// This table is used by StatsEventCompat to access the stats_event API.
-struct stats_event_api_table {
- struct stats_event* (*obtain)(void);
- void (*build)(struct stats_event*);
- int (*write)(struct stats_event*);
- void (*release)(struct stats_event*);
- void (*set_atom_id)(struct stats_event*, uint32_t);
- void (*write_int32)(struct stats_event*, int32_t);
- void (*write_int64)(struct stats_event*, int64_t);
- void (*write_float)(struct stats_event*, float);
- void (*write_bool)(struct stats_event*, bool);
- void (*write_byte_array)(struct stats_event*, const uint8_t*, size_t);
- void (*write_string8)(struct stats_event*, const char*);
- void (*write_attribution_chain)(struct stats_event*, const uint32_t*, const char* const*,
- uint8_t);
- void (*write_key_value_pairs)(struct stats_event*, struct key_value_pair*, uint8_t);
- void (*add_bool_annotation)(struct stats_event*, uint8_t, bool);
- void (*add_int32_annotation)(struct stats_event*, uint8_t, int32_t);
- uint32_t (*get_atom_id)(struct stats_event*);
- uint8_t* (*get_buffer)(struct stats_event*, size_t*);
- uint32_t (*get_errors)(struct stats_event*);
-};
+uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size);
+uint32_t AStatsEvent_getErrors(AStatsEvent* event);
// exposed for benchmarking only
-void stats_event_truncate_buffer(struct stats_event* event, bool truncate);
+void AStatsEvent_truncateBuffer(struct AStatsEvent* event, bool truncate);
#ifdef __cplusplus
}
diff --git a/libstats/socket/libstatssocket.map.txt b/libstats/socket/libstatssocket.map.txt
index 55bfbda..e2e7ae3 100644
--- a/libstats/socket/libstatssocket.map.txt
+++ b/libstats/socket/libstatssocket.map.txt
@@ -1,23 +1,19 @@
LIBSTATSSOCKET {
global:
- stats_event_obtain; # apex # introduced=1
- stats_event_build; # apex # introduced=1
- stats_event_write; # apex # introduced=1
- stats_event_release; # apex # introduced=1
- stats_event_set_atom_id; # apex # introduced=1
- stats_event_write_int32; # apex # introduced=1
- stats_event_write_int64; # apex # introduced=1
- stats_event_write_float; # apex # introduced=1
- stats_event_write_bool; # apex # introduced=1
- stats_event_write_byte_array; # apex # introduced=1
- stats_event_write_string8; # apex # introduced=1
- stats_event_write_attribution_chain; # apex # introduced=1
- stats_event_write_key_value_pairs; # apex # introduced=1
- stats_event_add_bool_annotation; # apex # introduced=1
- stats_event_add_int32_annotation; # apex # introduced=1
- stats_event_get_atom_id; # apex # introduced=1
- stats_event_get_buffer; # apex # introduced=1
- stats_event_get_errors; # apex # introduced=1
+ AStatsEvent_obtain; # apex # introduced=30
+ AStatsEvent_build; # apex # introduced=30
+ AStatsEvent_write; # apex # introduced=30
+ AStatsEvent_release; # apex # introduced=30
+ AStatsEvent_setAtomId; # apex # introduced=30
+ AStatsEvent_writeInt32; # apex # introduced=30
+ AStatsEvent_writeInt64; # apex # introduced=30
+ AStatsEvent_writeFloat; # apex # introduced=30
+ AStatsEvent_writeBool; # apex # introduced=30
+ AStatsEvent_writeByteArray; # apex # introduced=30
+ AStatsEvent_writeString; # apex # introduced=30
+ AStatsEvent_writeAttributionChain; # apex # introduced=30
+ AStatsEvent_addBoolAnnotation; # apex # introduced=30
+ AStatsEvent_addInt32Annotation; # apex # introduced=30
local:
*;
};
diff --git a/libstats/socket/stats_event.c b/libstats/socket/stats_event.c
index 15039c6..5f77558 100644
--- a/libstats/socket/stats_event.c
+++ b/libstats/socket/stats_event.c
@@ -35,9 +35,36 @@
#define MAX_ANNOTATION_COUNT 15
#define MAX_BYTE_VALUE 127 // parsing side requires that lengths fit in 7 bits
-// The stats_event struct holds the serialized encoding of an event
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
+// The AStatsEvent struct holds the serialized encoding of an event
// within a buf. Also includes other required fields.
-struct stats_event {
+struct AStatsEvent {
uint8_t* buf;
size_t lastFieldPos; // location of last field within the buf
size_t size; // number of valid bytes within buffer
@@ -55,8 +82,8 @@
return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;
}
-struct stats_event* stats_event_obtain() {
- struct stats_event* event = malloc(sizeof(struct stats_event));
+AStatsEvent* AStatsEvent_obtain() {
+ AStatsEvent* event = malloc(sizeof(AStatsEvent));
event->buf = (uint8_t*)calloc(MAX_EVENT_PAYLOAD, 1);
event->buf[0] = OBJECT_TYPE;
event->atomId = 0;
@@ -76,12 +103,12 @@
return event;
}
-void stats_event_release(struct stats_event* event) {
+void AStatsEvent_release(AStatsEvent* event) {
free(event->buf);
free(event);
}
-void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId) {
+void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId) {
event->atomId = atomId;
event->buf[POS_ATOM_ID] = INT32_TYPE;
memcpy(&event->buf[POS_ATOM_ID + sizeof(uint8_t)], &atomId, sizeof(atomId));
@@ -89,7 +116,7 @@
}
// Side-effect: modifies event->errors if the buffer would overflow
-static bool overflows(struct stats_event* event, size_t size) {
+static bool overflows(AStatsEvent* event, size_t size) {
if (event->size + size > MAX_EVENT_PAYLOAD) {
event->errors |= ERROR_OVERFLOW;
return true;
@@ -99,39 +126,39 @@
// Side-effect: all append functions increment event->size if there is
// sufficient space within the buffer to place the value
-static void append_byte(struct stats_event* event, uint8_t value) {
+static void append_byte(AStatsEvent* event, uint8_t value) {
if (!overflows(event, sizeof(value))) {
event->buf[event->size] = value;
event->size += sizeof(value);
}
}
-static void append_bool(struct stats_event* event, bool value) {
+static void append_bool(AStatsEvent* event, bool value) {
append_byte(event, (uint8_t)value);
}
-static void append_int32(struct stats_event* event, int32_t value) {
+static void append_int32(AStatsEvent* event, int32_t value) {
if (!overflows(event, sizeof(value))) {
memcpy(&event->buf[event->size], &value, sizeof(value));
event->size += sizeof(value);
}
}
-static void append_int64(struct stats_event* event, int64_t value) {
+static void append_int64(AStatsEvent* event, int64_t value) {
if (!overflows(event, sizeof(value))) {
memcpy(&event->buf[event->size], &value, sizeof(value));
event->size += sizeof(value);
}
}
-static void append_float(struct stats_event* event, float value) {
+static void append_float(AStatsEvent* event, float value) {
if (!overflows(event, sizeof(value))) {
memcpy(&event->buf[event->size], &value, sizeof(value));
event->size += sizeof(float);
}
}
-static void append_byte_array(struct stats_event* event, const uint8_t* buf, size_t size) {
+static void append_byte_array(AStatsEvent* event, const uint8_t* buf, size_t size) {
if (!overflows(event, size)) {
memcpy(&event->buf[event->size], buf, size);
event->size += size;
@@ -139,7 +166,7 @@
}
// Side-effect: modifies event->errors if buf is not properly null-terminated
-static void append_string(struct stats_event* event, const char* buf) {
+static void append_string(AStatsEvent* event, const char* buf) {
size_t size = strnlen(buf, MAX_EVENT_PAYLOAD);
if (size == MAX_EVENT_PAYLOAD) {
event->errors |= ERROR_STRING_NOT_NULL_TERMINATED;
@@ -150,41 +177,41 @@
append_byte_array(event, (uint8_t*)buf, size);
}
-static void start_field(struct stats_event* event, uint8_t typeId) {
+static void start_field(AStatsEvent* event, uint8_t typeId) {
event->lastFieldPos = event->size;
append_byte(event, typeId);
event->numElements++;
}
-void stats_event_write_int32(struct stats_event* event, int32_t value) {
+void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value) {
if (event->errors) return;
start_field(event, INT32_TYPE);
append_int32(event, value);
}
-void stats_event_write_int64(struct stats_event* event, int64_t value) {
+void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value) {
if (event->errors) return;
start_field(event, INT64_TYPE);
append_int64(event, value);
}
-void stats_event_write_float(struct stats_event* event, float value) {
+void AStatsEvent_writeFloat(AStatsEvent* event, float value) {
if (event->errors) return;
start_field(event, FLOAT_TYPE);
append_float(event, value);
}
-void stats_event_write_bool(struct stats_event* event, bool value) {
+void AStatsEvent_writeBool(AStatsEvent* event, bool value) {
if (event->errors) return;
start_field(event, BOOL_TYPE);
append_bool(event, value);
}
-void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes) {
+void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes) {
if (event->errors) return;
start_field(event, BYTE_ARRAY_TYPE);
@@ -193,7 +220,7 @@
}
// Value is assumed to be encoded using UTF8
-void stats_event_write_string8(struct stats_event* event, const char* value) {
+void AStatsEvent_writeString(AStatsEvent* event, const char* value) {
if (event->errors) return;
start_field(event, STRING_TYPE);
@@ -201,8 +228,8 @@
}
// Tags are assumed to be encoded using UTF8
-void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
- const char* const* tags, uint8_t numNodes) {
+void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
+ const char* const* tags, uint8_t numNodes) {
if (numNodes > MAX_BYTE_VALUE) event->errors |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
if (event->errors) return;
@@ -215,39 +242,8 @@
}
}
-void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
- uint8_t numPairs) {
- if (numPairs > MAX_BYTE_VALUE) event->errors |= ERROR_TOO_MANY_KEY_VALUE_PAIRS;
- if (event->errors) return;
-
- start_field(event, KEY_VALUE_PAIRS_TYPE);
- append_byte(event, numPairs);
-
- for (uint8_t i = 0; i < numPairs; i++) {
- append_int32(event, pairs[i].key);
- append_byte(event, pairs[i].valueType);
- switch (pairs[i].valueType) {
- case INT32_TYPE:
- append_int32(event, pairs[i].int32Value);
- break;
- case INT64_TYPE:
- append_int64(event, pairs[i].int64Value);
- break;
- case FLOAT_TYPE:
- append_float(event, pairs[i].floatValue);
- break;
- case STRING_TYPE:
- append_string(event, pairs[i].stringValue);
- break;
- default:
- event->errors |= ERROR_INVALID_VALUE_TYPE;
- return;
- }
- }
-}
-
// Side-effect: modifies event->errors if field has too many annotations
-static void increment_annotation_count(struct stats_event* event) {
+static void increment_annotation_count(AStatsEvent* event) {
uint8_t fieldType = event->buf[event->lastFieldPos] & 0x0F;
uint32_t oldAnnotationCount = (event->buf[event->lastFieldPos] & 0xF0) >> 4;
uint32_t newAnnotationCount = oldAnnotationCount + 1;
@@ -260,7 +256,7 @@
event->buf[event->lastFieldPos] = (((uint8_t)newAnnotationCount << 4) & 0xF0) | fieldType;
}
-void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value) {
+void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value) {
if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
if (event->errors) return;
@@ -271,8 +267,7 @@
increment_annotation_count(event);
}
-void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
- int32_t value) {
+void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value) {
if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
if (event->errors) return;
@@ -283,24 +278,24 @@
increment_annotation_count(event);
}
-uint32_t stats_event_get_atom_id(struct stats_event* event) {
+uint32_t AStatsEvent_getAtomId(AStatsEvent* event) {
return event->atomId;
}
-uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size) {
+uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size) {
if (size) *size = event->size;
return event->buf;
}
-uint32_t stats_event_get_errors(struct stats_event* event) {
+uint32_t AStatsEvent_getErrors(AStatsEvent* event) {
return event->errors;
}
-void stats_event_truncate_buffer(struct stats_event* event, bool truncate) {
+void AStatsEvent_truncateBuffer(AStatsEvent* event, bool truncate) {
event->truncate = truncate;
}
-void stats_event_build(struct stats_event* event) {
+void AStatsEvent_build(AStatsEvent* event) {
if (event->built) return;
if (event->atomId == 0) event->errors |= ERROR_NO_ATOM_ID;
@@ -327,28 +322,7 @@
event->built = true;
}
-int stats_event_write(struct stats_event* event) {
- stats_event_build(event);
+int AStatsEvent_write(AStatsEvent* event) {
+ AStatsEvent_build(event);
return write_buffer_to_statsd(&event->buf, event->size, event->atomId);
-}
-
-struct stats_event_api_table table = {
- stats_event_obtain,
- stats_event_build,
- stats_event_write,
- stats_event_release,
- stats_event_set_atom_id,
- stats_event_write_int32,
- stats_event_write_int64,
- stats_event_write_float,
- stats_event_write_bool,
- stats_event_write_byte_array,
- stats_event_write_string8,
- stats_event_write_attribution_chain,
- stats_event_write_key_value_pairs,
- stats_event_add_bool_annotation,
- stats_event_add_int32_annotation,
- stats_event_get_atom_id,
- stats_event_get_buffer,
- stats_event_get_errors,
-};
+}
\ No newline at end of file
diff --git a/libstats/socket/tests/stats_event_test.cpp b/libstats/socket/tests/stats_event_test.cpp
index cf0592c..48bf4b8 100644
--- a/libstats/socket/tests/stats_event_test.cpp
+++ b/libstats/socket/tests/stats_event_test.cpp
@@ -18,6 +18,34 @@
#include <gtest/gtest.h>
#include <utils/SystemClock.h>
+// Keep in sync stats_event.c. Consider moving to separate header file to avoid duplication.
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
using std::string;
using std::vector;
@@ -88,17 +116,17 @@
bool boolValue = false;
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_int32(event, int32Value);
- stats_event_write_int64(event, int64Value);
- stats_event_write_float(event, floatValue);
- stats_event_write_bool(event, boolValue);
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeInt32(event, int32Value);
+ AStatsEvent_writeInt64(event, int64Value);
+ AStatsEvent_writeFloat(event, floatValue);
+ AStatsEvent_writeBool(event, boolValue);
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/4, startTime, endTime, atomId);
@@ -120,8 +148,8 @@
checkScalar(&buffer, boolValue);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestStrings) {
@@ -129,14 +157,14 @@
string str = "test_string";
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_string8(event, str.c_str());
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeString(event, str.c_str());
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -145,8 +173,8 @@
checkString(&buffer, str);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestByteArrays) {
@@ -154,14 +182,14 @@
vector<uint8_t> message = {'b', 'y', 't', '\0', 'e', 's'};
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_byte_array(event, message.data(), message.size());
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeByteArray(event, message.data(), message.size());
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -170,8 +198,8 @@
checkByteArray(&buffer, message);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestAttributionChains) {
@@ -188,14 +216,14 @@
}
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_attribution_chain(event, uids, cTags, numNodes);
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeAttributionChain(event, uids, cTags, numNodes);
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -208,60 +236,8 @@
}
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
-}
-
-TEST(StatsEventTest, TestKeyValuePairs) {
- uint32_t atomId = 100;
-
- uint8_t numPairs = 4;
- struct key_value_pair pairs[numPairs];
- pairs[0] = {.key = 0, .valueType = INT32_TYPE, .int32Value = -1};
- pairs[1] = {.key = 1, .valueType = INT64_TYPE, .int64Value = 0x123456789};
- pairs[2] = {.key = 2, .valueType = FLOAT_TYPE, .floatValue = 5.5};
- string str = "test_key_value_pair_string";
- pairs[3] = {.key = 3, .valueType = STRING_TYPE, .stringValue = str.c_str()};
-
- int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_key_value_pairs(event, pairs, numPairs);
- stats_event_build(event);
- int64_t endTime = android::elapsedRealtimeNano();
-
- size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
- uint8_t* bufferEnd = buffer + bufferSize;
-
- checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
-
- checkTypeHeader(&buffer, KEY_VALUE_PAIRS_TYPE);
- checkScalar(&buffer, numPairs);
-
- // first pair
- checkScalar(&buffer, pairs[0].key);
- checkTypeHeader(&buffer, pairs[0].valueType);
- checkScalar(&buffer, pairs[0].int32Value);
-
- // second pair
- checkScalar(&buffer, pairs[1].key);
- checkTypeHeader(&buffer, pairs[1].valueType);
- checkScalar(&buffer, pairs[1].int64Value);
-
- // third pair
- checkScalar(&buffer, pairs[2].key);
- checkTypeHeader(&buffer, pairs[2].valueType);
- checkScalar(&buffer, pairs[2].floatValue);
-
- // fourth pair
- checkScalar(&buffer, pairs[3].key);
- checkTypeHeader(&buffer, pairs[3].valueType);
- checkString(&buffer, str);
-
- EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestAnnotations) {
@@ -282,19 +258,19 @@
bool floatAnnotation2Value = false;
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, 100);
- stats_event_write_bool(event, boolValue);
- stats_event_add_bool_annotation(event, boolAnnotation1Id, boolAnnotation1Value);
- stats_event_add_int32_annotation(event, boolAnnotation2Id, boolAnnotation2Value);
- stats_event_write_float(event, floatValue);
- stats_event_add_int32_annotation(event, floatAnnotation1Id, floatAnnotation1Value);
- stats_event_add_bool_annotation(event, floatAnnotation2Id, floatAnnotation2Value);
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, 100);
+ AStatsEvent_writeBool(event, boolValue);
+ AStatsEvent_addBoolAnnotation(event, boolAnnotation1Id, boolAnnotation1Value);
+ AStatsEvent_addInt32Annotation(event, boolAnnotation2Id, boolAnnotation2Value);
+ AStatsEvent_writeFloat(event, floatValue);
+ AStatsEvent_addInt32Annotation(event, floatAnnotation1Id, floatAnnotation1Value);
+ AStatsEvent_addBoolAnnotation(event, floatAnnotation2Id, floatAnnotation2Value);
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/2, startTime, endTime, atomId);
@@ -312,33 +288,33 @@
checkAnnotation(&buffer, floatAnnotation2Id, BOOL_TYPE, floatAnnotation2Value);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestNoAtomIdError) {
- struct stats_event* event = stats_event_obtain();
+ AStatsEvent* event = AStatsEvent_obtain();
// Don't set the atom id in order to trigger the error.
- stats_event_build(event);
+ AStatsEvent_build(event);
- uint32_t errors = stats_event_get_errors(event);
+ uint32_t errors = AStatsEvent_getErrors(event);
EXPECT_NE(errors | ERROR_NO_ATOM_ID, 0);
- stats_event_release(event);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestOverflowError) {
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, 100);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, 100);
// Add 1000 int32s to the event. Each int32 takes 5 bytes so this will
// overflow the 4068 byte buffer.
for (int i = 0; i < 1000; i++) {
- stats_event_write_int32(event, 0);
+ AStatsEvent_writeInt32(event, 0);
}
- stats_event_build(event);
+ AStatsEvent_build(event);
- uint32_t errors = stats_event_get_errors(event);
+ uint32_t errors = AStatsEvent_getErrors(event);
EXPECT_NE(errors | ERROR_OVERFLOW, 0);
- stats_event_release(event);
+ AStatsEvent_release(event);
}