diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp index 72eb0e969..2171aa47f 100644 --- a/libstats/pull/Android.bp +++ b/libstats/pull/Android.bp @@ -32,7 +32,7 @@ cc_library_shared { ], export_include_dirs: ["include"], shared_libs: [ - //TODO: use libbinder_ndk. + //TODO: use libbinder_ndk. Remove libservices. "libbinder", "libstatssocket", "libservices", @@ -40,5 +40,12 @@ cc_library_shared { 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 b779ac98a..ad9b04edc 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 + #include #include #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 000000000..dc3fd8b04 --- /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 e8fc2ea32..9c497b8ea 100644 --- a/libstats/pull/stats_pull_atom_callback.cpp +++ b/libstats/pull/stats_pull_atom_callback.cpp @@ -28,12 +28,12 @@ #include -struct pulled_stats_event_list { - std::vector data; +struct AStatsEventList { + std::vector 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 @@ struct stats_event* add_stats_event_to_pull_data(pulled_stats_event_list* pull_d 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 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(); + 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 additiveFields) : mCallback(callback), @@ -55,15 +88,16 @@ class StatsPullAtomCallbackInternal : public android::os::BnPullAtomCallback { ::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 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 @@ class StatsPullAtomCallbackInternal : public android::os::BnPullAtomCallback { 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 @@ class StatsPullAtomCallbackInternal : public android::os::BnPullAtomCallback { const std::vector& 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 @@ void unregisterStatsPullAtomCallbackBlocking(int32_t atomTag) { 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 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 callbackBinder = new StatsPullAtomCallbackInternal( @@ -189,7 +224,7 @@ void register_stats_pull_atom_callback(int32_t atom_tag, stats_pull_atom_callbac registerThread.detach(); } -void unregister_stats_pull_atom_callback(int32_t atom_tag) { +void AStatsManager_unregisterPullAtomCallback(int32_t atom_tag) { { std::lock_guard lg(pullAtomMutex); // Always remove the puller from our map. diff --git a/libstats/push_compat/StatsEventCompat.cpp b/libstats/push_compat/StatsEventCompat.cpp index edfa070ed..de458b3e5 100644 --- a/libstats/push_compat/StatsEventCompat.cpp +++ b/libstats/push_compat/StatsEventCompat.cpp @@ -38,7 +38,7 @@ const bool StatsEventCompat::mPlatformAtLeastR = // 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 @@ StatsEventCompat::StatsEventCompat() : mEventQ(kStatsEventTag) { 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 @@ StatsEventCompat::StatsEventCompat() : mEventQ(kStatsEventTag) { } 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::setAtomId(int32_t atomId) { 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::writeInt32(int32_t value) { 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::writeInt64(int64_t value) { 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::writeFloat(float value) { 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::writeBool(bool value) { 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 @@ void StatsEventCompat::writeString(const char* value) { 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::writeString(const char* value) { void StatsEventCompat::writeAttributionChain(const int32_t* uids, size_t numUids, const vector& 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 @@ void StatsEventCompat::writeKeyValuePairs(const map& int32Map, const map& int64Map, const map& stringMap, const map& floatMap) { - if (mStatsEventApi) { - vector 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 map(const map&); 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 a8cde681c..ad423a1c9 100644 --- a/libstats/push_compat/include/StatsEventCompat.h +++ b/libstats/push_compat/include/StatsEventCompat.h @@ -57,10 +57,11 @@ class StatsEventCompat { 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 diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp index 8a43d854b..f36b214f5 100644 --- a/libstats/socket/Android.bp +++ b/libstats/socket/Android.bp @@ -45,7 +45,7 @@ cc_library { 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 9488168b5..3fc6e551f 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 struct stats_event* constructStatsEvent() { 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 @@ BENCHMARK(BM_stats_event_truncate_buffer); 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 080e957b2..6a2d9cd6e 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_() and add__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 55bfbda66..e2e7ae37e 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 15039c63d..5f77558cb 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 @@ static int64_t get_elapsed_realtime_ns() { 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 @@ struct stats_event* stats_event_obtain() { 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 @@ void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId) { } // 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 @@ static bool overflows(struct stats_event* event, size_t size) { // 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 @@ static void append_byte_array(struct stats_event* event, const uint8_t* buf, siz } // 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 @@ static void append_string(struct stats_event* event, const char* buf) { 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 @@ void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, } // 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 @@ void stats_event_write_string8(struct stats_event* event, const char* value) { } // 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_attribution_chain(struct stats_event* event, const uint32 } } -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 @@ static void increment_annotation_count(struct stats_event* event) { 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 @@ void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotati 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 @@ void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotat 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 @@ void stats_event_build(struct stats_event* event) { 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 cf0592c3a..48bf4b8e2 100644 --- a/libstats/socket/tests/stats_event_test.cpp +++ b/libstats/socket/tests/stats_event_test.cpp @@ -18,6 +18,34 @@ #include #include +// 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 @@ TEST(StatsEventTest, TestScalars) { 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 @@ TEST(StatsEventTest, TestScalars) { 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 @@ TEST(StatsEventTest, TestStrings) { 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 @@ TEST(StatsEventTest, TestStrings) { 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 @@ TEST(StatsEventTest, TestByteArrays) { vector 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 @@ TEST(StatsEventTest, TestByteArrays) { 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 @@ TEST(StatsEventTest, TestAttributionChains) { } 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 @@ TEST(StatsEventTest, TestAttributionChains) { } 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 @@ TEST(StatsEventTest, TestAnnotations) { 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 @@ TEST(StatsEventTest, TestAnnotations) { 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); }