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