Create log event from key value maps.
BUG: b/112816333
Test: statsd test.
Change-Id: Ib66f06186abfacd77807436379e1e142a5b87c99
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d7a926f..6065bbf 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -127,6 +127,7 @@
WTFOccurred wtf_occurred = 80;
LowMemReported low_mem_reported = 81;
GenericAtom generic_atom = 82;
+ KeyValuePairsAtom key_value_pairs_atom = 83;
}
// Pulled events will start at field 10000.
@@ -177,6 +178,20 @@
optional string tag = 2;
}
+message KeyValuePair {
+ optional int32 key = 1;
+ oneof value {
+ int64 value_int = 2;
+ string value_str = 3;
+ float value_float = 4;
+ }
+}
+
+message KeyValuePairsAtom {
+ optional int32 uid = 1;
+ repeated KeyValuePair pairs = 2;
+}
+
/*
* *****************************************************************************
* Below are all of the individual atoms that are logged by Android via statsd.
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 04d34f3..73e6572 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -18,6 +18,7 @@
#include "logd/LogEvent.h"
#include "stats_log_util.h"
+#include "statslog.h"
namespace android {
namespace os {
@@ -51,6 +52,52 @@
}
}
+LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ int32_t uid,
+ const std::map<int32_t, int64_t>& int_map,
+ const std::map<int32_t, std::string>& string_map,
+ const std::map<int32_t, float>& float_map) {
+ mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
+ mTagId = android::util::KEY_VALUE_PAIRS_ATOM;
+ mLogUid = uid;
+
+ int pos[] = {1, 1, 1};
+
+ mValues.push_back(FieldValue(Field(mTagId, pos, 0 /* depth */), Value(uid)));
+ pos[0]++;
+ for (const auto&itr : int_map) {
+ pos[2] = 1;
+ mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));
+ pos[2] = 2;
+ mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.second)));
+ mValues.back().mField.decorateLastPos(2);
+ pos[1]++;
+ }
+
+ for (const auto&itr : string_map) {
+ pos[2] = 1;
+ mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));
+ pos[2] = 3;
+ mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.second)));
+ mValues.back().mField.decorateLastPos(2);
+ pos[1]++;
+ }
+
+ for (const auto&itr : float_map) {
+ pos[2] = 1;
+ mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));
+ pos[2] = 4;
+ mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.second)));
+ mValues.back().mField.decorateLastPos(2);
+ pos[1]++;
+ }
+ if (!mValues.empty()) {
+ mValues.back().mField.decorateLastPos(1);
+ mValues.at(mValues.size() - 2).mField.decorateLastPos(1);
+ }
+}
+
LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) {
mLogdTimestampNs = timestampNs;
mTagId = tagId;
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 24d624d..9ed09dd 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -69,6 +69,15 @@
// For testing. The timestamp is used as both elapsed real time and logd timestamp.
explicit LogEvent(int32_t tagId, int64_t timestampNs);
+ /**
+ * Constructs a KeyValuePairsAtom LogEvent from value maps.
+ */
+ explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ int32_t uid,
+ const std::map<int32_t, int64_t>& int_map,
+ const std::map<int32_t, std::string>& string_map,
+ const std::map<int32_t, float>& float_map);
+
~LogEvent();
/**
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 2fcde29..acfa151 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -158,6 +158,96 @@
EXPECT_EQ((float)1.1, item7.mValue.float_value);
}
+TEST(LogEventTest, TestKeyValuePairsAtomParsing) {
+ std::map<int32_t, int64_t> int_map;
+ std::map<int32_t, std::string> string_map;
+ std::map<int32_t, float> float_map;
+
+ int_map[11] = 123L;
+ int_map[22] = 345L;
+
+ string_map[1] = "test2";
+ string_map[2] = "test1";
+
+ float_map[111] = 2.2f;
+ float_map[222] = 1.1f;
+
+ LogEvent event1(83, 2000, 2001, 10001, int_map, string_map, float_map);
+ event1.init();
+
+ EXPECT_EQ(83, event1.GetTagId());
+ EXPECT_EQ((int64_t)2000, event1.GetLogdTimestampNs());
+ EXPECT_EQ((int64_t)2001, event1.GetElapsedTimestampNs());
+
+ const auto& items = event1.getValues();
+ EXPECT_EQ((size_t)13, items.size());
+
+ const FieldValue& item0 = event1.getValues()[0];
+ EXPECT_EQ(0x00010000, item0.mField.getField());
+ EXPECT_EQ(Type::INT, item0.mValue.getType());
+ EXPECT_EQ(10001, item0.mValue.int_value);
+
+ const FieldValue& item1 = event1.getValues()[1];
+ EXPECT_EQ(0x2020101, item1.mField.getField());
+ EXPECT_EQ(Type::INT, item1.mValue.getType());
+ EXPECT_EQ(11, item1.mValue.int_value);
+
+ const FieldValue& item2 = event1.getValues()[2];
+ EXPECT_EQ(0x2020182, item2.mField.getField());
+ EXPECT_EQ(Type::LONG, item2.mValue.getType());
+ EXPECT_EQ(123L, item2.mValue.long_value);
+
+ const FieldValue& item3 = event1.getValues()[3];
+ EXPECT_EQ(0x2020201, item3.mField.getField());
+ EXPECT_EQ(Type::INT, item3.mValue.getType());
+ EXPECT_EQ(22, item3.mValue.int_value);
+
+ const FieldValue& item4 = event1.getValues()[4];
+ EXPECT_EQ(0x2020282, item4.mField.getField());
+ EXPECT_EQ(Type::LONG, item4.mValue.getType());
+ EXPECT_EQ(345L, item4.mValue.long_value);
+
+ const FieldValue& item5 = event1.getValues()[5];
+ EXPECT_EQ(0x2020301, item5.mField.getField());
+ EXPECT_EQ(Type::INT, item5.mValue.getType());
+ EXPECT_EQ(1, item5.mValue.int_value);
+
+ const FieldValue& item6 = event1.getValues()[6];
+ EXPECT_EQ(0x2020383, item6.mField.getField());
+ EXPECT_EQ(Type::STRING, item6.mValue.getType());
+ EXPECT_EQ("test2", item6.mValue.str_value);
+
+ const FieldValue& item7 = event1.getValues()[7];
+ EXPECT_EQ(0x2020401, item7.mField.getField());
+ EXPECT_EQ(Type::INT, item7.mValue.getType());
+ EXPECT_EQ(2, item7.mValue.int_value);
+
+ const FieldValue& item8 = event1.getValues()[8];
+ EXPECT_EQ(0x2020483, item8.mField.getField());
+ EXPECT_EQ(Type::STRING, item8.mValue.getType());
+ EXPECT_EQ("test1", item8.mValue.str_value);
+
+ const FieldValue& item9 = event1.getValues()[9];
+ EXPECT_EQ(0x2020501, item9.mField.getField());
+ EXPECT_EQ(Type::INT, item9.mValue.getType());
+ EXPECT_EQ(111, item9.mValue.int_value);
+
+ const FieldValue& item10 = event1.getValues()[10];
+ EXPECT_EQ(0x2020584, item10.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item10.mValue.getType());
+ EXPECT_EQ(2.2f, item10.mValue.float_value);
+
+ const FieldValue& item11 = event1.getValues()[11];
+ EXPECT_EQ(0x2028601, item11.mField.getField());
+ EXPECT_EQ(Type::INT, item11.mValue.getType());
+ EXPECT_EQ(222, item11.mValue.int_value);
+
+ const FieldValue& item12 = event1.getValues()[12];
+ EXPECT_EQ(0x2028684, item12.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item12.mValue.getType());
+ EXPECT_EQ(1.1f, item12.mValue.float_value);
+}
+
} // namespace statsd
} // namespace os
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index ebdcdfd..40ee490 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -116,6 +116,9 @@
if (field->message_type()->full_name() ==
"android.os.statsd.AttributionNode") {
return JAVA_TYPE_ATTRIBUTION_CHAIN;
+ } else if (field->message_type()->full_name() ==
+ "android.os.statsd.KeyValuePair") {
+ return JAVA_TYPE_KEY_VALUE_PAIR;
} else {
return JAVA_TYPE_OBJECT;
}
@@ -181,6 +184,16 @@
expectedNumber++;
}
+ // Skips the key value pair atom.
+ for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
+ it != fields.end(); it++) {
+ const FieldDescriptor *field = it->second;
+ java_type_t javaType = java_type(field);
+ if (javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
+ return 0;
+ }
+ }
+
// Check that only allowed types are present. Remove any invalid ones.
for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
it != fields.end(); it++) {
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 5d2c302..ccdd145 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -48,6 +48,7 @@
JAVA_TYPE_DOUBLE = 6,
JAVA_TYPE_STRING = 7,
JAVA_TYPE_ENUM = 8,
+ JAVA_TYPE_KEY_VALUE_PAIR = 9,
JAVA_TYPE_OBJECT = -1,
JAVA_TYPE_BYTE_ARRAY = -2,