1 /*
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 "hash.h"
18 #include "stats_log_util.h"
19
20 #include <logd/LogEvent.h>
21 #include <private/android_filesystem_config.h>
22 #include <utils/Log.h>
23 #include <set>
24 #include <stack>
25 #include <utils/Log.h>
26 #include <utils/SystemClock.h>
27
28 using android::util::AtomsInfo;
29 using android::util::FIELD_COUNT_REPEATED;
30 using android::util::FIELD_TYPE_BOOL;
31 using android::util::FIELD_TYPE_FIXED64;
32 using android::util::FIELD_TYPE_FLOAT;
33 using android::util::FIELD_TYPE_INT32;
34 using android::util::FIELD_TYPE_INT64;
35 using android::util::FIELD_TYPE_MESSAGE;
36 using android::util::FIELD_TYPE_STRING;
37 using android::util::FIELD_TYPE_UINT64;
38 using android::util::ProtoOutputStream;
39
40 namespace android {
41 namespace os {
42 namespace statsd {
43
44 // for DimensionsValue Proto
45 const int DIMENSIONS_VALUE_FIELD = 1;
46 const int DIMENSIONS_VALUE_VALUE_STR = 2;
47 const int DIMENSIONS_VALUE_VALUE_INT = 3;
48 const int DIMENSIONS_VALUE_VALUE_LONG = 4;
49 // const int DIMENSIONS_VALUE_VALUE_BOOL = 5; // logd doesn't have bool data type.
50 const int DIMENSIONS_VALUE_VALUE_FLOAT = 6;
51 const int DIMENSIONS_VALUE_VALUE_TUPLE = 7;
52 const int DIMENSIONS_VALUE_VALUE_STR_HASH = 8;
53
54 const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
55
56 // for PulledAtomStats proto
57 const int FIELD_ID_PULLED_ATOM_STATS = 10;
58 const int FIELD_ID_PULL_ATOM_ID = 1;
59 const int FIELD_ID_TOTAL_PULL = 2;
60 const int FIELD_ID_TOTAL_PULL_FROM_CACHE = 3;
61 const int FIELD_ID_MIN_PULL_INTERVAL_SEC = 4;
62 const int FIELD_ID_AVERAGE_PULL_TIME_NANOS = 5;
63 const int FIELD_ID_MAX_PULL_TIME_NANOS = 6;
64 const int FIELD_ID_AVERAGE_PULL_DELAY_NANOS = 7;
65 const int FIELD_ID_MAX_PULL_DELAY_NANOS = 8;
66 const int FIELD_ID_DATA_ERROR = 9;
67 const int FIELD_ID_PULL_TIMEOUT = 10;
68 const int FIELD_ID_PULL_EXCEED_MAX_DELAY = 11;
69 const int FIELD_ID_PULL_FAILED = 12;
70 const int FIELD_ID_STATS_COMPANION_FAILED = 13;
71 const int FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED = 14;
72 const int FIELD_ID_EMPTY_DATA = 15;
73 const int FIELD_ID_PULL_REGISTERED_COUNT = 16;
74 const int FIELD_ID_PULL_UNREGISTERED_COUNT = 17;
75 // for AtomMetricStats proto
76 const int FIELD_ID_ATOM_METRIC_STATS = 17;
77 const int FIELD_ID_METRIC_ID = 1;
78 const int FIELD_ID_HARD_DIMENSION_LIMIT_REACHED = 2;
79 const int FIELD_ID_LATE_LOG_EVENT_SKIPPED = 3;
80 const int FIELD_ID_SKIPPED_FORWARD_BUCKETS = 4;
81 const int FIELD_ID_BAD_VALUE_TYPE = 5;
82 const int FIELD_ID_CONDITION_CHANGE_IN_NEXT_BUCKET = 6;
83 const int FIELD_ID_INVALIDATED_BUCKET = 7;
84 const int FIELD_ID_BUCKET_DROPPED = 8;
85 const int FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS = 9;
86 const int FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS = 10;
87 const int FIELD_ID_BUCKET_UNKNOWN_CONDITION = 11;
88 const int FIELD_ID_BUCKET_COUNT = 12;
89
90 namespace {
91
writeDimensionToProtoHelper(const std::vector<FieldValue> & dims,size_t * index,int depth,int prefix,std::set<string> * str_set,ProtoOutputStream * protoOutput)92 void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
93 int prefix, std::set<string> *str_set,
94 ProtoOutputStream* protoOutput) {
95 size_t count = dims.size();
96 while (*index < count) {
97 const auto& dim = dims[*index];
98 const int valueDepth = dim.mField.getDepth();
99 const int valuePrefix = dim.mField.getPrefix(depth);
100 const int fieldNum = dim.mField.getPosAtDepth(depth);
101 if (valueDepth > 2) {
102 ALOGE("Depth > 2 not supported");
103 return;
104 }
105
106 if (depth == valueDepth && valuePrefix == prefix) {
107 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
108 DIMENSIONS_VALUE_TUPLE_VALUE);
109 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
110 switch (dim.mValue.getType()) {
111 case INT:
112 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
113 dim.mValue.int_value);
114 break;
115 case LONG:
116 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
117 (long long)dim.mValue.long_value);
118 break;
119 case FLOAT:
120 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
121 dim.mValue.float_value);
122 break;
123 case STRING:
124 if (str_set == nullptr) {
125 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
126 dim.mValue.str_value);
127 } else {
128 str_set->insert(dim.mValue.str_value);
129 protoOutput->write(
130 FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
131 (long long)Hash64(dim.mValue.str_value));
132 }
133 break;
134 default:
135 break;
136 }
137 if (token != 0) {
138 protoOutput->end(token);
139 }
140 (*index)++;
141 } else if (valueDepth > depth && valuePrefix == prefix) {
142 // Writing the sub tree
143 uint64_t dimensionToken = protoOutput->start(
144 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
145 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
146 uint64_t tupleToken =
147 protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
148 writeDimensionToProtoHelper(dims, index, valueDepth, dim.mField.getPrefix(valueDepth),
149 str_set, protoOutput);
150 protoOutput->end(tupleToken);
151 protoOutput->end(dimensionToken);
152 } else {
153 // Done with the prev sub tree
154 return;
155 }
156 }
157 }
158
writeDimensionLeafToProtoHelper(const std::vector<FieldValue> & dims,const int dimensionLeafField,size_t * index,int depth,int prefix,std::set<string> * str_set,ProtoOutputStream * protoOutput)159 void writeDimensionLeafToProtoHelper(const std::vector<FieldValue>& dims,
160 const int dimensionLeafField,
161 size_t* index, int depth,
162 int prefix, std::set<string> *str_set,
163 ProtoOutputStream* protoOutput) {
164 size_t count = dims.size();
165 while (*index < count) {
166 const auto& dim = dims[*index];
167 const int valueDepth = dim.mField.getDepth();
168 const int valuePrefix = dim.mField.getPrefix(depth);
169 if (valueDepth > 2) {
170 ALOGE("Depth > 2 not supported");
171 return;
172 }
173
174 if (depth == valueDepth && valuePrefix == prefix) {
175 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
176 dimensionLeafField);
177 switch (dim.mValue.getType()) {
178 case INT:
179 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
180 dim.mValue.int_value);
181 break;
182 case LONG:
183 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
184 (long long)dim.mValue.long_value);
185 break;
186 case FLOAT:
187 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
188 dim.mValue.float_value);
189 break;
190 case STRING:
191 if (str_set == nullptr) {
192 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
193 dim.mValue.str_value);
194 } else {
195 str_set->insert(dim.mValue.str_value);
196 protoOutput->write(
197 FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
198 (long long)Hash64(dim.mValue.str_value));
199 }
200 break;
201 default:
202 break;
203 }
204 if (token != 0) {
205 protoOutput->end(token);
206 }
207 (*index)++;
208 } else if (valueDepth > depth && valuePrefix == prefix) {
209 writeDimensionLeafToProtoHelper(dims, dimensionLeafField,
210 index, valueDepth, dim.mField.getPrefix(valueDepth),
211 str_set, protoOutput);
212 } else {
213 // Done with the prev sub tree
214 return;
215 }
216 }
217 }
218
writeDimensionPathToProtoHelper(const std::vector<Matcher> & fieldMatchers,size_t * index,int depth,int prefix,ProtoOutputStream * protoOutput)219 void writeDimensionPathToProtoHelper(const std::vector<Matcher>& fieldMatchers,
220 size_t* index, int depth, int prefix,
221 ProtoOutputStream* protoOutput) {
222 size_t count = fieldMatchers.size();
223 while (*index < count) {
224 const Field& field = fieldMatchers[*index].mMatcher;
225 const int valueDepth = field.getDepth();
226 const int valuePrefix = field.getPrefix(depth);
227 const int fieldNum = field.getPosAtDepth(depth);
228 if (valueDepth > 2) {
229 ALOGE("Depth > 2 not supported");
230 return;
231 }
232
233 if (depth == valueDepth && valuePrefix == prefix) {
234 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
235 DIMENSIONS_VALUE_TUPLE_VALUE);
236 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
237 if (token != 0) {
238 protoOutput->end(token);
239 }
240 (*index)++;
241 } else if (valueDepth > depth && valuePrefix == prefix) {
242 // Writing the sub tree
243 uint64_t dimensionToken = protoOutput->start(
244 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
245 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
246 uint64_t tupleToken =
247 protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
248 writeDimensionPathToProtoHelper(fieldMatchers, index, valueDepth,
249 field.getPrefix(valueDepth), protoOutput);
250 protoOutput->end(tupleToken);
251 protoOutput->end(dimensionToken);
252 } else {
253 // Done with the prev sub tree
254 return;
255 }
256 }
257 }
258
259 } // namespace
260
writeDimensionToProto(const HashableDimensionKey & dimension,std::set<string> * str_set,ProtoOutputStream * protoOutput)261 void writeDimensionToProto(const HashableDimensionKey& dimension, std::set<string> *str_set,
262 ProtoOutputStream* protoOutput) {
263 if (dimension.getValues().size() == 0) {
264 return;
265 }
266 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
267 dimension.getValues()[0].mField.getTag());
268 uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
269 size_t index = 0;
270 writeDimensionToProtoHelper(dimension.getValues(), &index, 0, 0, str_set, protoOutput);
271 protoOutput->end(topToken);
272 }
273
writeDimensionLeafNodesToProto(const HashableDimensionKey & dimension,const int dimensionLeafFieldId,std::set<string> * str_set,ProtoOutputStream * protoOutput)274 void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension,
275 const int dimensionLeafFieldId,
276 std::set<string> *str_set,
277 ProtoOutputStream* protoOutput) {
278 if (dimension.getValues().size() == 0) {
279 return;
280 }
281 size_t index = 0;
282 writeDimensionLeafToProtoHelper(dimension.getValues(), dimensionLeafFieldId,
283 &index, 0, 0, str_set, protoOutput);
284 }
285
writeDimensionPathToProto(const std::vector<Matcher> & fieldMatchers,ProtoOutputStream * protoOutput)286 void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
287 ProtoOutputStream* protoOutput) {
288 if (fieldMatchers.size() == 0) {
289 return;
290 }
291 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
292 fieldMatchers[0].mMatcher.getTag());
293 uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
294 size_t index = 0;
295 writeDimensionPathToProtoHelper(fieldMatchers, &index, 0, 0, protoOutput);
296 protoOutput->end(topToken);
297 }
298
299 // Supported Atoms format
300 // XYZ_Atom {
301 // repeated SubMsg field_1 = 1;
302 // SubMsg2 field_2 = 2;
303 // int32/float/string/int63 field_3 = 3;
304 // }
305 // logd's msg format, doesn't allow us to distinguish between the 2 cases below
306 // Case (1):
307 // Atom {
308 // SubMsg {
309 // int i = 1;
310 // int j = 2;
311 // }
312 // repeated SubMsg
313 // }
314 //
315 // and case (2):
316 // Atom {
317 // SubMsg {
318 // repeated int i = 1;
319 // repeated int j = 2;
320 // }
321 // optional SubMsg = 1;
322 // }
323 //
324 //
writeFieldValueTreeToStreamHelper(int tagId,const std::vector<FieldValue> & dims,size_t * index,int depth,int prefix,ProtoOutputStream * protoOutput)325 void writeFieldValueTreeToStreamHelper(int tagId, const std::vector<FieldValue>& dims,
326 size_t* index, int depth, int prefix,
327 ProtoOutputStream* protoOutput) {
328 size_t count = dims.size();
329 while (*index < count) {
330 const auto& dim = dims[*index];
331 const int valueDepth = dim.mField.getDepth();
332 const int valuePrefix = dim.mField.getPrefix(depth);
333 const int fieldNum = dim.mField.getPosAtDepth(depth);
334 if (valueDepth > 2) {
335 ALOGE("Depth > 2 not supported");
336 return;
337 }
338
339 if (depth == valueDepth && valuePrefix == prefix) {
340 switch (dim.mValue.getType()) {
341 case INT:
342 protoOutput->write(FIELD_TYPE_INT32 | fieldNum, dim.mValue.int_value);
343 break;
344 case LONG:
345 protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
346 (long long)dim.mValue.long_value);
347 break;
348 case FLOAT:
349 protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value);
350 break;
351 case STRING: {
352 bool isBytesField = false;
353 // Bytes field is logged via string format in log_msg format. So here we check
354 // if this string field is a byte field.
355 std::map<int, std::vector<int>>::const_iterator itr;
356 if (depth == 0 && (itr = AtomsInfo::kBytesFieldAtoms.find(tagId)) !=
357 AtomsInfo::kBytesFieldAtoms.end()) {
358 const std::vector<int>& bytesFields = itr->second;
359 for (int bytesField : bytesFields) {
360 if (bytesField == fieldNum) {
361 // This is a bytes field
362 isBytesField = true;
363 break;
364 }
365 }
366 }
367 if (isBytesField) {
368 if (dim.mValue.str_value.length() > 0) {
369 protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
370 (const char*)dim.mValue.str_value.c_str(),
371 dim.mValue.str_value.length());
372 }
373 } else {
374 protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
375 }
376 break;
377 }
378 case STORAGE:
379 protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
380 (const char*)dim.mValue.storage_value.data(),
381 dim.mValue.storage_value.size());
382 break;
383 default:
384 break;
385 }
386 (*index)++;
387 } else if (valueDepth > depth && valuePrefix == prefix) {
388 // Writing the sub tree
389 uint64_t msg_token = 0ULL;
390 if (valueDepth == depth + 2) {
391 msg_token =
392 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
393 } else if (valueDepth == depth + 1) {
394 msg_token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
395 }
396 // Directly jump to the leaf value because the repeated position field is implied
397 // by the position of the sub msg in the parent field.
398 writeFieldValueTreeToStreamHelper(tagId, dims, index, valueDepth,
399 dim.mField.getPrefix(valueDepth), protoOutput);
400 if (msg_token != 0) {
401 protoOutput->end(msg_token);
402 }
403 } else {
404 // Done with the prev sub tree
405 return;
406 }
407 }
408 }
409
writeFieldValueTreeToStream(int tagId,const std::vector<FieldValue> & values,util::ProtoOutputStream * protoOutput)410 void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
411 util::ProtoOutputStream* protoOutput) {
412 uint64_t atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId);
413
414 size_t index = 0;
415 writeFieldValueTreeToStreamHelper(tagId, values, &index, 0, 0, protoOutput);
416 protoOutput->end(atomToken);
417 }
418
TimeUnitToBucketSizeInMillisGuardrailed(int uid,TimeUnit unit)419 int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
420 int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
421 if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL &&
422 uid != AID_ROOT) {
423 bucketSizeMillis = 5 * 60 * 1000LL;
424 }
425 return bucketSizeMillis;
426 }
427
TimeUnitToBucketSizeInMillis(TimeUnit unit)428 int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
429 switch (unit) {
430 case ONE_MINUTE:
431 return 60 * 1000LL;
432 case FIVE_MINUTES:
433 return 5 * 60 * 1000LL;
434 case TEN_MINUTES:
435 return 10 * 60 * 1000LL;
436 case THIRTY_MINUTES:
437 return 30 * 60 * 1000LL;
438 case ONE_HOUR:
439 return 60 * 60 * 1000LL;
440 case THREE_HOURS:
441 return 3 * 60 * 60 * 1000LL;
442 case SIX_HOURS:
443 return 6 * 60 * 60 * 1000LL;
444 case TWELVE_HOURS:
445 return 12 * 60 * 60 * 1000LL;
446 case ONE_DAY:
447 return 24 * 60 * 60 * 1000LL;
448 case CTS:
449 return 1000;
450 case TIME_UNIT_UNSPECIFIED:
451 default:
452 return -1;
453 }
454 }
455
writePullerStatsToStream(const std::pair<int,StatsdStats::PulledAtomStats> & pair,util::ProtoOutputStream * protoOutput)456 void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
457 util::ProtoOutputStream* protoOutput) {
458 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_PULLED_ATOM_STATS |
459 FIELD_COUNT_REPEATED);
460 protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_PULL_ATOM_ID, (int32_t)pair.first);
461 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL, (long long)pair.second.totalPull);
462 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL_FROM_CACHE,
463 (long long)pair.second.totalPullFromCache);
464 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_PULL_INTERVAL_SEC,
465 (long long)pair.second.minPullIntervalSec);
466 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_AVERAGE_PULL_TIME_NANOS,
467 (long long)pair.second.avgPullTimeNs);
468 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_TIME_NANOS,
469 (long long)pair.second.maxPullTimeNs);
470 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_AVERAGE_PULL_DELAY_NANOS,
471 (long long)pair.second.avgPullDelayNs);
472 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_DELAY_NANOS,
473 (long long)pair.second.maxPullDelayNs);
474 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DATA_ERROR, (long long)pair.second.dataError);
475 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_TIMEOUT,
476 (long long)pair.second.pullTimeout);
477 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_EXCEED_MAX_DELAY,
478 (long long)pair.second.pullExceedMaxDelay);
479 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_FAILED,
480 (long long)pair.second.pullFailed);
481 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_STATS_COMPANION_FAILED,
482 (long long)pair.second.statsCompanionPullFailed);
483 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED,
484 (long long)pair.second.statsCompanionPullBinderTransactionFailed);
485 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_EMPTY_DATA,
486 (long long)pair.second.emptyData);
487 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_REGISTERED_COUNT,
488 (long long) pair.second.registeredCount);
489 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UNREGISTERED_COUNT,
490 (long long) pair.second.unregisteredCount);
491 protoOutput->end(token);
492 }
493
writeAtomMetricStatsToStream(const std::pair<int64_t,StatsdStats::AtomMetricStats> & pair,util::ProtoOutputStream * protoOutput)494 void writeAtomMetricStatsToStream(const std::pair<int64_t, StatsdStats::AtomMetricStats> &pair,
495 util::ProtoOutputStream *protoOutput) {
496 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_METRIC_STATS |
497 FIELD_COUNT_REPEATED);
498 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID, (long long)pair.first);
499 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_HARD_DIMENSION_LIMIT_REACHED,
500 (long long)pair.second.hardDimensionLimitReached);
501 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_LATE_LOG_EVENT_SKIPPED,
502 (long long)pair.second.lateLogEventSkipped);
503 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_FORWARD_BUCKETS,
504 (long long)pair.second.skippedForwardBuckets);
505 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BAD_VALUE_TYPE,
506 (long long)pair.second.badValueType);
507 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_CHANGE_IN_NEXT_BUCKET,
508 (long long)pair.second.conditionChangeInNextBucket);
509 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_INVALIDATED_BUCKET,
510 (long long)pair.second.invalidatedBucket);
511 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_DROPPED,
512 (long long)pair.second.bucketDropped);
513 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS,
514 (long long)pair.second.minBucketBoundaryDelayNs);
515 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS,
516 (long long)pair.second.maxBucketBoundaryDelayNs);
517 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_UNKNOWN_CONDITION,
518 (long long)pair.second.bucketUnknownCondition);
519 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_COUNT,
520 (long long)pair.second.bucketCount);
521 protoOutput->end(token);
522 }
523
getElapsedRealtimeNs()524 int64_t getElapsedRealtimeNs() {
525 return ::android::elapsedRealtimeNano();
526 }
527
getElapsedRealtimeSec()528 int64_t getElapsedRealtimeSec() {
529 return ::android::elapsedRealtimeNano() / NS_PER_SEC;
530 }
531
getElapsedRealtimeMillis()532 int64_t getElapsedRealtimeMillis() {
533 return ::android::elapsedRealtime();
534 }
535
getWallClockNs()536 int64_t getWallClockNs() {
537 return time(nullptr) * NS_PER_SEC;
538 }
539
getWallClockSec()540 int64_t getWallClockSec() {
541 return time(nullptr);
542 }
543
getWallClockMillis()544 int64_t getWallClockMillis() {
545 return time(nullptr) * MS_PER_SEC;
546 }
547
truncateTimestampIfNecessary(int atomId,int64_t timestampNs)548 int64_t truncateTimestampIfNecessary(int atomId, int64_t timestampNs) {
549 if (AtomsInfo::kTruncatingTimestampAtomBlackList.find(atomId) !=
550 AtomsInfo::kTruncatingTimestampAtomBlackList.end() ||
551 (atomId >= StatsdStats::kTimestampTruncationStartTag &&
552 atomId <= StatsdStats::kTimestampTruncationEndTag)) {
553 return timestampNs / NS_PER_SEC / (5 * 60) * NS_PER_SEC * (5 * 60);
554 } else {
555 return timestampNs;
556 }
557 }
558
NanoToMillis(const int64_t nano)559 int64_t NanoToMillis(const int64_t nano) {
560 return nano / 1000000;
561 }
562
MillisToNano(const int64_t millis)563 int64_t MillisToNano(const int64_t millis) {
564 return millis * 1000000;
565 }
566
567 } // namespace statsd
568 } // namespace os
569 } // namespace android
570