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