• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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