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