blob: a41f30c2bece0cadd72eeea100b14f1f18b749c6 [file] [log] [blame]
Yangster-mac20877162017-12-22 17:19:39 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "stats_log_util.h"
18
19#include <set>
20#include <stack>
21#include <utils/Log.h>
22
23using android::util::FIELD_COUNT_REPEATED;
24using android::util::FIELD_TYPE_BOOL;
25using android::util::FIELD_TYPE_FLOAT;
26using android::util::FIELD_TYPE_INT32;
27using android::util::FIELD_TYPE_INT64;
28using android::util::FIELD_TYPE_MESSAGE;
29using android::util::FIELD_TYPE_STRING;
30using android::util::ProtoOutputStream;
31
32namespace android {
33namespace os {
34namespace statsd {
35
36// for DimensionsValue Proto
37const int DIMENSIONS_VALUE_FIELD = 1;
38const int DIMENSIONS_VALUE_VALUE_STR = 2;
39const int DIMENSIONS_VALUE_VALUE_INT = 3;
40const int DIMENSIONS_VALUE_VALUE_LONG = 4;
41const int DIMENSIONS_VALUE_VALUE_BOOL = 5;
42const int DIMENSIONS_VALUE_VALUE_FLOAT = 6;
43const int DIMENSIONS_VALUE_VALUE_TUPLE = 7;
44
45// for MessageValue Proto
46const int FIELD_ID_FIELD_VALUE_IN_MESSAGE_VALUE_PROTO = 1;
47
Chenjie Yub038b702017-12-18 15:15:34 -080048// for PulledAtomStats proto
49const int FIELD_ID_PULLED_ATOM_STATS = 10;
50const int FIELD_ID_PULL_ATOM_ID = 1;
51const int FIELD_ID_TOTAL_PULL = 2;
52const int FIELD_ID_TOTAL_PULL_FROM_CACHE = 3;
53const int FIELD_ID_MIN_PULL_INTERVAL_SEC = 4;
54
Yangster-mac20877162017-12-22 17:19:39 -080055void writeDimensionsValueProtoToStream(const DimensionsValue& dimensionsValue,
56 ProtoOutputStream* protoOutput) {
57 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, dimensionsValue.field());
58 switch (dimensionsValue.value_case()) {
59 case DimensionsValue::ValueCase::kValueStr:
60 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
61 dimensionsValue.value_str());
62 break;
63 case DimensionsValue::ValueCase::kValueInt:
64 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
65 dimensionsValue.value_int());
66 break;
67 case DimensionsValue::ValueCase::kValueLong:
68 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
69 dimensionsValue.value_long());
70 break;
71 case DimensionsValue::ValueCase::kValueBool:
72 protoOutput->write(FIELD_TYPE_BOOL | DIMENSIONS_VALUE_VALUE_BOOL,
73 dimensionsValue.value_bool());
74 break;
75 case DimensionsValue::ValueCase::kValueFloat:
76 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
77 dimensionsValue.value_float());
78 break;
79 case DimensionsValue::ValueCase::kValueTuple:
80 {
81 long long tupleToken = protoOutput->start(
82 FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
83 for (int i = 0; i < dimensionsValue.value_tuple().dimensions_value_size(); ++i) {
84 long long token = protoOutput->start(
85 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED
86 | FIELD_ID_FIELD_VALUE_IN_MESSAGE_VALUE_PROTO);
87 writeDimensionsValueProtoToStream(
88 dimensionsValue.value_tuple().dimensions_value(i), protoOutput);
89 protoOutput->end(token);
90 }
91 protoOutput->end(tupleToken);
92 }
93 break;
94 default:
95 break;
96 }
97}
98
99// for Field Proto
100const int FIELD_FIELD = 1;
101const int FIELD_POSITION_INDEX = 2;
102const int FIELD_CHILD = 3;
103
104void writeFieldProtoToStream(
105 const Field& field, util::ProtoOutputStream* protoOutput) {
106 protoOutput->write(FIELD_TYPE_INT32 | FIELD_FIELD, field.field());
107 if (field.has_position_index()) {
108 protoOutput->write(FIELD_TYPE_INT32 | FIELD_POSITION_INDEX, field.position_index());
109 }
110 for (int i = 0; i < field.child_size(); ++i) {
111 long long childToken = protoOutput->start(
112 FIELD_TYPE_MESSAGE| FIELD_COUNT_REPEATED | FIELD_CHILD);
113 writeFieldProtoToStream(field.child(i), protoOutput);
114 protoOutput->end(childToken);
115 }
116}
117
118namespace {
119
120void addOrUpdateChildrenMap(
121 const Field& root,
122 const Field& node,
123 std::map<Field, std::set<Field, FieldCmp>, FieldCmp> *childrenMap) {
124 Field parentNode = root;
125 if (node.has_position_index()) {
126 appendLeaf(&parentNode, node.field(), node.position_index());
127 } else {
128 appendLeaf(&parentNode, node.field());
129 }
130 if (childrenMap->find(parentNode) == childrenMap->end()) {
131 childrenMap->insert(std::make_pair(parentNode, std::set<Field, FieldCmp>{}));
132 }
133 auto it = childrenMap->find(parentNode);
134 for (int i = 0; i < node.child_size(); ++i) {
135 auto child = node.child(i);
136 Field childNode = parentNode;
137 if (child.has_position_index()) {
138 appendLeaf(&childNode, child.field(), child.position_index());
139 } else {
140 appendLeaf(&childNode, child.field());
141 }
142 it->second.insert(childNode);
143 addOrUpdateChildrenMap(parentNode, child, childrenMap);
144 }
145}
146
147void addOrUpdateChildrenMap(
148 const Field& field,
149 std::map<Field, std::set<Field, FieldCmp>, FieldCmp> *childrenMap) {
150 Field root;
151 addOrUpdateChildrenMap(root, field, childrenMap);
152}
153
154} // namespace
155
156void writeFieldValueTreeToStream(const FieldValueMap &fieldValueMap,
157 util::ProtoOutputStream* protoOutput) {
158 std::map<Field, std::set<Field, FieldCmp>, FieldCmp> childrenMap;
159 // Rebuild the field tree.
160 for (auto it = fieldValueMap.begin(); it != fieldValueMap.end(); ++it) {
161 addOrUpdateChildrenMap(it->first, &childrenMap);
162 }
163 std::stack<std::pair<long long, Field>> tokenStack;
164 // Iterate over the node tree to fill the Atom proto.
165 for (auto it = childrenMap.begin(); it != childrenMap.end(); ++it) {
166 const Field* nodeLeaf = getSingleLeaf(&it->first);
167 const int fieldNum = nodeLeaf->field();
168 while (!tokenStack.empty()) {
169 auto currentMsgNode = tokenStack.top().second;
170 auto currentMsgNodeChildrenIt = childrenMap.find(currentMsgNode);
171 if (currentMsgNodeChildrenIt->second.find(it->first) ==
172 currentMsgNodeChildrenIt->second.end()) {
173 protoOutput->end(tokenStack.top().first);
174 tokenStack.pop();
175 } else {
176 break;
177 }
178 }
179 if (it->second.size() == 0) {
180 auto itValue = fieldValueMap.find(it->first);
181 if (itValue != fieldValueMap.end()) {
182 const DimensionsValue& value = itValue->second;
183 switch (value.value_case()) {
184 case DimensionsValue::ValueCase::kValueStr:
185 protoOutput->write(FIELD_TYPE_STRING | fieldNum,
186 value.value_str());
187 break;
188 case DimensionsValue::ValueCase::kValueInt:
189 protoOutput->write(FIELD_TYPE_INT32 | fieldNum,
190 value.value_int());
191 break;
192 case DimensionsValue::ValueCase::kValueLong:
193 protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
194 value.value_long());
195 break;
196 case DimensionsValue::ValueCase::kValueBool:
197 protoOutput->write(FIELD_TYPE_BOOL | fieldNum,
198 value.value_bool());
199 break;
200 case DimensionsValue::ValueCase::kValueFloat:
201 protoOutput->write(FIELD_TYPE_FLOAT | fieldNum,
202 value.value_float());
203 break;
204 // This would not happen as the node has no child.
205 case DimensionsValue::ValueCase::kValueTuple:
206 break;
207 default:
208 break;
209 }
210 } else {
211 ALOGE("Leaf node value not found. This should never happen.");
212 }
213 } else {
214 long long token;
215 if (nodeLeaf->has_position_index()) {
216 token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
217 } else {
218 token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
219 }
220 tokenStack.push(std::make_pair(token, it->first));
221 }
222 }
223
224 while (!tokenStack.empty()) {
225 protoOutput->end(tokenStack.top().first);
226 tokenStack.pop();
227 }
Yangster-macb8144812018-01-04 10:56:23 -0800228}
Yangster-mac20877162017-12-22 17:19:39 -0800229
Yangster-macb8144812018-01-04 10:56:23 -0800230int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
231 switch (unit) {
232 case ONE_MINUTE:
233 return 60 * 1000LL;
234 case FIVE_MINUTES:
235 return 5 * 60 * 1000LL;
236 case TEN_MINUTES:
237 return 10 * 60 * 1000LL;
238 case THIRTY_MINUTES:
239 return 30 * 60 * 1000LL;
240 case ONE_HOUR:
241 return 60 * 60 * 1000LL;
242 case THREE_HOURS:
243 return 3 * 60 * 60 * 1000LL;
244 case SIX_HOURS:
245 return 6 * 60 * 60 * 1000LL;
246 case TWELVE_HOURS:
247 return 12 * 60 * 60 * 1000LL;
248 case ONE_DAY:
249 return 24 * 60 * 60 * 1000LL;
250 case CTS:
251 return 1000;
252 case TIME_UNIT_UNSPECIFIED:
253 default:
254 return -1;
255 }
Yangster-mac20877162017-12-22 17:19:39 -0800256}
257
Chenjie Yub038b702017-12-18 15:15:34 -0800258void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
259 util::ProtoOutputStream* protoOutput) {
260 long long token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_PULLED_ATOM_STATS |
261 FIELD_COUNT_REPEATED);
262 protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_PULL_ATOM_ID, (int32_t)pair.first);
263 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL, (long long)pair.second.totalPull);
264 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL_FROM_CACHE,
265 (long long)pair.second.totalPullFromCache);
266 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_PULL_INTERVAL_SEC,
267 (long long)pair.second.minPullIntervalSec);
268 protoOutput->end(token);
269}
270
Yangster-mac20877162017-12-22 17:19:39 -0800271} // namespace statsd
272} // namespace os
273} // namespace android