Expose libstatspull as a stable C API

Libstatspull will ship as a part of the statsd apex in R.

Also update libstatssocket to have version 30 to align with api level,
as per native api council feedback.

Change both libraries to use NDK style naming conventions (AStatsEvent,
AStatsManager), and remove unneeded APIs in libstatssocket.

Remove KeyValuePairs from libstatssocket. KeyValuePairs will not be
supported in native code.

Bug: 147499386
Test: make libstatspull
Test: make libstatssocket
Test: atest libstatssocket_test
Change-Id: Ie79771461215a057529aaac91db95e4334c3960e
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index 9fd9fbc..d76a5e7 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -45,7 +45,7 @@
     stubs: {
         symbol_file: "libstatssocket.map.txt",
         versions: [
-            "1",
+            "30",
         ],
     }
 }
diff --git a/libstats/socket/benchmark/stats_event_benchmark.cpp b/libstats/socket/benchmark/stats_event_benchmark.cpp
index 9488168..3fc6e55 100644
--- a/libstats/socket/benchmark/stats_event_benchmark.cpp
+++ b/libstats/socket/benchmark/stats_event_benchmark.cpp
@@ -17,14 +17,14 @@
 #include "benchmark/benchmark.h"
 #include "stats_event.h"
 
-static struct stats_event* constructStatsEvent() {
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, 100);
+static AStatsEvent* constructStatsEvent() {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
 
     // randomly sample atom size
     int numElements = rand() % 800;
     for (int i = 0; i < numElements; i++) {
-        stats_event_write_int32(event, i);
+        AStatsEvent_writeInt32(event, i);
     }
 
     return event;
@@ -32,10 +32,10 @@
 
 static void BM_stats_event_truncate_buffer(benchmark::State& state) {
     while (state.KeepRunning()) {
-        struct stats_event* event = constructStatsEvent();
-        stats_event_build(event);
-        stats_event_write(event);
-        stats_event_release(event);
+        AStatsEvent* event = constructStatsEvent();
+        AStatsEvent_build(event);
+        AStatsEvent_write(event);
+        AStatsEvent_release(event);
     }
 }
 
@@ -43,11 +43,11 @@
 
 static void BM_stats_event_full_buffer(benchmark::State& state) {
     while (state.KeepRunning()) {
-        struct stats_event* event = constructStatsEvent();
-        stats_event_truncate_buffer(event, false);
-        stats_event_build(event);
-        stats_event_write(event);
-        stats_event_release(event);
+        AStatsEvent* event = constructStatsEvent();
+        AStatsEvent_truncateBuffer(event, false);
+        AStatsEvent_build(event);
+        AStatsEvent_write(event);
+        AStatsEvent_release(event);
     }
 }
 
diff --git a/libstats/socket/include/stats_event.h b/libstats/socket/include/stats_event.h
index 080e957..6a2d9cd 100644
--- a/libstats/socket/include/stats_event.h
+++ b/libstats/socket/include/stats_event.h
@@ -26,17 +26,17 @@
  * This code defines and encapsulates the socket protocol.
  *
  * Usage:
- *      struct stats_event* event = stats_event_obtain();
+ *      AStatsEvent* event = AStatsEvent_obtain();
  *
- *      stats_event_set_atom_id(event, atomId);
- *      stats_event_write_int32(event, 24);
- *      stats_event_add_bool_annotation(event, 1, true); // annotations apply to the previous field
- *      stats_event_add_int32_annotation(event, 2, 128);
- *      stats_event_write_float(event, 2.0);
+ *      AStatsEvent_setAtomId(event, atomId);
+ *      AStatsEvent_writeInt32(event, 24);
+ *      AStatsEvent_addBoolAnnotation(event, 1, true); // annotations apply to the previous field
+ *      AStatsEvent_addInt32Annotation(event, 2, 128);
+ *      AStatsEvent_writeFloat(event, 2.0);
  *
- *      stats_event_build(event);
- *      stats_event_write(event);
- *      stats_event_release(event);
+ *      AStatsEvent_build(event);
+ *      AStatsEvent_write(event);
+ *      AStatsEvent_release(event);
  *
  * Notes:
  *    (a) write_<type>() and add_<type>_annotation() should be called in the order that fields
@@ -47,115 +47,118 @@
  *    (e) All strings should be encoded using UTF8.
  */
 
-/* ERRORS */
-#define ERROR_NO_TIMESTAMP 0x1
-#define ERROR_NO_ATOM_ID 0x2
-#define ERROR_OVERFLOW 0x4
-#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
-#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
-#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
-#define ERROR_INVALID_ANNOTATION_ID 0x40
-#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
-#define ERROR_TOO_MANY_ANNOTATIONS 0x100
-#define ERROR_TOO_MANY_FIELDS 0x200
-#define ERROR_INVALID_VALUE_TYPE 0x400
-#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
-
-/* TYPE IDS */
-#define INT32_TYPE 0x00
-#define INT64_TYPE 0x01
-#define STRING_TYPE 0x02
-#define LIST_TYPE 0x03
-#define FLOAT_TYPE 0x04
-#define BOOL_TYPE 0x05
-#define BYTE_ARRAY_TYPE 0x06
-#define OBJECT_TYPE 0x07
-#define KEY_VALUE_PAIRS_TYPE 0x08
-#define ATTRIBUTION_CHAIN_TYPE 0x09
-#define ERROR_TYPE 0x0F
-
 #ifdef __cplusplus
 extern "C" {
 #endif  // __CPLUSPLUS
 
-struct stats_event;
-
-/* SYSTEM API */
-struct stats_event* stats_event_obtain();
-// The build function can be called multiple times without error. If the event
-// has been built before, this function is a no-op.
-void stats_event_build(struct stats_event* event);
-int stats_event_write(struct stats_event* event);
-void stats_event_release(struct stats_event* event);
-
-void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId);
-
-void stats_event_write_int32(struct stats_event* event, int32_t value);
-void stats_event_write_int64(struct stats_event* event, int64_t value);
-void stats_event_write_float(struct stats_event* event, float value);
-void stats_event_write_bool(struct stats_event* event, bool value);
-
-void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes);
-
-// Buf must be null-terminated.
-void stats_event_write_string8(struct stats_event* event, const char* value);
-
-// Tags must be null-terminated.
-void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
-                                         const char* const* tags, uint8_t numNodes);
-
-/* key_value_pair struct can be constructed as follows:
- *    struct key_value_pair pair = {.key = key, .valueType = STRING_TYPE,
- *                                  .stringValue = buf};
+/**
+ * Opaque struct use to represent a StatsEvent. It builds and stores the data that is sent to
+ * statsd.
  */
-struct key_value_pair {
-    int32_t key;
-    uint8_t valueType;  // expected to be INT32_TYPE, INT64_TYPE, FLOAT_TYPE, or STRING_TYPE
-    union {
-        int32_t int32Value;
-        int64_t int64Value;
-        float floatValue;
-        const char* stringValue;  // must be null terminated
-    };
-};
+struct AStatsEvent;
+typedef struct AStatsEvent AStatsEvent;
 
-void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
-                                       uint8_t numPairs);
+/**
+ * Returns a new AStatsEvent. If you call this function, you must call AStatsEvent_release to free
+ * the allocated memory.
+ */
+AStatsEvent* AStatsEvent_obtain();
 
-void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value);
-void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
-                                      int32_t value);
+/**
+ * Builds and finalizes the StatsEvent.
+ *
+ * After this function, the StatsEvent must not be modified in any way other than calling release or
+ * write. Build must be always be called before AStatsEvent_write.
+ *
+ * Build can be called multiple times without error.
+ * If the event has been built before, this function is a no-op.
+ */
+void AStatsEvent_build(AStatsEvent* event);
 
-uint32_t stats_event_get_atom_id(struct stats_event* event);
+/**
+ * Writes the StatsEvent to the stats log.
+ *
+ * After calling this, AStatsEvent_release must be called,
+ * and is the only function that can be safely called.
+ */
+int AStatsEvent_write(AStatsEvent* event);
+
+/**
+ * Frees the memory held by this StatsEvent
+ *
+ * After calling this, the StatsEvent must not be used or modified in any way.
+ */
+void AStatsEvent_release(AStatsEvent* event);
+
+/**
+ * Sets the atom id for this StatsEvent.
+ **/
+void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId);
+
+/**
+ * Writes an int32_t field to this StatsEvent.
+ **/
+void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value);
+
+/**
+ * Writes an int64_t field to this StatsEvent.
+ **/
+void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value);
+
+/**
+ * Writes a float field to this StatsEvent.
+ **/
+void AStatsEvent_writeFloat(AStatsEvent* event, float value);
+
+/**
+ * Write a bool field to this StatsEvent.
+ **/
+void AStatsEvent_writeBool(AStatsEvent* event, bool value);
+
+/**
+ * Write a byte array field to this StatsEvent.
+ **/
+void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes);
+
+/**
+ * Write a string field to this StatsEvent.
+ *
+ * The string must be null-terminated.
+ **/
+void AStatsEvent_writeString(AStatsEvent* event, const char* value);
+
+/**
+ * Write an attribution chain field to this StatsEvent.
+ *
+ * The sizes of uids and tags must be equal. The AttributionNode at position i is
+ * made up of uids[i] and tags[i].
+ *
+ * \param uids array of uids in the attribution chain.
+ * \param tags array of tags in the attribution chain. Each tag must be null-terminated.
+ * \param numNodes the number of AttributionNodes in the attribution chain. This is the length of
+ *                 the uids and the tags.
+ **/
+void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
+                                       const char* const* tags, uint8_t numNodes);
+
+/**
+ * Write a bool annotation for the previous field written.
+ **/
+void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value);
+
+/**
+ * Write an integer annotation for the previous field written.
+ **/
+void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value);
+
+// Internal/test APIs. Should not be exposed outside of the APEX.
+uint32_t AStatsEvent_getAtomId(AStatsEvent* event);
 // Size is an output parameter.
-uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size);
-uint32_t stats_event_get_errors(struct stats_event* event);
-
-// This table is used by StatsEventCompat to access the stats_event API.
-struct stats_event_api_table {
-    struct stats_event* (*obtain)(void);
-    void (*build)(struct stats_event*);
-    int (*write)(struct stats_event*);
-    void (*release)(struct stats_event*);
-    void (*set_atom_id)(struct stats_event*, uint32_t);
-    void (*write_int32)(struct stats_event*, int32_t);
-    void (*write_int64)(struct stats_event*, int64_t);
-    void (*write_float)(struct stats_event*, float);
-    void (*write_bool)(struct stats_event*, bool);
-    void (*write_byte_array)(struct stats_event*, const uint8_t*, size_t);
-    void (*write_string8)(struct stats_event*, const char*);
-    void (*write_attribution_chain)(struct stats_event*, const uint32_t*, const char* const*,
-                                    uint8_t);
-    void (*write_key_value_pairs)(struct stats_event*, struct key_value_pair*, uint8_t);
-    void (*add_bool_annotation)(struct stats_event*, uint8_t, bool);
-    void (*add_int32_annotation)(struct stats_event*, uint8_t, int32_t);
-    uint32_t (*get_atom_id)(struct stats_event*);
-    uint8_t* (*get_buffer)(struct stats_event*, size_t*);
-    uint32_t (*get_errors)(struct stats_event*);
-};
+uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size);
+uint32_t AStatsEvent_getErrors(AStatsEvent* event);
 
 // exposed for benchmarking only
-void stats_event_truncate_buffer(struct stats_event* event, bool truncate);
+void AStatsEvent_truncateBuffer(struct AStatsEvent* event, bool truncate);
 
 #ifdef __cplusplus
 }
diff --git a/libstats/socket/libstatssocket.map.txt b/libstats/socket/libstatssocket.map.txt
index 55bfbda..e2e7ae3 100644
--- a/libstats/socket/libstatssocket.map.txt
+++ b/libstats/socket/libstatssocket.map.txt
@@ -1,23 +1,19 @@
 LIBSTATSSOCKET {
     global:
-        stats_event_obtain; # apex # introduced=1
-        stats_event_build; # apex # introduced=1
-        stats_event_write; # apex # introduced=1
-        stats_event_release; # apex # introduced=1
-        stats_event_set_atom_id; # apex # introduced=1
-        stats_event_write_int32; # apex # introduced=1
-        stats_event_write_int64; # apex # introduced=1
-        stats_event_write_float; # apex # introduced=1
-        stats_event_write_bool; # apex # introduced=1
-        stats_event_write_byte_array; # apex # introduced=1
-        stats_event_write_string8; # apex # introduced=1
-        stats_event_write_attribution_chain; # apex # introduced=1
-        stats_event_write_key_value_pairs; # apex # introduced=1
-        stats_event_add_bool_annotation; # apex # introduced=1
-        stats_event_add_int32_annotation; # apex # introduced=1
-        stats_event_get_atom_id; # apex # introduced=1
-        stats_event_get_buffer; # apex # introduced=1
-        stats_event_get_errors; # apex # introduced=1
+        AStatsEvent_obtain; # apex # introduced=30
+        AStatsEvent_build; # apex # introduced=30
+        AStatsEvent_write; # apex # introduced=30
+        AStatsEvent_release; # apex # introduced=30
+        AStatsEvent_setAtomId; # apex # introduced=30
+        AStatsEvent_writeInt32; # apex # introduced=30
+        AStatsEvent_writeInt64; # apex # introduced=30
+        AStatsEvent_writeFloat; # apex # introduced=30
+        AStatsEvent_writeBool; # apex # introduced=30
+        AStatsEvent_writeByteArray; # apex # introduced=30
+        AStatsEvent_writeString; # apex # introduced=30
+        AStatsEvent_writeAttributionChain; # apex # introduced=30
+        AStatsEvent_addBoolAnnotation; # apex # introduced=30
+        AStatsEvent_addInt32Annotation; # apex # introduced=30
     local:
         *;
 };
diff --git a/libstats/socket/stats_event.c b/libstats/socket/stats_event.c
index 15039c6..5f77558 100644
--- a/libstats/socket/stats_event.c
+++ b/libstats/socket/stats_event.c
@@ -35,9 +35,36 @@
 #define MAX_ANNOTATION_COUNT 15
 #define MAX_BYTE_VALUE 127  // parsing side requires that lengths fit in 7 bits
 
-// The stats_event struct holds the serialized encoding of an event
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
+// The AStatsEvent struct holds the serialized encoding of an event
 // within a buf. Also includes other required fields.
-struct stats_event {
+struct AStatsEvent {
     uint8_t* buf;
     size_t lastFieldPos;  // location of last field within the buf
     size_t size;          // number of valid bytes within buffer
@@ -55,8 +82,8 @@
     return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;
 }
 
-struct stats_event* stats_event_obtain() {
-    struct stats_event* event = malloc(sizeof(struct stats_event));
+AStatsEvent* AStatsEvent_obtain() {
+    AStatsEvent* event = malloc(sizeof(AStatsEvent));
     event->buf = (uint8_t*)calloc(MAX_EVENT_PAYLOAD, 1);
     event->buf[0] = OBJECT_TYPE;
     event->atomId = 0;
@@ -76,12 +103,12 @@
     return event;
 }
 
-void stats_event_release(struct stats_event* event) {
+void AStatsEvent_release(AStatsEvent* event) {
     free(event->buf);
     free(event);
 }
 
-void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId) {
+void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId) {
     event->atomId = atomId;
     event->buf[POS_ATOM_ID] = INT32_TYPE;
     memcpy(&event->buf[POS_ATOM_ID + sizeof(uint8_t)], &atomId, sizeof(atomId));
@@ -89,7 +116,7 @@
 }
 
 // Side-effect: modifies event->errors if the buffer would overflow
-static bool overflows(struct stats_event* event, size_t size) {
+static bool overflows(AStatsEvent* event, size_t size) {
     if (event->size + size > MAX_EVENT_PAYLOAD) {
         event->errors |= ERROR_OVERFLOW;
         return true;
@@ -99,39 +126,39 @@
 
 // Side-effect: all append functions increment event->size if there is
 // sufficient space within the buffer to place the value
-static void append_byte(struct stats_event* event, uint8_t value) {
+static void append_byte(AStatsEvent* event, uint8_t value) {
     if (!overflows(event, sizeof(value))) {
         event->buf[event->size] = value;
         event->size += sizeof(value);
     }
 }
 
-static void append_bool(struct stats_event* event, bool value) {
+static void append_bool(AStatsEvent* event, bool value) {
     append_byte(event, (uint8_t)value);
 }
 
-static void append_int32(struct stats_event* event, int32_t value) {
+static void append_int32(AStatsEvent* event, int32_t value) {
     if (!overflows(event, sizeof(value))) {
         memcpy(&event->buf[event->size], &value, sizeof(value));
         event->size += sizeof(value);
     }
 }
 
-static void append_int64(struct stats_event* event, int64_t value) {
+static void append_int64(AStatsEvent* event, int64_t value) {
     if (!overflows(event, sizeof(value))) {
         memcpy(&event->buf[event->size], &value, sizeof(value));
         event->size += sizeof(value);
     }
 }
 
-static void append_float(struct stats_event* event, float value) {
+static void append_float(AStatsEvent* event, float value) {
     if (!overflows(event, sizeof(value))) {
         memcpy(&event->buf[event->size], &value, sizeof(value));
         event->size += sizeof(float);
     }
 }
 
-static void append_byte_array(struct stats_event* event, const uint8_t* buf, size_t size) {
+static void append_byte_array(AStatsEvent* event, const uint8_t* buf, size_t size) {
     if (!overflows(event, size)) {
         memcpy(&event->buf[event->size], buf, size);
         event->size += size;
@@ -139,7 +166,7 @@
 }
 
 // Side-effect: modifies event->errors if buf is not properly null-terminated
-static void append_string(struct stats_event* event, const char* buf) {
+static void append_string(AStatsEvent* event, const char* buf) {
     size_t size = strnlen(buf, MAX_EVENT_PAYLOAD);
     if (size == MAX_EVENT_PAYLOAD) {
         event->errors |= ERROR_STRING_NOT_NULL_TERMINATED;
@@ -150,41 +177,41 @@
     append_byte_array(event, (uint8_t*)buf, size);
 }
 
-static void start_field(struct stats_event* event, uint8_t typeId) {
+static void start_field(AStatsEvent* event, uint8_t typeId) {
     event->lastFieldPos = event->size;
     append_byte(event, typeId);
     event->numElements++;
 }
 
-void stats_event_write_int32(struct stats_event* event, int32_t value) {
+void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value) {
     if (event->errors) return;
 
     start_field(event, INT32_TYPE);
     append_int32(event, value);
 }
 
-void stats_event_write_int64(struct stats_event* event, int64_t value) {
+void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value) {
     if (event->errors) return;
 
     start_field(event, INT64_TYPE);
     append_int64(event, value);
 }
 
-void stats_event_write_float(struct stats_event* event, float value) {
+void AStatsEvent_writeFloat(AStatsEvent* event, float value) {
     if (event->errors) return;
 
     start_field(event, FLOAT_TYPE);
     append_float(event, value);
 }
 
-void stats_event_write_bool(struct stats_event* event, bool value) {
+void AStatsEvent_writeBool(AStatsEvent* event, bool value) {
     if (event->errors) return;
 
     start_field(event, BOOL_TYPE);
     append_bool(event, value);
 }
 
-void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes) {
+void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes) {
     if (event->errors) return;
 
     start_field(event, BYTE_ARRAY_TYPE);
@@ -193,7 +220,7 @@
 }
 
 // Value is assumed to be encoded using UTF8
-void stats_event_write_string8(struct stats_event* event, const char* value) {
+void AStatsEvent_writeString(AStatsEvent* event, const char* value) {
     if (event->errors) return;
 
     start_field(event, STRING_TYPE);
@@ -201,8 +228,8 @@
 }
 
 // Tags are assumed to be encoded using UTF8
-void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
-                                         const char* const* tags, uint8_t numNodes) {
+void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
+                                       const char* const* tags, uint8_t numNodes) {
     if (numNodes > MAX_BYTE_VALUE) event->errors |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
     if (event->errors) return;
 
@@ -215,39 +242,8 @@
     }
 }
 
-void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
-                                       uint8_t numPairs) {
-    if (numPairs > MAX_BYTE_VALUE) event->errors |= ERROR_TOO_MANY_KEY_VALUE_PAIRS;
-    if (event->errors) return;
-
-    start_field(event, KEY_VALUE_PAIRS_TYPE);
-    append_byte(event, numPairs);
-
-    for (uint8_t i = 0; i < numPairs; i++) {
-        append_int32(event, pairs[i].key);
-        append_byte(event, pairs[i].valueType);
-        switch (pairs[i].valueType) {
-            case INT32_TYPE:
-                append_int32(event, pairs[i].int32Value);
-                break;
-            case INT64_TYPE:
-                append_int64(event, pairs[i].int64Value);
-                break;
-            case FLOAT_TYPE:
-                append_float(event, pairs[i].floatValue);
-                break;
-            case STRING_TYPE:
-                append_string(event, pairs[i].stringValue);
-                break;
-            default:
-                event->errors |= ERROR_INVALID_VALUE_TYPE;
-                return;
-        }
-    }
-}
-
 // Side-effect: modifies event->errors if field has too many annotations
-static void increment_annotation_count(struct stats_event* event) {
+static void increment_annotation_count(AStatsEvent* event) {
     uint8_t fieldType = event->buf[event->lastFieldPos] & 0x0F;
     uint32_t oldAnnotationCount = (event->buf[event->lastFieldPos] & 0xF0) >> 4;
     uint32_t newAnnotationCount = oldAnnotationCount + 1;
@@ -260,7 +256,7 @@
     event->buf[event->lastFieldPos] = (((uint8_t)newAnnotationCount << 4) & 0xF0) | fieldType;
 }
 
-void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value) {
+void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value) {
     if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
     if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
     if (event->errors) return;
@@ -271,8 +267,7 @@
     increment_annotation_count(event);
 }
 
-void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
-                                      int32_t value) {
+void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value) {
     if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
     if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
     if (event->errors) return;
@@ -283,24 +278,24 @@
     increment_annotation_count(event);
 }
 
-uint32_t stats_event_get_atom_id(struct stats_event* event) {
+uint32_t AStatsEvent_getAtomId(AStatsEvent* event) {
     return event->atomId;
 }
 
-uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size) {
+uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size) {
     if (size) *size = event->size;
     return event->buf;
 }
 
-uint32_t stats_event_get_errors(struct stats_event* event) {
+uint32_t AStatsEvent_getErrors(AStatsEvent* event) {
     return event->errors;
 }
 
-void stats_event_truncate_buffer(struct stats_event* event, bool truncate) {
+void AStatsEvent_truncateBuffer(AStatsEvent* event, bool truncate) {
     event->truncate = truncate;
 }
 
-void stats_event_build(struct stats_event* event) {
+void AStatsEvent_build(AStatsEvent* event) {
     if (event->built) return;
 
     if (event->atomId == 0) event->errors |= ERROR_NO_ATOM_ID;
@@ -327,28 +322,7 @@
     event->built = true;
 }
 
-int stats_event_write(struct stats_event* event) {
-    stats_event_build(event);
+int AStatsEvent_write(AStatsEvent* event) {
+    AStatsEvent_build(event);
     return write_buffer_to_statsd(&event->buf, event->size, event->atomId);
-}
-
-struct stats_event_api_table table = {
-        stats_event_obtain,
-        stats_event_build,
-        stats_event_write,
-        stats_event_release,
-        stats_event_set_atom_id,
-        stats_event_write_int32,
-        stats_event_write_int64,
-        stats_event_write_float,
-        stats_event_write_bool,
-        stats_event_write_byte_array,
-        stats_event_write_string8,
-        stats_event_write_attribution_chain,
-        stats_event_write_key_value_pairs,
-        stats_event_add_bool_annotation,
-        stats_event_add_int32_annotation,
-        stats_event_get_atom_id,
-        stats_event_get_buffer,
-        stats_event_get_errors,
-};
+}
\ No newline at end of file
diff --git a/libstats/socket/tests/stats_event_test.cpp b/libstats/socket/tests/stats_event_test.cpp
index cf0592c..48bf4b8 100644
--- a/libstats/socket/tests/stats_event_test.cpp
+++ b/libstats/socket/tests/stats_event_test.cpp
@@ -18,6 +18,34 @@
 #include <gtest/gtest.h>
 #include <utils/SystemClock.h>
 
+// Keep in sync stats_event.c. Consider moving to separate header file to avoid duplication.
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
 using std::string;
 using std::vector;
 
@@ -88,17 +116,17 @@
     bool boolValue = false;
 
     int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, atomId);
-    stats_event_write_int32(event, int32Value);
-    stats_event_write_int64(event, int64Value);
-    stats_event_write_float(event, floatValue);
-    stats_event_write_bool(event, boolValue);
-    stats_event_build(event);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_writeInt32(event, int32Value);
+    AStatsEvent_writeInt64(event, int64Value);
+    AStatsEvent_writeFloat(event, floatValue);
+    AStatsEvent_writeBool(event, boolValue);
+    AStatsEvent_build(event);
     int64_t endTime = android::elapsedRealtimeNano();
 
     size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
     uint8_t* bufferEnd = buffer + bufferSize;
 
     checkMetadata(&buffer, /*numElements=*/4, startTime, endTime, atomId);
@@ -120,8 +148,8 @@
     checkScalar(&buffer, boolValue);
 
     EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
 
 TEST(StatsEventTest, TestStrings) {
@@ -129,14 +157,14 @@
     string str = "test_string";
 
     int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, atomId);
-    stats_event_write_string8(event, str.c_str());
-    stats_event_build(event);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_writeString(event, str.c_str());
+    AStatsEvent_build(event);
     int64_t endTime = android::elapsedRealtimeNano();
 
     size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
     uint8_t* bufferEnd = buffer + bufferSize;
 
     checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -145,8 +173,8 @@
     checkString(&buffer, str);
 
     EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
 
 TEST(StatsEventTest, TestByteArrays) {
@@ -154,14 +182,14 @@
     vector<uint8_t> message = {'b', 'y', 't', '\0', 'e', 's'};
 
     int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, atomId);
-    stats_event_write_byte_array(event, message.data(), message.size());
-    stats_event_build(event);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_writeByteArray(event, message.data(), message.size());
+    AStatsEvent_build(event);
     int64_t endTime = android::elapsedRealtimeNano();
 
     size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
     uint8_t* bufferEnd = buffer + bufferSize;
 
     checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -170,8 +198,8 @@
     checkByteArray(&buffer, message);
 
     EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
 
 TEST(StatsEventTest, TestAttributionChains) {
@@ -188,14 +216,14 @@
     }
 
     int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, atomId);
-    stats_event_write_attribution_chain(event, uids, cTags, numNodes);
-    stats_event_build(event);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_writeAttributionChain(event, uids, cTags, numNodes);
+    AStatsEvent_build(event);
     int64_t endTime = android::elapsedRealtimeNano();
 
     size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
     uint8_t* bufferEnd = buffer + bufferSize;
 
     checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -208,60 +236,8 @@
     }
 
     EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
-}
-
-TEST(StatsEventTest, TestKeyValuePairs) {
-    uint32_t atomId = 100;
-
-    uint8_t numPairs = 4;
-    struct key_value_pair pairs[numPairs];
-    pairs[0] = {.key = 0, .valueType = INT32_TYPE, .int32Value = -1};
-    pairs[1] = {.key = 1, .valueType = INT64_TYPE, .int64Value = 0x123456789};
-    pairs[2] = {.key = 2, .valueType = FLOAT_TYPE, .floatValue = 5.5};
-    string str = "test_key_value_pair_string";
-    pairs[3] = {.key = 3, .valueType = STRING_TYPE, .stringValue = str.c_str()};
-
-    int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, atomId);
-    stats_event_write_key_value_pairs(event, pairs, numPairs);
-    stats_event_build(event);
-    int64_t endTime = android::elapsedRealtimeNano();
-
-    size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
-    uint8_t* bufferEnd = buffer + bufferSize;
-
-    checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
-
-    checkTypeHeader(&buffer, KEY_VALUE_PAIRS_TYPE);
-    checkScalar(&buffer, numPairs);
-
-    // first pair
-    checkScalar(&buffer, pairs[0].key);
-    checkTypeHeader(&buffer, pairs[0].valueType);
-    checkScalar(&buffer, pairs[0].int32Value);
-
-    // second pair
-    checkScalar(&buffer, pairs[1].key);
-    checkTypeHeader(&buffer, pairs[1].valueType);
-    checkScalar(&buffer, pairs[1].int64Value);
-
-    // third pair
-    checkScalar(&buffer, pairs[2].key);
-    checkTypeHeader(&buffer, pairs[2].valueType);
-    checkScalar(&buffer, pairs[2].floatValue);
-
-    // fourth pair
-    checkScalar(&buffer, pairs[3].key);
-    checkTypeHeader(&buffer, pairs[3].valueType);
-    checkString(&buffer, str);
-
-    EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
 
 TEST(StatsEventTest, TestAnnotations) {
@@ -282,19 +258,19 @@
     bool floatAnnotation2Value = false;
 
     int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, 100);
-    stats_event_write_bool(event, boolValue);
-    stats_event_add_bool_annotation(event, boolAnnotation1Id, boolAnnotation1Value);
-    stats_event_add_int32_annotation(event, boolAnnotation2Id, boolAnnotation2Value);
-    stats_event_write_float(event, floatValue);
-    stats_event_add_int32_annotation(event, floatAnnotation1Id, floatAnnotation1Value);
-    stats_event_add_bool_annotation(event, floatAnnotation2Id, floatAnnotation2Value);
-    stats_event_build(event);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+    AStatsEvent_writeBool(event, boolValue);
+    AStatsEvent_addBoolAnnotation(event, boolAnnotation1Id, boolAnnotation1Value);
+    AStatsEvent_addInt32Annotation(event, boolAnnotation2Id, boolAnnotation2Value);
+    AStatsEvent_writeFloat(event, floatValue);
+    AStatsEvent_addInt32Annotation(event, floatAnnotation1Id, floatAnnotation1Value);
+    AStatsEvent_addBoolAnnotation(event, floatAnnotation2Id, floatAnnotation2Value);
+    AStatsEvent_build(event);
     int64_t endTime = android::elapsedRealtimeNano();
 
     size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
     uint8_t* bufferEnd = buffer + bufferSize;
 
     checkMetadata(&buffer, /*numElements=*/2, startTime, endTime, atomId);
@@ -312,33 +288,33 @@
     checkAnnotation(&buffer, floatAnnotation2Id, BOOL_TYPE, floatAnnotation2Value);
 
     EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
 
 TEST(StatsEventTest, TestNoAtomIdError) {
-    struct stats_event* event = stats_event_obtain();
+    AStatsEvent* event = AStatsEvent_obtain();
     // Don't set the atom id in order to trigger the error.
-    stats_event_build(event);
+    AStatsEvent_build(event);
 
-    uint32_t errors = stats_event_get_errors(event);
+    uint32_t errors = AStatsEvent_getErrors(event);
     EXPECT_NE(errors | ERROR_NO_ATOM_ID, 0);
 
-    stats_event_release(event);
+    AStatsEvent_release(event);
 }
 
 TEST(StatsEventTest, TestOverflowError) {
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, 100);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
     // Add 1000 int32s to the event. Each int32 takes 5 bytes so this will
     // overflow the 4068 byte buffer.
     for (int i = 0; i < 1000; i++) {
-        stats_event_write_int32(event, 0);
+        AStatsEvent_writeInt32(event, 0);
     }
-    stats_event_build(event);
+    AStatsEvent_build(event);
 
-    uint32_t errors = stats_event_get_errors(event);
+    uint32_t errors = AStatsEvent_getErrors(event);
     EXPECT_NE(errors | ERROR_OVERFLOW, 0);
 
-    stats_event_release(event);
+    AStatsEvent_release(event);
 }