Merge "Expose libstatspull as a stable C API"
This commit is contained in:
commit
f49c38beb5
|
@ -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",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
*;
|
||||
};
|
|
@ -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 @@ 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<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 @@ 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<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 @@ 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<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 @@ 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<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 @@ 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<std::mutex> lg(pullAtomMutex);
|
||||
// Always remove the puller from our map.
|
||||
|
|
|
@ -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<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 @@ void StatsEventCompat::writeKeyValuePairs(const map<int, int32_t>& int32Map,
|
|||
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<float>(const map<int, float
|
|||
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);
|
||||
|
|
|
@ -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 <class T>
|
||||
|
|
|
@ -45,7 +45,7 @@ cc_library {
|
|||
stubs: {
|
||||
symbol_file: "libstatssocket.map.txt",
|
||||
versions: [
|
||||
"1",
|
||||
"30",
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
*;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
|
@ -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 @@ 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<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 @@ 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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue