summaryrefslogtreecommitdiff
path: root/cmds/statsd/src/stats_log_util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/statsd/src/stats_log_util.cpp')
-rw-r--r--cmds/statsd/src/stats_log_util.cpp346
1 files changed, 181 insertions, 165 deletions
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 6c6140081bd8..30eef4fef166 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -16,9 +16,13 @@
#include "stats_log_util.h"
+#include <logd/LogEvent.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Log.h>
#include <set>
#include <stack>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_BOOL;
@@ -38,12 +42,11 @@ const int DIMENSIONS_VALUE_FIELD = 1;
const int DIMENSIONS_VALUE_VALUE_STR = 2;
const int DIMENSIONS_VALUE_VALUE_INT = 3;
const int DIMENSIONS_VALUE_VALUE_LONG = 4;
-const int DIMENSIONS_VALUE_VALUE_BOOL = 5;
+// const int DIMENSIONS_VALUE_VALUE_BOOL = 5; // logd doesn't have bool data type.
const int DIMENSIONS_VALUE_VALUE_FLOAT = 6;
const int DIMENSIONS_VALUE_VALUE_TUPLE = 7;
-// for MessageValue Proto
-const int FIELD_ID_FIELD_VALUE_IN_MESSAGE_VALUE_PROTO = 1;
+const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
// for PulledAtomStats proto
const int FIELD_ID_PULLED_ATOM_STATS = 10;
@@ -51,186 +54,175 @@ const int FIELD_ID_PULL_ATOM_ID = 1;
const int FIELD_ID_TOTAL_PULL = 2;
const int FIELD_ID_TOTAL_PULL_FROM_CACHE = 3;
const int FIELD_ID_MIN_PULL_INTERVAL_SEC = 4;
+namespace {
-void writeDimensionsValueProtoToStream(const DimensionsValue& dimensionsValue,
- ProtoOutputStream* protoOutput) {
- if (!dimensionsValue.has_field()) {
- return;
- }
- protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, dimensionsValue.field());
- switch (dimensionsValue.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
- dimensionsValue.value_str());
- break;
- case DimensionsValue::ValueCase::kValueInt:
- protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
- dimensionsValue.value_int());
- break;
- case DimensionsValue::ValueCase::kValueLong:
- protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
- dimensionsValue.value_long());
- break;
- case DimensionsValue::ValueCase::kValueBool:
- protoOutput->write(FIELD_TYPE_BOOL | DIMENSIONS_VALUE_VALUE_BOOL,
- dimensionsValue.value_bool());
- break;
- case DimensionsValue::ValueCase::kValueFloat:
- protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
- dimensionsValue.value_float());
- break;
- case DimensionsValue::ValueCase::kValueTuple:
- {
- long long tupleToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
- for (int i = 0; i < dimensionsValue.value_tuple().dimensions_value_size(); ++i) {
- long long token = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED
- | FIELD_ID_FIELD_VALUE_IN_MESSAGE_VALUE_PROTO);
- writeDimensionsValueProtoToStream(
- dimensionsValue.value_tuple().dimensions_value(i), protoOutput);
- protoOutput->end(token);
- }
- protoOutput->end(tupleToken);
+void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
+ int prefix, ProtoOutputStream* protoOutput) {
+ size_t count = dims.size();
+ while (*index < count) {
+ const auto& dim = dims[*index];
+ const int valueDepth = dim.mField.getDepth();
+ const int valuePrefix = dim.mField.getPrefix(depth);
+ const int fieldNum = dim.mField.getPosAtDepth(depth);
+ if (valueDepth > 2) {
+ ALOGE("Depth > 2 not supported");
+ return;
+ }
+
+ if (depth == valueDepth && valuePrefix == prefix) {
+ long long token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ DIMENSIONS_VALUE_TUPLE_VALUE);
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
+ switch (dim.mValue.getType()) {
+ case INT:
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
+ dim.mValue.int_value);
+ break;
+ case LONG:
+ protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
+ (long long)dim.mValue.long_value);
+ break;
+ case FLOAT:
+ protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
+ dim.mValue.float_value);
+ break;
+ case STRING:
+ protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
+ dim.mValue.str_value);
+ break;
+ default:
+ break;
}
- break;
- default:
- break;
+ if (token != 0) {
+ protoOutput->end(token);
+ }
+ (*index)++;
+ } else if (valueDepth > depth && valuePrefix == prefix) {
+ // Writing the sub tree
+ long long dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
+ long long tupleToken =
+ protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
+ writeDimensionToProtoHelper(dims, index, valueDepth, dim.mField.getPrefix(valueDepth),
+ protoOutput);
+ protoOutput->end(tupleToken);
+ protoOutput->end(dimensionToken);
+ } else {
+ // Done with the prev sub tree
+ return;
+ }
}
}
-// for Field Proto
-const int FIELD_FIELD = 1;
-const int FIELD_POSITION_INDEX = 2;
-const int FIELD_CHILD = 3;
+} // namespace
-void writeFieldProtoToStream(
- const Field& field, util::ProtoOutputStream* protoOutput) {
- if (!field.has_field()) {
+void writeDimensionToProto(const HashableDimensionKey& dimension, ProtoOutputStream* protoOutput) {
+ if (dimension.getValues().size() == 0) {
return;
}
- protoOutput->write(FIELD_TYPE_INT32 | FIELD_FIELD, field.field());
- if (field.has_position_index()) {
- protoOutput->write(FIELD_TYPE_INT32 | FIELD_POSITION_INDEX, field.position_index());
- }
- for (int i = 0; i < field.child_size(); ++i) {
- long long childToken = protoOutput->start(
- FIELD_TYPE_MESSAGE| FIELD_COUNT_REPEATED | FIELD_CHILD);
- writeFieldProtoToStream(field.child(i), protoOutput);
- protoOutput->end(childToken);
- }
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
+ dimension.getValues()[0].mField.getTag());
+ long long topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
+ size_t index = 0;
+ writeDimensionToProtoHelper(dimension.getValues(), &index, 0, 0, protoOutput);
+ protoOutput->end(topToken);
}
-namespace {
-
-void addOrUpdateChildrenMap(
- const Field& root,
- const Field& node,
- std::map<Field, std::set<Field, FieldCmp>, FieldCmp> *childrenMap) {
- Field parentNode = root;
- if (node.has_position_index()) {
- appendLeaf(&parentNode, node.field(), node.position_index());
- } else {
- appendLeaf(&parentNode, node.field());
- }
- if (childrenMap->find(parentNode) == childrenMap->end()) {
- childrenMap->insert(std::make_pair(parentNode, std::set<Field, FieldCmp>{}));
- }
- auto it = childrenMap->find(parentNode);
- for (int i = 0; i < node.child_size(); ++i) {
- auto child = node.child(i);
- Field childNode = parentNode;
- if (child.has_position_index()) {
- appendLeaf(&childNode, child.field(), child.position_index());
- } else {
- appendLeaf(&childNode, child.field());
+// Supported Atoms format
+// XYZ_Atom {
+// repeated SubMsg field_1 = 1;
+// SubMsg2 field_2 = 2;
+// int32/float/string/int63 field_3 = 3;
+// }
+// logd's msg format, doesn't allow us to distinguish between the 2 cases below
+// Case (1):
+// Atom {
+// SubMsg {
+// int i = 1;
+// int j = 2;
+// }
+// repeated SubMsg
+// }
+//
+// and case (2):
+// Atom {
+// SubMsg {
+// repeated int i = 1;
+// repeated int j = 2;
+// }
+// optional SubMsg = 1;
+// }
+//
+//
+void writeFieldValueTreeToStreamHelper(const std::vector<FieldValue>& dims, size_t* index,
+ int depth, int prefix, ProtoOutputStream* protoOutput) {
+ size_t count = dims.size();
+ while (*index < count) {
+ const auto& dim = dims[*index];
+ const int valueDepth = dim.mField.getDepth();
+ const int valuePrefix = dim.mField.getPrefix(depth);
+ const int fieldNum = dim.mField.getPosAtDepth(depth);
+ if (valueDepth > 2) {
+ ALOGE("Depth > 2 not supported");
+ return;
}
- it->second.insert(childNode);
- addOrUpdateChildrenMap(parentNode, child, childrenMap);
- }
-}
-
-void addOrUpdateChildrenMap(
- const Field& field,
- std::map<Field, std::set<Field, FieldCmp>, FieldCmp> *childrenMap) {
- Field root;
- addOrUpdateChildrenMap(root, field, childrenMap);
-}
-
-} // namespace
-void writeFieldValueTreeToStream(const FieldValueMap &fieldValueMap,
- util::ProtoOutputStream* protoOutput) {
- std::map<Field, std::set<Field, FieldCmp>, FieldCmp> childrenMap;
- // Rebuild the field tree.
- for (auto it = fieldValueMap.begin(); it != fieldValueMap.end(); ++it) {
- addOrUpdateChildrenMap(it->first, &childrenMap);
- }
- std::stack<std::pair<long long, Field>> tokenStack;
- // Iterate over the node tree to fill the Atom proto.
- for (auto it = childrenMap.begin(); it != childrenMap.end(); ++it) {
- const Field* nodeLeaf = getSingleLeaf(&it->first);
- const int fieldNum = nodeLeaf->field();
- while (!tokenStack.empty()) {
- auto currentMsgNode = tokenStack.top().second;
- auto currentMsgNodeChildrenIt = childrenMap.find(currentMsgNode);
- if (currentMsgNodeChildrenIt->second.find(it->first) ==
- currentMsgNodeChildrenIt->second.end()) {
- protoOutput->end(tokenStack.top().first);
- tokenStack.pop();
- } else {
- break;
+ if (depth == valueDepth && valuePrefix == prefix) {
+ switch (dim.mValue.getType()) {
+ case INT:
+ protoOutput->write(FIELD_TYPE_INT32 | fieldNum, dim.mValue.int_value);
+ break;
+ case LONG:
+ protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
+ (long long)dim.mValue.long_value);
+ break;
+ case FLOAT:
+ protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value);
+ break;
+ case STRING:
+ protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
+ break;
}
- }
- if (it->second.size() == 0) {
- auto itValue = fieldValueMap.find(it->first);
- if (itValue != fieldValueMap.end()) {
- const DimensionsValue& value = itValue->second;
- switch (value.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- protoOutput->write(FIELD_TYPE_STRING | fieldNum,
- value.value_str());
- break;
- case DimensionsValue::ValueCase::kValueInt:
- protoOutput->write(FIELD_TYPE_INT32 | fieldNum,
- value.value_int());
- break;
- case DimensionsValue::ValueCase::kValueLong:
- protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
- value.value_long());
- break;
- case DimensionsValue::ValueCase::kValueBool:
- protoOutput->write(FIELD_TYPE_BOOL | fieldNum,
- value.value_bool());
- break;
- case DimensionsValue::ValueCase::kValueFloat:
- protoOutput->write(FIELD_TYPE_FLOAT | fieldNum,
- value.value_float());
- break;
- // This would not happen as the node has no child.
- case DimensionsValue::ValueCase::kValueTuple:
- break;
- default:
- break;
- }
- } else {
- ALOGE("Leaf node value not found. This should never happen.");
+ (*index)++;
+ } else if (valueDepth > depth && valuePrefix == prefix) {
+ // Writing the sub tree
+ long long msg_token = 0;
+ if (valueDepth == depth + 2) {
+ msg_token =
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
+ } else if (valueDepth == depth + 1) {
+ msg_token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
}
- } else {
- long long token;
- if (nodeLeaf->has_position_index()) {
- token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
- } else {
- token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
+ // Directly jump to the leaf value because the repeated position field is implied
+ // by the position of the sub msg in the parent field.
+ writeFieldValueTreeToStreamHelper(dims, index, valueDepth,
+ dim.mField.getPrefix(valueDepth), protoOutput);
+ if (msg_token != 0) {
+ protoOutput->end(msg_token);
}
- tokenStack.push(std::make_pair(token, it->first));
+ } else {
+ // Done with the prev sub tree
+ return;
}
}
+}
- while (!tokenStack.empty()) {
- protoOutput->end(tokenStack.top().first);
- tokenStack.pop();
+void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
+ util::ProtoOutputStream* protoOutput) {
+ long long atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId);
+
+ size_t index = 0;
+ writeFieldValueTreeToStreamHelper(values, &index, 0, 0, protoOutput);
+ protoOutput->end(atomToken);
+}
+
+int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
+ int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
+ if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL) {
+ bucketSizeMillis = 5 * 60 * 1000LL;
}
+ return bucketSizeMillis;
}
int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
@@ -274,6 +266,30 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>
protoOutput->end(token);
}
+int64_t getElapsedRealtimeNs() {
+ return ::android::elapsedRealtimeNano();
+}
+
+int64_t getElapsedRealtimeSec() {
+ return ::android::elapsedRealtimeNano() / NS_PER_SEC;
+}
+
+int64_t getElapsedRealtimeMillis() {
+ return ::android::elapsedRealtime();
+}
+
+int64_t getWallClockNs() {
+ return time(nullptr) * NS_PER_SEC;
+}
+
+int64_t getWallClockSec() {
+ return time(nullptr);
+}
+
+int64_t getWallClockMillis() {
+ return time(nullptr) * MS_PER_SEC;
+}
+
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android