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 (depth == valueDepth && valuePrefix == prefix) {
120 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
121 DIMENSIONS_VALUE_TUPLE_VALUE);
122 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
123 switch (dim.mValue.getType()) {
124 case INT:
125 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
126 dim.mValue.int_value);
127 break;
128 case LONG:
129 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
130 (long long)dim.mValue.long_value);
131 break;
132 case FLOAT:
133 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
134 dim.mValue.float_value);
135 break;
136 case STRING:
137 if (str_set == nullptr) {
138 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
139 dim.mValue.str_value);
140 } else {
141 str_set->insert(dim.mValue.str_value);
142 protoOutput->write(
143 FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
144 (long long)Hash64(dim.mValue.str_value));
145 }
146 break;
147 default:
148 break;
149 }
150 if (token != 0) {
151 protoOutput->end(token);
152 }
153 (*index)++;
154 } else if (valueDepth > depth && valuePrefix == prefix) {
155 // Writing the sub tree
156 uint64_t dimensionToken = protoOutput->start(
157 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
158 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
159 uint64_t tupleToken =
160 protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
161 writeDimensionToProtoHelper(dims, index, valueDepth, dim.mField.getPrefix(valueDepth),
162 str_set, protoOutput);
163 protoOutput->end(tupleToken);
164 protoOutput->end(dimensionToken);
165 } else {
166 // Done with the prev sub tree
167 return;
168 }
169 }
170 }
171
writeDimensionLeafToProtoHelper(const std::vector<FieldValue> & dims,const int dimensionLeafField,size_t * index,int depth,int prefix,std::set<string> * str_set,ProtoOutputStream * protoOutput)172 void writeDimensionLeafToProtoHelper(const std::vector<FieldValue>& dims,
173 const int dimensionLeafField,
174 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 (depth == valueDepth && valuePrefix == prefix) {
188 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
189 dimensionLeafField);
190 switch (dim.mValue.getType()) {
191 case INT:
192 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
193 dim.mValue.int_value);
194 break;
195 case LONG:
196 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
197 (long long)dim.mValue.long_value);
198 break;
199 case FLOAT:
200 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
201 dim.mValue.float_value);
202 break;
203 case STRING:
204 if (str_set == nullptr) {
205 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
206 dim.mValue.str_value);
207 } else {
208 str_set->insert(dim.mValue.str_value);
209 protoOutput->write(
210 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 && 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 && 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 && 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 // SubMsg2 field_2 = 2;
316 // int32/float/string/int63 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 if (valueDepth > 2) {
348 ALOGE("Depth > 2 not supported");
349 return;
350 }
351
352 if (depth == valueDepth && valuePrefix == prefix) {
353 switch (dim.mValue.getType()) {
354 case INT:
355 protoOutput->write(FIELD_TYPE_INT32 | fieldNum, dim.mValue.int_value);
356 break;
357 case LONG:
358 protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
359 (long long)dim.mValue.long_value);
360 break;
361 case FLOAT:
362 protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value);
363 break;
364 case STRING: {
365 protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
366 break;
367 }
368 case STORAGE:
369 protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
370 (const char*)dim.mValue.storage_value.data(),
371 dim.mValue.storage_value.size());
372 break;
373 default:
374 break;
375 }
376 (*index)++;
377 } else if (valueDepth > depth && valuePrefix == prefix) {
378 // Writing the sub tree
379 uint64_t msg_token = 0ULL;
380 if (valueDepth == depth + 2) {
381 msg_token =
382 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
383 } else if (valueDepth == depth + 1) {
384 msg_token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
385 }
386 // Directly jump to the leaf value because the repeated position field is implied
387 // by the position of the sub msg in the parent field.
388 writeFieldValueTreeToStreamHelper(tagId, dims, index, valueDepth,
389 dim.mField.getPrefix(valueDepth), protoOutput);
390 if (msg_token != 0) {
391 protoOutput->end(msg_token);
392 }
393 } else {
394 // Done with the prev sub tree
395 return;
396 }
397 }
398 }
399
writeFieldValueTreeToStream(int tagId,const std::vector<FieldValue> & values,util::ProtoOutputStream * protoOutput)400 void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
401 util::ProtoOutputStream* protoOutput) {
402 uint64_t atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId);
403
404 size_t index = 0;
405 writeFieldValueTreeToStreamHelper(tagId, values, &index, 0, 0, protoOutput);
406 protoOutput->end(atomToken);
407 }
408
writeStateToProto(const FieldValue & state,util::ProtoOutputStream * protoOutput)409 void writeStateToProto(const FieldValue& state, util::ProtoOutputStream* protoOutput) {
410 protoOutput->write(FIELD_TYPE_INT32 | STATE_VALUE_ATOM_ID, state.mField.getTag());
411
412 switch (state.mValue.getType()) {
413 case INT:
414 protoOutput->write(FIELD_TYPE_INT32 | STATE_VALUE_CONTENTS_VALUE,
415 state.mValue.int_value);
416 break;
417 case LONG:
418 protoOutput->write(FIELD_TYPE_INT64 | STATE_VALUE_CONTENTS_GROUP_ID,
419 state.mValue.long_value);
420 break;
421 default:
422 break;
423 }
424 }
425
TimeUnitToBucketSizeInMillisGuardrailed(int uid,TimeUnit unit)426 int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
427 int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
428 if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL &&
429 uid != AID_ROOT) {
430 bucketSizeMillis = 5 * 60 * 1000LL;
431 }
432 return bucketSizeMillis;
433 }
434
TimeUnitToBucketSizeInMillis(TimeUnit unit)435 int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
436 switch (unit) {
437 case ONE_MINUTE:
438 return 60 * 1000LL;
439 case FIVE_MINUTES:
440 return 5 * 60 * 1000LL;
441 case TEN_MINUTES:
442 return 10 * 60 * 1000LL;
443 case THIRTY_MINUTES:
444 return 30 * 60 * 1000LL;
445 case ONE_HOUR:
446 return 60 * 60 * 1000LL;
447 case THREE_HOURS:
448 return 3 * 60 * 60 * 1000LL;
449 case SIX_HOURS:
450 return 6 * 60 * 60 * 1000LL;
451 case TWELVE_HOURS:
452 return 12 * 60 * 60 * 1000LL;
453 case ONE_DAY:
454 return 24 * 60 * 60 * 1000LL;
455 case ONE_WEEK:
456 return 7 * 24 * 60 * 60 * 1000LL;
457 case CTS:
458 return 1000;
459 case TIME_UNIT_UNSPECIFIED:
460 default:
461 return -1;
462 }
463 }
464
writeNonZeroStatToStream(const uint64_t fieldId,const int64_t value,util::ProtoOutputStream * protoOutput)465 void writeNonZeroStatToStream(const uint64_t fieldId, const int64_t value,
466 util::ProtoOutputStream* protoOutput) {
467 if (value != 0) {
468 protoOutput->write(fieldId, value);
469 }
470 }
471
writePullerStatsToStream(const std::pair<int,StatsdStats::PulledAtomStats> & pair,util::ProtoOutputStream * protoOutput)472 void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
473 util::ProtoOutputStream* protoOutput) {
474 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_PULLED_ATOM_STATS |
475 FIELD_COUNT_REPEATED);
476 protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_PULL_ATOM_ID, (int32_t)pair.first);
477 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL, (long long)pair.second.totalPull);
478 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL_FROM_CACHE,
479 (long long)pair.second.totalPullFromCache);
480 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_PULL_INTERVAL_SEC,
481 (long long)pair.second.minPullIntervalSec);
482 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_AVERAGE_PULL_TIME_NANOS,
483 (long long)pair.second.avgPullTimeNs);
484 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_TIME_NANOS,
485 (long long)pair.second.maxPullTimeNs);
486 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_AVERAGE_PULL_DELAY_NANOS,
487 (long long)pair.second.avgPullDelayNs);
488 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_DELAY_NANOS,
489 (long long)pair.second.maxPullDelayNs);
490 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DATA_ERROR, (long long)pair.second.dataError);
491 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_TIMEOUT,
492 (long long)pair.second.pullTimeout);
493 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_EXCEED_MAX_DELAY,
494 (long long)pair.second.pullExceedMaxDelay);
495 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_FAILED, (long long)pair.second.pullFailed);
496 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_EMPTY_DATA, (long long)pair.second.emptyData);
497 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_REGISTERED_COUNT,
498 (long long)pair.second.registeredCount);
499 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UNREGISTERED_COUNT,
500 (long long)pair.second.unregisteredCount);
501 protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_ERROR_COUNT, pair.second.atomErrorCount);
502 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BINDER_CALL_FAIL_COUNT,
503 (long long)pair.second.binderCallFailCount);
504 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UID_PROVIDER_NOT_FOUND,
505 (long long)pair.second.pullUidProviderNotFound);
506 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULLER_NOT_FOUND,
507 (long long)pair.second.pullerNotFound);
508 for (const auto& pullTimeoutMetadata : pair.second.pullTimeoutMetadata) {
509 uint64_t timeoutMetadataToken = protoOutput->start(FIELD_TYPE_MESSAGE |
510 FIELD_ID_PULL_TIMEOUT_METADATA |
511 FIELD_COUNT_REPEATED);
512 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_TIMEOUT_METADATA_UPTIME_MILLIS,
513 pullTimeoutMetadata.pullTimeoutUptimeMillis);
514 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_TIMEOUT_METADATA_ELAPSED_MILLIS,
515 pullTimeoutMetadata.pullTimeoutElapsedMillis);
516 protoOutput->end(timeoutMetadataToken);
517 }
518 protoOutput->end(token);
519 }
520
writeAtomMetricStatsToStream(const std::pair<int64_t,StatsdStats::AtomMetricStats> & pair,util::ProtoOutputStream * protoOutput)521 void writeAtomMetricStatsToStream(const std::pair<int64_t, StatsdStats::AtomMetricStats> &pair,
522 util::ProtoOutputStream *protoOutput) {
523 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_METRIC_STATS |
524 FIELD_COUNT_REPEATED);
525
526 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID, (long long)pair.first,
527 protoOutput);
528 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_HARD_DIMENSION_LIMIT_REACHED,
529 (long long)pair.second.hardDimensionLimitReached, protoOutput);
530 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_LATE_LOG_EVENT_SKIPPED,
531 (long long)pair.second.lateLogEventSkipped, protoOutput);
532 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_FORWARD_BUCKETS,
533 (long long)pair.second.skippedForwardBuckets, protoOutput);
534 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_BAD_VALUE_TYPE,
535 (long long)pair.second.badValueType, protoOutput);
536 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_CHANGE_IN_NEXT_BUCKET,
537 (long long)pair.second.conditionChangeInNextBucket, protoOutput);
538 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_INVALIDATED_BUCKET,
539 (long long)pair.second.invalidatedBucket, protoOutput);
540 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_DROPPED,
541 (long long)pair.second.bucketDropped, protoOutput);
542 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS,
543 (long long)pair.second.minBucketBoundaryDelayNs, protoOutput);
544 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS,
545 (long long)pair.second.maxBucketBoundaryDelayNs, protoOutput);
546 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_UNKNOWN_CONDITION,
547 (long long)pair.second.bucketUnknownCondition, protoOutput);
548 writeNonZeroStatToStream(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_COUNT,
549 (long long)pair.second.bucketCount, protoOutput);
550 protoOutput->end(token);
551 }
552
getElapsedRealtimeNs()553 int64_t getElapsedRealtimeNs() {
554 return ::android::elapsedRealtimeNano();
555 }
556
getElapsedRealtimeSec()557 int64_t getElapsedRealtimeSec() {
558 return ::android::elapsedRealtimeNano() / NS_PER_SEC;
559 }
560
getElapsedRealtimeMillis()561 int64_t getElapsedRealtimeMillis() {
562 return ::android::elapsedRealtime();
563 }
564
getSystemUptimeMillis()565 int64_t getSystemUptimeMillis() {
566 return ::android::uptimeMillis();
567 }
568
getWallClockNs()569 int64_t getWallClockNs() {
570 return time(nullptr) * NS_PER_SEC;
571 }
572
getWallClockSec()573 int64_t getWallClockSec() {
574 return time(nullptr);
575 }
576
getWallClockMillis()577 int64_t getWallClockMillis() {
578 return time(nullptr) * MS_PER_SEC;
579 }
580
truncateTimestampIfNecessary(const LogEvent & event)581 int64_t truncateTimestampIfNecessary(const LogEvent& event) {
582 if (event.shouldTruncateTimestamp() ||
583 (event.GetTagId() >= StatsdStats::kTimestampTruncationStartTag &&
584 event.GetTagId() <= StatsdStats::kTimestampTruncationEndTag)) {
585 return event.GetElapsedTimestampNs() / NS_PER_SEC / (5 * 60) * NS_PER_SEC * (5 * 60);
586 } else {
587 return event.GetElapsedTimestampNs();
588 }
589 }
590
NanoToMillis(const int64_t nano)591 int64_t NanoToMillis(const int64_t nano) {
592 return nano / 1000000;
593 }
594
MillisToNano(const int64_t millis)595 int64_t MillisToNano(const int64_t millis) {
596 return millis * 1000000;
597 }
598
checkPermissionForIds(const char * permission,pid_t pid,uid_t uid)599 bool checkPermissionForIds(const char* permission, pid_t pid, uid_t uid) {
600 shared_ptr<IStatsCompanionService> scs = getStatsCompanionService();
601 if (scs == nullptr) {
602 return false;
603 }
604
605 bool success;
606 ::ndk::ScopedAStatus status = scs->checkPermission(string(permission), pid, uid, &success);
607 if (!status.isOk()) {
608 return false;
609 }
610
611 return success;
612 }
613
614 } // namespace statsd
615 } // namespace os
616 } // namespace android
617