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