blob: a0ab3e46e719069521bab383b298e46bfa215ced [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
Yangster-mac9def8e32018-04-17 13:55:51 -070017#include "hash.h"
Yangster-mac20877162017-12-22 17:19:39 -080018#include "stats_log_util.h"
19
Yao Chen8a8d16c2018-02-08 14:50:40 -080020#include <logd/LogEvent.h>
yro59cc24d2018-02-13 20:17:32 -080021#include <private/android_filesystem_config.h>
Yao Chen8a8d16c2018-02-08 14:50:40 -080022#include <utils/Log.h>
Yangster-mac20877162017-12-22 17:19:39 -080023#include <set>
24#include <stack>
Yangster-mac330af582018-02-08 15:24:38 -080025#include <utils/Log.h>
26#include <utils/SystemClock.h>
Yangster-mac20877162017-12-22 17:19:39 -080027
28using android::util::FIELD_COUNT_REPEATED;
29using android::util::FIELD_TYPE_BOOL;
30using android::util::FIELD_TYPE_FLOAT;
31using android::util::FIELD_TYPE_INT32;
32using android::util::FIELD_TYPE_INT64;
Yangster-mac9def8e32018-04-17 13:55:51 -070033using android::util::FIELD_TYPE_UINT64;
34using android::util::FIELD_TYPE_FIXED64;
Yangster-mac20877162017-12-22 17:19:39 -080035using android::util::FIELD_TYPE_MESSAGE;
36using android::util::FIELD_TYPE_STRING;
37using android::util::ProtoOutputStream;
38
39namespace android {
40namespace os {
41namespace statsd {
42
43// for DimensionsValue Proto
44const int DIMENSIONS_VALUE_FIELD = 1;
45const int DIMENSIONS_VALUE_VALUE_STR = 2;
46const int DIMENSIONS_VALUE_VALUE_INT = 3;
47const int DIMENSIONS_VALUE_VALUE_LONG = 4;
Yao Chen4c959cb2018-02-13 13:27:48 -080048// const int DIMENSIONS_VALUE_VALUE_BOOL = 5; // logd doesn't have bool data type.
Yangster-mac20877162017-12-22 17:19:39 -080049const int DIMENSIONS_VALUE_VALUE_FLOAT = 6;
50const int DIMENSIONS_VALUE_VALUE_TUPLE = 7;
Yangster-mac9def8e32018-04-17 13:55:51 -070051const int DIMENSIONS_VALUE_VALUE_STR_HASH = 8;
Yangster-mac20877162017-12-22 17:19:39 -080052
Yao Chen8a8d16c2018-02-08 14:50:40 -080053const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
54
Chenjie Yub038b702017-12-18 15:15:34 -080055// for PulledAtomStats proto
56const int FIELD_ID_PULLED_ATOM_STATS = 10;
57const int FIELD_ID_PULL_ATOM_ID = 1;
58const int FIELD_ID_TOTAL_PULL = 2;
59const int FIELD_ID_TOTAL_PULL_FROM_CACHE = 3;
60const int FIELD_ID_MIN_PULL_INTERVAL_SEC = 4;
Yangster-mac9def8e32018-04-17 13:55:51 -070061
Yao Chen8a8d16c2018-02-08 14:50:40 -080062namespace {
Chenjie Yub038b702017-12-18 15:15:34 -080063
Yao Chen8a8d16c2018-02-08 14:50:40 -080064void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
Yangster-mac9def8e32018-04-17 13:55:51 -070065 int prefix, std::set<string> *str_set,
66 ProtoOutputStream* protoOutput) {
Yao Chen8a8d16c2018-02-08 14:50:40 -080067 size_t count = dims.size();
68 while (*index < count) {
69 const auto& dim = dims[*index];
70 const int valueDepth = dim.mField.getDepth();
71 const int valuePrefix = dim.mField.getPrefix(depth);
72 const int fieldNum = dim.mField.getPosAtDepth(depth);
73 if (valueDepth > 2) {
74 ALOGE("Depth > 2 not supported");
75 return;
76 }
77
78 if (depth == valueDepth && valuePrefix == prefix) {
Yi Jin5ee07872018-03-05 18:18:27 -080079 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
Yao Chen8a8d16c2018-02-08 14:50:40 -080080 DIMENSIONS_VALUE_TUPLE_VALUE);
81 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
82 switch (dim.mValue.getType()) {
83 case INT:
84 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
85 dim.mValue.int_value);
86 break;
87 case LONG:
88 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
89 (long long)dim.mValue.long_value);
90 break;
91 case FLOAT:
92 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
93 dim.mValue.float_value);
94 break;
95 case STRING:
Yangster-mac9def8e32018-04-17 13:55:51 -070096 if (str_set == nullptr) {
97 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
98 dim.mValue.str_value);
99 } else {
100 str_set->insert(dim.mValue.str_value);
101 protoOutput->write(
102 FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
103 (long long)Hash64(dim.mValue.str_value));
104 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800105 break;
106 default:
107 break;
108 }
109 if (token != 0) {
110 protoOutput->end(token);
111 }
112 (*index)++;
113 } else if (valueDepth > depth && valuePrefix == prefix) {
114 // Writing the sub tree
Yi Jin5ee07872018-03-05 18:18:27 -0800115 uint64_t dimensionToken = protoOutput->start(
Yao Chen8a8d16c2018-02-08 14:50:40 -0800116 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
117 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
Yi Jin5ee07872018-03-05 18:18:27 -0800118 uint64_t tupleToken =
Yao Chen8a8d16c2018-02-08 14:50:40 -0800119 protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
120 writeDimensionToProtoHelper(dims, index, valueDepth, dim.mField.getPrefix(valueDepth),
Yangster-mac9def8e32018-04-17 13:55:51 -0700121 str_set, protoOutput);
122 protoOutput->end(tupleToken);
123 protoOutput->end(dimensionToken);
124 } else {
125 // Done with the prev sub tree
126 return;
127 }
128 }
129}
130
131void writeDimensionLeafToProtoHelper(const std::vector<FieldValue>& dims,
132 const int dimensionLeafField,
133 size_t* index, int depth,
134 int prefix, std::set<string> *str_set,
135 ProtoOutputStream* protoOutput) {
136 size_t count = dims.size();
137 while (*index < count) {
138 const auto& dim = dims[*index];
139 const int valueDepth = dim.mField.getDepth();
140 const int valuePrefix = dim.mField.getPrefix(depth);
141 if (valueDepth > 2) {
142 ALOGE("Depth > 2 not supported");
143 return;
144 }
145
146 if (depth == valueDepth && valuePrefix == prefix) {
147 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
148 dimensionLeafField);
149 switch (dim.mValue.getType()) {
150 case INT:
151 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
152 dim.mValue.int_value);
153 break;
154 case LONG:
155 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
156 (long long)dim.mValue.long_value);
157 break;
158 case FLOAT:
159 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
160 dim.mValue.float_value);
161 break;
162 case STRING:
163 if (str_set == nullptr) {
164 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
165 dim.mValue.str_value);
166 } else {
167 str_set->insert(dim.mValue.str_value);
168 protoOutput->write(
169 FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
170 (long long)Hash64(dim.mValue.str_value));
171 }
172 break;
173 default:
174 break;
175 }
176 if (token != 0) {
177 protoOutput->end(token);
178 }
179 (*index)++;
180 } else if (valueDepth > depth && valuePrefix == prefix) {
181 writeDimensionLeafToProtoHelper(dims, dimensionLeafField,
182 index, valueDepth, dim.mField.getPrefix(valueDepth),
183 str_set, protoOutput);
184 } else {
185 // Done with the prev sub tree
186 return;
187 }
188 }
189}
190
191void writeDimensionPathToProtoHelper(const std::vector<Matcher>& fieldMatchers,
192 size_t* index, int depth, int prefix,
193 ProtoOutputStream* protoOutput) {
194 size_t count = fieldMatchers.size();
195 while (*index < count) {
196 const Field& field = fieldMatchers[*index].mMatcher;
197 const int valueDepth = field.getDepth();
198 const int valuePrefix = field.getPrefix(depth);
199 const int fieldNum = field.getPosAtDepth(depth);
200 if (valueDepth > 2) {
201 ALOGE("Depth > 2 not supported");
202 return;
203 }
204
205 if (depth == valueDepth && valuePrefix == prefix) {
206 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
207 DIMENSIONS_VALUE_TUPLE_VALUE);
208 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
209 if (token != 0) {
210 protoOutput->end(token);
211 }
212 (*index)++;
213 } else if (valueDepth > depth && valuePrefix == prefix) {
214 // Writing the sub tree
215 uint64_t dimensionToken = protoOutput->start(
216 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
217 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
218 uint64_t tupleToken =
219 protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
220 writeDimensionPathToProtoHelper(fieldMatchers, index, valueDepth,
221 field.getPrefix(valueDepth), protoOutput);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800222 protoOutput->end(tupleToken);
223 protoOutput->end(dimensionToken);
224 } else {
225 // Done with the prev sub tree
226 return;
227 }
228 }
229}
230
231} // namespace
232
Yangster-mac9def8e32018-04-17 13:55:51 -0700233void writeDimensionToProto(const HashableDimensionKey& dimension, std::set<string> *str_set,
234 ProtoOutputStream* protoOutput) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800235 if (dimension.getValues().size() == 0) {
Yangster-mac93694462018-01-22 20:49:31 -0800236 return;
237 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800238 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
239 dimension.getValues()[0].mField.getTag());
Yi Jin5ee07872018-03-05 18:18:27 -0800240 uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800241 size_t index = 0;
Yangster-mac9def8e32018-04-17 13:55:51 -0700242 writeDimensionToProtoHelper(dimension.getValues(), &index, 0, 0, str_set, protoOutput);
243 protoOutput->end(topToken);
244}
245
246void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension,
247 const int dimensionLeafFieldId,
248 std::set<string> *str_set,
249 ProtoOutputStream* protoOutput) {
250 if (dimension.getValues().size() == 0) {
251 return;
252 }
253 size_t index = 0;
254 writeDimensionLeafToProtoHelper(dimension.getValues(), dimensionLeafFieldId,
255 &index, 0, 0, str_set, protoOutput);
256}
257
258void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
259 ProtoOutputStream* protoOutput) {
260 if (fieldMatchers.size() == 0) {
261 return;
262 }
263 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
264 fieldMatchers[0].mMatcher.getTag());
265 uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
266 size_t index = 0;
267 writeDimensionPathToProtoHelper(fieldMatchers, &index, 0, 0, protoOutput);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800268 protoOutput->end(topToken);
Yangster-mac20877162017-12-22 17:19:39 -0800269}
270
Yao Chen8a8d16c2018-02-08 14:50:40 -0800271// Supported Atoms format
272// XYZ_Atom {
273// repeated SubMsg field_1 = 1;
274// SubMsg2 field_2 = 2;
275// int32/float/string/int63 field_3 = 3;
276// }
277// logd's msg format, doesn't allow us to distinguish between the 2 cases below
278// Case (1):
279// Atom {
280// SubMsg {
281// int i = 1;
282// int j = 2;
283// }
284// repeated SubMsg
285// }
286//
287// and case (2):
288// Atom {
289// SubMsg {
290// repeated int i = 1;
291// repeated int j = 2;
292// }
293// optional SubMsg = 1;
294// }
295//
296//
297void writeFieldValueTreeToStreamHelper(const std::vector<FieldValue>& dims, size_t* index,
298 int depth, int prefix, ProtoOutputStream* protoOutput) {
299 size_t count = dims.size();
300 while (*index < count) {
301 const auto& dim = dims[*index];
302 const int valueDepth = dim.mField.getDepth();
303 const int valuePrefix = dim.mField.getPrefix(depth);
304 const int fieldNum = dim.mField.getPosAtDepth(depth);
305 if (valueDepth > 2) {
306 ALOGE("Depth > 2 not supported");
307 return;
Yangster-mac20877162017-12-22 17:19:39 -0800308 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800309
310 if (depth == valueDepth && valuePrefix == prefix) {
311 switch (dim.mValue.getType()) {
312 case INT:
313 protoOutput->write(FIELD_TYPE_INT32 | fieldNum, dim.mValue.int_value);
314 break;
315 case LONG:
316 protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
317 (long long)dim.mValue.long_value);
318 break;
319 case FLOAT:
320 protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value);
321 break;
322 case STRING:
323 protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
324 break;
Yangster-macf5204922018-02-23 13:08:03 -0800325 default:
326 break;
Yao Chen8a8d16c2018-02-08 14:50:40 -0800327 }
328 (*index)++;
329 } else if (valueDepth > depth && valuePrefix == prefix) {
330 // Writing the sub tree
Yi Jin5ee07872018-03-05 18:18:27 -0800331 uint64_t msg_token = 0ULL;
Yao Chen8a8d16c2018-02-08 14:50:40 -0800332 if (valueDepth == depth + 2) {
333 msg_token =
334 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
335 } else if (valueDepth == depth + 1) {
336 msg_token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
337 }
338 // Directly jump to the leaf value because the repeated position field is implied
339 // by the position of the sub msg in the parent field.
340 writeFieldValueTreeToStreamHelper(dims, index, valueDepth,
341 dim.mField.getPrefix(valueDepth), protoOutput);
342 if (msg_token != 0) {
343 protoOutput->end(msg_token);
344 }
345 } else {
346 // Done with the prev sub tree
347 return;
348 }
Yangster-mac20877162017-12-22 17:19:39 -0800349 }
350}
351
Yao Chen8a8d16c2018-02-08 14:50:40 -0800352void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
Yangster-mac20877162017-12-22 17:19:39 -0800353 util::ProtoOutputStream* protoOutput) {
Yi Jin5ee07872018-03-05 18:18:27 -0800354 uint64_t atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId);
Yangster-mac20877162017-12-22 17:19:39 -0800355
Yao Chen8a8d16c2018-02-08 14:50:40 -0800356 size_t index = 0;
357 writeFieldValueTreeToStreamHelper(values, &index, 0, 0, protoOutput);
358 protoOutput->end(atomToken);
Yangster-macb8144812018-01-04 10:56:23 -0800359}
Yangster-mac20877162017-12-22 17:19:39 -0800360
yro59cc24d2018-02-13 20:17:32 -0800361int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
362 int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
Chenjie Yu1a0a9412018-03-28 10:07:22 -0700363 if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL &&
364 uid != AID_ROOT) {
yro59cc24d2018-02-13 20:17:32 -0800365 bucketSizeMillis = 5 * 60 * 1000LL;
366 }
367 return bucketSizeMillis;
368}
369
Yangster-macb8144812018-01-04 10:56:23 -0800370int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
371 switch (unit) {
372 case ONE_MINUTE:
373 return 60 * 1000LL;
374 case FIVE_MINUTES:
375 return 5 * 60 * 1000LL;
376 case TEN_MINUTES:
377 return 10 * 60 * 1000LL;
378 case THIRTY_MINUTES:
379 return 30 * 60 * 1000LL;
380 case ONE_HOUR:
381 return 60 * 60 * 1000LL;
382 case THREE_HOURS:
383 return 3 * 60 * 60 * 1000LL;
384 case SIX_HOURS:
385 return 6 * 60 * 60 * 1000LL;
386 case TWELVE_HOURS:
387 return 12 * 60 * 60 * 1000LL;
388 case ONE_DAY:
389 return 24 * 60 * 60 * 1000LL;
390 case CTS:
391 return 1000;
392 case TIME_UNIT_UNSPECIFIED:
393 default:
394 return -1;
395 }
Yangster-mac20877162017-12-22 17:19:39 -0800396}
397
Chenjie Yub038b702017-12-18 15:15:34 -0800398void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
399 util::ProtoOutputStream* protoOutput) {
Yi Jin5ee07872018-03-05 18:18:27 -0800400 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_PULLED_ATOM_STATS |
Chenjie Yub038b702017-12-18 15:15:34 -0800401 FIELD_COUNT_REPEATED);
402 protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_PULL_ATOM_ID, (int32_t)pair.first);
403 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL, (long long)pair.second.totalPull);
404 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL_FROM_CACHE,
405 (long long)pair.second.totalPullFromCache);
406 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_PULL_INTERVAL_SEC,
407 (long long)pair.second.minPullIntervalSec);
408 protoOutput->end(token);
409}
410
Yangster-mac330af582018-02-08 15:24:38 -0800411int64_t getElapsedRealtimeNs() {
412 return ::android::elapsedRealtimeNano();
413}
414
415int64_t getElapsedRealtimeSec() {
416 return ::android::elapsedRealtimeNano() / NS_PER_SEC;
417}
418
419int64_t getElapsedRealtimeMillis() {
420 return ::android::elapsedRealtime();
421}
422
423int64_t getWallClockNs() {
424 return time(nullptr) * NS_PER_SEC;
425}
426
427int64_t getWallClockSec() {
428 return time(nullptr);
429}
430
431int64_t getWallClockMillis() {
432 return time(nullptr) * MS_PER_SEC;
433}
434
Yangster-macd5c35622018-02-02 10:33:25 -0800435int64_t truncateTimestampNsToFiveMinutes(int64_t timestampNs) {
436 return timestampNs / NS_PER_SEC / (5 * 60) * NS_PER_SEC * (5 * 60);
437}
438
Yangster-mac9def8e32018-04-17 13:55:51 -0700439int64_t NanoToMillis(const int64_t nano) {
440 return nano / 1000000;
441}
442
443int64_t MillisToNano(const int64_t millis) {
444 return millis * 1000000;
445}
446
Yangster-mac20877162017-12-22 17:19:39 -0800447} // namespace statsd
448} // namespace os
yro59cc24d2018-02-13 20:17:32 -0800449} // namespace android