blob: 6c6140081bd81166c25a989548d83a2c40251a95 [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) {
Yangster-mac93694462018-01-22 20:49:31 -080057 if (!dimensionsValue.has_field()) {
58 return;
59 }
Yangster-mac20877162017-12-22 17:19:39 -080060 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, dimensionsValue.field());
61 switch (dimensionsValue.value_case()) {
62 case DimensionsValue::ValueCase::kValueStr:
63 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
64 dimensionsValue.value_str());
65 break;
66 case DimensionsValue::ValueCase::kValueInt:
67 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
68 dimensionsValue.value_int());
69 break;
70 case DimensionsValue::ValueCase::kValueLong:
71 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
72 dimensionsValue.value_long());
73 break;
74 case DimensionsValue::ValueCase::kValueBool:
75 protoOutput->write(FIELD_TYPE_BOOL | DIMENSIONS_VALUE_VALUE_BOOL,
76 dimensionsValue.value_bool());
77 break;
78 case DimensionsValue::ValueCase::kValueFloat:
79 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
80 dimensionsValue.value_float());
81 break;
82 case DimensionsValue::ValueCase::kValueTuple:
83 {
84 long long tupleToken = protoOutput->start(
85 FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
86 for (int i = 0; i < dimensionsValue.value_tuple().dimensions_value_size(); ++i) {
87 long long token = protoOutput->start(
88 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED
89 | FIELD_ID_FIELD_VALUE_IN_MESSAGE_VALUE_PROTO);
90 writeDimensionsValueProtoToStream(
91 dimensionsValue.value_tuple().dimensions_value(i), protoOutput);
92 protoOutput->end(token);
93 }
94 protoOutput->end(tupleToken);
95 }
96 break;
97 default:
98 break;
99 }
100}
101
102// for Field Proto
103const int FIELD_FIELD = 1;
104const int FIELD_POSITION_INDEX = 2;
105const int FIELD_CHILD = 3;
106
107void writeFieldProtoToStream(
108 const Field& field, util::ProtoOutputStream* protoOutput) {
Yangster-mac93694462018-01-22 20:49:31 -0800109 if (!field.has_field()) {
110 return;
111 }
Yangster-mac20877162017-12-22 17:19:39 -0800112 protoOutput->write(FIELD_TYPE_INT32 | FIELD_FIELD, field.field());
113 if (field.has_position_index()) {
114 protoOutput->write(FIELD_TYPE_INT32 | FIELD_POSITION_INDEX, field.position_index());
115 }
116 for (int i = 0; i < field.child_size(); ++i) {
117 long long childToken = protoOutput->start(
118 FIELD_TYPE_MESSAGE| FIELD_COUNT_REPEATED | FIELD_CHILD);
119 writeFieldProtoToStream(field.child(i), protoOutput);
120 protoOutput->end(childToken);
121 }
122}
123
124namespace {
125
126void addOrUpdateChildrenMap(
127 const Field& root,
128 const Field& node,
129 std::map<Field, std::set<Field, FieldCmp>, FieldCmp> *childrenMap) {
130 Field parentNode = root;
131 if (node.has_position_index()) {
132 appendLeaf(&parentNode, node.field(), node.position_index());
133 } else {
134 appendLeaf(&parentNode, node.field());
135 }
136 if (childrenMap->find(parentNode) == childrenMap->end()) {
137 childrenMap->insert(std::make_pair(parentNode, std::set<Field, FieldCmp>{}));
138 }
139 auto it = childrenMap->find(parentNode);
140 for (int i = 0; i < node.child_size(); ++i) {
141 auto child = node.child(i);
142 Field childNode = parentNode;
143 if (child.has_position_index()) {
144 appendLeaf(&childNode, child.field(), child.position_index());
145 } else {
146 appendLeaf(&childNode, child.field());
147 }
148 it->second.insert(childNode);
149 addOrUpdateChildrenMap(parentNode, child, childrenMap);
150 }
151}
152
153void addOrUpdateChildrenMap(
154 const Field& field,
155 std::map<Field, std::set<Field, FieldCmp>, FieldCmp> *childrenMap) {
156 Field root;
157 addOrUpdateChildrenMap(root, field, childrenMap);
158}
159
160} // namespace
161
162void writeFieldValueTreeToStream(const FieldValueMap &fieldValueMap,
163 util::ProtoOutputStream* protoOutput) {
164 std::map<Field, std::set<Field, FieldCmp>, FieldCmp> childrenMap;
165 // Rebuild the field tree.
166 for (auto it = fieldValueMap.begin(); it != fieldValueMap.end(); ++it) {
167 addOrUpdateChildrenMap(it->first, &childrenMap);
168 }
169 std::stack<std::pair<long long, Field>> tokenStack;
170 // Iterate over the node tree to fill the Atom proto.
171 for (auto it = childrenMap.begin(); it != childrenMap.end(); ++it) {
172 const Field* nodeLeaf = getSingleLeaf(&it->first);
173 const int fieldNum = nodeLeaf->field();
174 while (!tokenStack.empty()) {
175 auto currentMsgNode = tokenStack.top().second;
176 auto currentMsgNodeChildrenIt = childrenMap.find(currentMsgNode);
177 if (currentMsgNodeChildrenIt->second.find(it->first) ==
178 currentMsgNodeChildrenIt->second.end()) {
179 protoOutput->end(tokenStack.top().first);
180 tokenStack.pop();
181 } else {
182 break;
183 }
184 }
185 if (it->second.size() == 0) {
186 auto itValue = fieldValueMap.find(it->first);
187 if (itValue != fieldValueMap.end()) {
188 const DimensionsValue& value = itValue->second;
189 switch (value.value_case()) {
190 case DimensionsValue::ValueCase::kValueStr:
191 protoOutput->write(FIELD_TYPE_STRING | fieldNum,
192 value.value_str());
193 break;
194 case DimensionsValue::ValueCase::kValueInt:
195 protoOutput->write(FIELD_TYPE_INT32 | fieldNum,
196 value.value_int());
197 break;
198 case DimensionsValue::ValueCase::kValueLong:
199 protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
200 value.value_long());
201 break;
202 case DimensionsValue::ValueCase::kValueBool:
203 protoOutput->write(FIELD_TYPE_BOOL | fieldNum,
204 value.value_bool());
205 break;
206 case DimensionsValue::ValueCase::kValueFloat:
207 protoOutput->write(FIELD_TYPE_FLOAT | fieldNum,
208 value.value_float());
209 break;
210 // This would not happen as the node has no child.
211 case DimensionsValue::ValueCase::kValueTuple:
212 break;
213 default:
214 break;
215 }
216 } else {
217 ALOGE("Leaf node value not found. This should never happen.");
218 }
219 } else {
220 long long token;
221 if (nodeLeaf->has_position_index()) {
222 token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
223 } else {
224 token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
225 }
226 tokenStack.push(std::make_pair(token, it->first));
227 }
228 }
229
230 while (!tokenStack.empty()) {
231 protoOutput->end(tokenStack.top().first);
232 tokenStack.pop();
233 }
Yangster-macb8144812018-01-04 10:56:23 -0800234}
Yangster-mac20877162017-12-22 17:19:39 -0800235
Yangster-macb8144812018-01-04 10:56:23 -0800236int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
237 switch (unit) {
238 case ONE_MINUTE:
239 return 60 * 1000LL;
240 case FIVE_MINUTES:
241 return 5 * 60 * 1000LL;
242 case TEN_MINUTES:
243 return 10 * 60 * 1000LL;
244 case THIRTY_MINUTES:
245 return 30 * 60 * 1000LL;
246 case ONE_HOUR:
247 return 60 * 60 * 1000LL;
248 case THREE_HOURS:
249 return 3 * 60 * 60 * 1000LL;
250 case SIX_HOURS:
251 return 6 * 60 * 60 * 1000LL;
252 case TWELVE_HOURS:
253 return 12 * 60 * 60 * 1000LL;
254 case ONE_DAY:
255 return 24 * 60 * 60 * 1000LL;
256 case CTS:
257 return 1000;
258 case TIME_UNIT_UNSPECIFIED:
259 default:
260 return -1;
261 }
Yangster-mac20877162017-12-22 17:19:39 -0800262}
263
Chenjie Yub038b702017-12-18 15:15:34 -0800264void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
265 util::ProtoOutputStream* protoOutput) {
266 long long token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_PULLED_ATOM_STATS |
267 FIELD_COUNT_REPEATED);
268 protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_PULL_ATOM_ID, (int32_t)pair.first);
269 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL, (long long)pair.second.totalPull);
270 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL_FROM_CACHE,
271 (long long)pair.second.totalPullFromCache);
272 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_PULL_INTERVAL_SEC,
273 (long long)pair.second.minPullIntervalSec);
274 protoOutput->end(token);
275}
276
Yangster-mac20877162017-12-22 17:19:39 -0800277} // namespace statsd
278} // namespace os
279} // namespace android