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 #define STATSD_DEBUG false // STOPSHIP if true
18 #include "logd/LogEvent.h"
19
20 #include <android-base/stringprintf.h>
21 #include <android/binder_ibinder.h>
22 #include <log/log.h>
23 #include <private/android_filesystem_config.h>
24
25 #include "annotations.h"
26 #include "stats_log_util.h"
27 #include "statslog_statsd.h"
28
29 namespace android {
30 namespace os {
31 namespace statsd {
32
33 // for TrainInfo experiment id serialization
34 const int FIELD_ID_EXPERIMENT_ID = 1;
35
36 using namespace android::util;
37 using android::base::StringPrintf;
38 using android::util::ProtoOutputStream;
39 using std::string;
40 using std::vector;
41
LogEvent(int32_t uid,int32_t pid)42 LogEvent::LogEvent(int32_t uid, int32_t pid)
43 : mLogdTimestampNs(time(nullptr)), mLogUid(uid), mLogPid(pid) {
44 }
45
LogEvent(const string & trainName,int64_t trainVersionCode,bool requiresStaging,bool rollbackEnabled,bool requiresLowLatencyMonitor,int32_t state,const std::vector<uint8_t> & experimentIds,int32_t userId)46 LogEvent::LogEvent(const string& trainName, int64_t trainVersionCode, bool requiresStaging,
47 bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
48 const std::vector<uint8_t>& experimentIds, int32_t userId) {
49 mLogdTimestampNs = getWallClockNs();
50 mElapsedTimestampNs = getElapsedRealtimeNs();
51 mTagId = util::BINARY_PUSH_STATE_CHANGED;
52 mLogUid = AIBinder_getCallingUid();
53 mLogPid = AIBinder_getCallingPid();
54
55 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), Value(trainName)));
56 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainVersionCode)));
57 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value((int)requiresStaging)));
58 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value((int)rollbackEnabled)));
59 mValues.push_back(
60 FieldValue(Field(mTagId, getSimpleField(5)), Value((int)requiresLowLatencyMonitor)));
61 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(6)), Value(state)));
62 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(7)), Value(experimentIds)));
63 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(8)), Value(userId)));
64 }
65
LogEvent(int64_t wallClockTimestampNs,int64_t elapsedTimestampNs,const InstallTrainInfo & trainInfo)66 LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
67 const InstallTrainInfo& trainInfo) {
68 mLogdTimestampNs = wallClockTimestampNs;
69 mElapsedTimestampNs = elapsedTimestampNs;
70 mTagId = util::TRAIN_INFO;
71
72 mValues.push_back(
73 FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode)));
74 std::vector<uint8_t> experimentIdsProto;
75 writeExperimentIdsToProto(trainInfo.experimentIds, &experimentIdsProto);
76 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(experimentIdsProto)));
77 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value(trainInfo.trainName)));
78 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value(trainInfo.status)));
79 }
80
parseInt32(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)81 void LogEvent::parseInt32(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
82 int32_t value = readNextValue<int32_t>();
83 addToValues(pos, depth, value, last);
84 parseAnnotations(numAnnotations);
85 }
86
parseInt64(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)87 void LogEvent::parseInt64(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
88 int64_t value = readNextValue<int64_t>();
89 addToValues(pos, depth, value, last);
90 parseAnnotations(numAnnotations);
91 }
92
parseString(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)93 void LogEvent::parseString(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
94 int32_t numBytes = readNextValue<int32_t>();
95 if ((uint32_t)numBytes > mRemainingLen) {
96 mValid = false;
97 return;
98 }
99
100 string value = string((char*)mBuf, numBytes);
101 mBuf += numBytes;
102 mRemainingLen -= numBytes;
103 addToValues(pos, depth, value, last);
104 parseAnnotations(numAnnotations);
105 }
106
parseFloat(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)107 void LogEvent::parseFloat(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
108 float value = readNextValue<float>();
109 addToValues(pos, depth, value, last);
110 parseAnnotations(numAnnotations);
111 }
112
parseBool(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)113 void LogEvent::parseBool(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
114 // cast to int32_t because FieldValue does not support bools
115 int32_t value = (int32_t)readNextValue<uint8_t>();
116 addToValues(pos, depth, value, last);
117 parseAnnotations(numAnnotations);
118 }
119
parseByteArray(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)120 void LogEvent::parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
121 int32_t numBytes = readNextValue<int32_t>();
122 if ((uint32_t)numBytes > mRemainingLen) {
123 mValid = false;
124 return;
125 }
126
127 vector<uint8_t> value(mBuf, mBuf + numBytes);
128 mBuf += numBytes;
129 mRemainingLen -= numBytes;
130 addToValues(pos, depth, value, last);
131 parseAnnotations(numAnnotations);
132 }
133
parseKeyValuePairs(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)134 void LogEvent::parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
135 int32_t numPairs = readNextValue<uint8_t>();
136
137 for (pos[1] = 1; pos[1] <= numPairs; pos[1]++) {
138 last[1] = (pos[1] == numPairs);
139
140 // parse key
141 pos[2] = 1;
142 parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
143
144 // parse value
145 last[2] = true;
146
147 uint8_t typeInfo = readNextValue<uint8_t>();
148 switch (getTypeId(typeInfo)) {
149 case INT32_TYPE:
150 pos[2] = 2; // pos[2] determined by index of type in KeyValuePair in atoms.proto
151 parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
152 break;
153 case INT64_TYPE:
154 pos[2] = 3;
155 parseInt64(pos, /*depth=*/2, last, /*numAnnotations=*/0);
156 break;
157 case STRING_TYPE:
158 pos[2] = 4;
159 parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
160 break;
161 case FLOAT_TYPE:
162 pos[2] = 5;
163 parseFloat(pos, /*depth=*/2, last, /*numAnnotations=*/0);
164 break;
165 default:
166 mValid = false;
167 }
168 }
169
170 parseAnnotations(numAnnotations);
171
172 pos[1] = pos[2] = 1;
173 last[1] = last[2] = false;
174 }
175
parseAttributionChain(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)176 void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last,
177 uint8_t numAnnotations) {
178 std::optional<size_t> firstUidInChainIndex = mValues.size();
179 const uint8_t numNodes = readNextValue<uint8_t>();
180
181 if (numNodes > INT8_MAX) mValid = false;
182
183 for (pos[1] = 1; pos[1] <= numNodes; pos[1]++) {
184 last[1] = (pos[1] == numNodes);
185
186 // parse uid
187 pos[2] = 1;
188 parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
189
190 // parse tag
191 pos[2] = 2;
192 last[2] = true;
193 parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
194 }
195
196 if (mValues.size() > (firstUidInChainIndex.value() + 1)) {
197 // At least one node was successfully parsed.
198 mAttributionChainStartIndex = firstUidInChainIndex;
199 mAttributionChainEndIndex = mValues.size() - 1;
200 } else {
201 firstUidInChainIndex = std::nullopt;
202 mValid = false;
203 }
204
205 if (mValid) {
206 parseAnnotations(numAnnotations, /*numElements*/ std::nullopt, firstUidInChainIndex);
207 }
208
209 pos[1] = pos[2] = 1;
210 last[1] = last[2] = false;
211 }
212
parseArray(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)213 void LogEvent::parseArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
214 const uint8_t numElements = readNextValue<uint8_t>();
215 const uint8_t typeInfo = readNextValue<uint8_t>();
216 const uint8_t typeId = getTypeId(typeInfo);
217
218 if (numElements > INT8_MAX) mValid = false;
219
220 for (pos[1] = 1; pos[1] <= numElements; pos[1]++) {
221 last[1] = (pos[1] == numElements);
222
223 // The top-level array is at depth 0, and all of its elements are at depth 1.
224 // Once nested fields are supported, array elements will be at top-level depth + 1.
225
226 switch (typeId) {
227 case INT32_TYPE:
228 parseInt32(pos, /*depth=*/1, last, /*numAnnotations=*/0);
229 break;
230 case INT64_TYPE:
231 parseInt64(pos, /*depth=*/1, last, /*numAnnotations=*/0);
232 break;
233 case FLOAT_TYPE:
234 parseFloat(pos, /*depth=*/1, last, /*numAnnotations=*/0);
235 break;
236 case BOOL_TYPE:
237 parseBool(pos, /*depth=*/1, last, /*numAnnotations=*/0);
238 break;
239 case STRING_TYPE:
240 parseString(pos, /*depth=*/1, last, /*numAnnotations=*/0);
241 break;
242 default:
243 mValid = false;
244 break;
245 }
246 }
247
248 parseAnnotations(numAnnotations, numElements);
249
250 pos[1] = 1;
251 last[1] = false;
252 }
253
254 // Assumes that mValues is not empty
checkPreviousValueType(Type expected)255 bool LogEvent::checkPreviousValueType(Type expected) {
256 return mValues[mValues.size() - 1].mValue.getType() == expected;
257 }
258
parseIsUidAnnotation(uint8_t annotationType,std::optional<uint8_t> numElements)259 void LogEvent::parseIsUidAnnotation(uint8_t annotationType, std::optional<uint8_t> numElements) {
260 // Need to set numElements if not an array.
261 if (!numElements) {
262 numElements = 1;
263 }
264
265 // If array is empty, skip uid parsing.
266 if (numElements == 0 && annotationType == BOOL_TYPE) {
267 readNextValue<uint8_t>();
268 return;
269 }
270
271 // Allowed types: INT, repeated INT
272 if (numElements > mValues.size() || !checkPreviousValueType(INT) ||
273 annotationType != BOOL_TYPE) {
274 mValid = false;
275 return;
276 }
277
278 bool isUid = readNextValue<uint8_t>();
279 if (isUid) {
280 mNumUidFields += numElements.value();
281 }
282
283 for (int i = 1; i <= numElements; i++) {
284 mValues[mValues.size() - i].mAnnotations.setUidField(isUid);
285 }
286 }
287
parseTruncateTimestampAnnotation(uint8_t annotationType)288 void LogEvent::parseTruncateTimestampAnnotation(uint8_t annotationType) {
289 if (!mValues.empty() || annotationType != BOOL_TYPE) {
290 mValid = false;
291 return;
292 }
293
294 mTruncateTimestamp = readNextValue<uint8_t>();
295 }
296
parsePrimaryFieldAnnotation(uint8_t annotationType,std::optional<uint8_t> numElements,std::optional<size_t> firstUidInChainIndex)297 void LogEvent::parsePrimaryFieldAnnotation(uint8_t annotationType,
298 std::optional<uint8_t> numElements,
299 std::optional<size_t> firstUidInChainIndex) {
300 // Allowed types: all types except for attribution chains and repeated fields.
301 if (mValues.empty() || annotationType != BOOL_TYPE || firstUidInChainIndex || numElements) {
302 mValid = false;
303 return;
304 }
305
306 const bool primaryField = readNextValue<uint8_t>();
307 mValues[mValues.size() - 1].mAnnotations.setPrimaryField(primaryField);
308 }
309
parsePrimaryFieldFirstUidAnnotation(uint8_t annotationType,std::optional<size_t> firstUidInChainIndex)310 void LogEvent::parsePrimaryFieldFirstUidAnnotation(uint8_t annotationType,
311 std::optional<size_t> firstUidInChainIndex) {
312 // Allowed types: attribution chains
313 if (mValues.empty() || annotationType != BOOL_TYPE || !firstUidInChainIndex) {
314 mValid = false;
315 return;
316 }
317
318 if (mValues.size() < firstUidInChainIndex.value() + 1) { // AttributionChain is empty.
319 mValid = false;
320 android_errorWriteLog(0x534e4554, "174485572");
321 return;
322 }
323
324 const bool primaryField = readNextValue<uint8_t>();
325 mValues[firstUidInChainIndex.value()].mAnnotations.setPrimaryField(primaryField);
326 }
327
parseExclusiveStateAnnotation(uint8_t annotationType,std::optional<uint8_t> numElements)328 void LogEvent::parseExclusiveStateAnnotation(uint8_t annotationType,
329 std::optional<uint8_t> numElements) {
330 // Allowed types: INT
331 if (mValues.empty() || annotationType != BOOL_TYPE || !checkPreviousValueType(INT) ||
332 numElements) {
333 mValid = false;
334 return;
335 }
336
337 const bool exclusiveState = readNextValue<uint8_t>();
338 mExclusiveStateFieldIndex = mValues.size() - 1;
339 mValues[getExclusiveStateFieldIndex().value()].mAnnotations.setExclusiveState(exclusiveState);
340 }
341
parseTriggerStateResetAnnotation(uint8_t annotationType,std::optional<uint8_t> numElements)342 void LogEvent::parseTriggerStateResetAnnotation(uint8_t annotationType,
343 std::optional<uint8_t> numElements) {
344 // Allowed types: INT
345 if (mValues.empty() || annotationType != INT32_TYPE || !checkPreviousValueType(INT) ||
346 numElements) {
347 mValid = false;
348 return;
349 }
350
351 mResetState = readNextValue<int32_t>();
352 }
353
parseStateNestedAnnotation(uint8_t annotationType,std::optional<uint8_t> numElements)354 void LogEvent::parseStateNestedAnnotation(uint8_t annotationType,
355 std::optional<uint8_t> numElements) {
356 // Allowed types: INT
357 if (mValues.empty() || annotationType != BOOL_TYPE || !checkPreviousValueType(INT) ||
358 numElements) {
359 mValid = false;
360 return;
361 }
362
363 bool nested = readNextValue<uint8_t>();
364 mValues[mValues.size() - 1].mAnnotations.setNested(nested);
365 }
366
367 // firstUidInChainIndex is a default parameter that is only needed when parsing
368 // annotations for attribution chains.
369 // numElements is a default param that is only needed when parsing annotations for repeated fields
parseAnnotations(uint8_t numAnnotations,std::optional<uint8_t> numElements,std::optional<size_t> firstUidInChainIndex)370 void LogEvent::parseAnnotations(uint8_t numAnnotations, std::optional<uint8_t> numElements,
371 std::optional<size_t> firstUidInChainIndex) {
372 for (uint8_t i = 0; i < numAnnotations; i++) {
373 uint8_t annotationId = readNextValue<uint8_t>();
374 uint8_t annotationType = readNextValue<uint8_t>();
375
376 switch (annotationId) {
377 case ANNOTATION_ID_IS_UID:
378 parseIsUidAnnotation(annotationType, numElements);
379 break;
380 case ANNOTATION_ID_TRUNCATE_TIMESTAMP:
381 parseTruncateTimestampAnnotation(annotationType);
382 break;
383 case ANNOTATION_ID_PRIMARY_FIELD:
384 parsePrimaryFieldAnnotation(annotationType, numElements, firstUidInChainIndex);
385 break;
386 case ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID:
387 parsePrimaryFieldFirstUidAnnotation(annotationType, firstUidInChainIndex);
388 break;
389 case ANNOTATION_ID_EXCLUSIVE_STATE:
390 parseExclusiveStateAnnotation(annotationType, numElements);
391 break;
392 case ANNOTATION_ID_TRIGGER_STATE_RESET:
393 parseTriggerStateResetAnnotation(annotationType, numElements);
394 break;
395 case ANNOTATION_ID_STATE_NESTED:
396 parseStateNestedAnnotation(annotationType, numElements);
397 break;
398 default:
399 mValid = false;
400 return;
401 }
402 }
403 }
404
405 // This parsing logic is tied to the encoding scheme used in StatsEvent.java and
406 // stats_event.c
parseBuffer(uint8_t * buf,size_t len)407 bool LogEvent::parseBuffer(uint8_t* buf, size_t len) {
408 mBuf = buf;
409 mRemainingLen = (uint32_t)len;
410
411 int32_t pos[] = {1, 1, 1};
412 bool last[] = {false, false, false};
413
414 // Beginning of buffer is OBJECT_TYPE | NUM_FIELDS | TIMESTAMP | ATOM_ID
415 uint8_t typeInfo = readNextValue<uint8_t>();
416 if (getTypeId(typeInfo) != OBJECT_TYPE) mValid = false;
417
418 uint8_t numElements = readNextValue<uint8_t>();
419 if (numElements < 2 || numElements > INT8_MAX) mValid = false;
420
421 typeInfo = readNextValue<uint8_t>();
422 if (getTypeId(typeInfo) != INT64_TYPE) mValid = false;
423 mElapsedTimestampNs = readNextValue<int64_t>();
424 numElements--;
425
426 typeInfo = readNextValue<uint8_t>();
427 if (getTypeId(typeInfo) != INT32_TYPE) mValid = false;
428 mTagId = readNextValue<int32_t>();
429 numElements--;
430 parseAnnotations(getNumAnnotations(typeInfo)); // atom-level annotations
431
432 for (pos[0] = 1; pos[0] <= numElements && mValid; pos[0]++) {
433 last[0] = (pos[0] == numElements);
434
435 typeInfo = readNextValue<uint8_t>();
436 uint8_t typeId = getTypeId(typeInfo);
437
438 switch (typeId) {
439 case BOOL_TYPE:
440 parseBool(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
441 break;
442 case INT32_TYPE:
443 parseInt32(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
444 break;
445 case INT64_TYPE:
446 parseInt64(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
447 break;
448 case FLOAT_TYPE:
449 parseFloat(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
450 break;
451 case BYTE_ARRAY_TYPE:
452 parseByteArray(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
453 break;
454 case STRING_TYPE:
455 parseString(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
456 break;
457 case KEY_VALUE_PAIRS_TYPE:
458 parseKeyValuePairs(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
459 break;
460 case ATTRIBUTION_CHAIN_TYPE:
461 parseAttributionChain(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
462 break;
463 case LIST_TYPE:
464 parseArray(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
465 break;
466 case ERROR_TYPE:
467 /* mErrorBitmask =*/ readNextValue<int32_t>();
468 mValid = false;
469 break;
470 default:
471 mValid = false;
472 break;
473 }
474 }
475
476 if (mRemainingLen != 0) mValid = false;
477 mBuf = nullptr;
478 return mValid;
479 }
480
getTypeId(uint8_t typeInfo)481 uint8_t LogEvent::getTypeId(uint8_t typeInfo) {
482 return typeInfo & 0x0F; // type id in lower 4 bytes
483 }
484
getNumAnnotations(uint8_t typeInfo)485 uint8_t LogEvent::getNumAnnotations(uint8_t typeInfo) {
486 return (typeInfo >> 4) & 0x0F; // num annotations in upper 4 bytes
487 }
488
GetLong(size_t key,status_t * err) const489 int64_t LogEvent::GetLong(size_t key, status_t* err) const {
490 // TODO(b/110561208): encapsulate the magical operations in Field struct as static functions
491 int field = getSimpleField(key);
492 for (const auto& value : mValues) {
493 if (value.mField.getField() == field) {
494 if (value.mValue.getType() == LONG) {
495 return value.mValue.long_value;
496 } else if (value.mValue.getType() == INT) {
497 return value.mValue.int_value;
498 } else {
499 *err = BAD_TYPE;
500 return 0;
501 }
502 }
503 if ((size_t)value.mField.getPosAtDepth(0) > key) {
504 break;
505 }
506 }
507
508 *err = BAD_INDEX;
509 return 0;
510 }
511
GetInt(size_t key,status_t * err) const512 int LogEvent::GetInt(size_t key, status_t* err) const {
513 int field = getSimpleField(key);
514 for (const auto& value : mValues) {
515 if (value.mField.getField() == field) {
516 if (value.mValue.getType() == INT) {
517 return value.mValue.int_value;
518 } else {
519 *err = BAD_TYPE;
520 return 0;
521 }
522 }
523 if ((size_t)value.mField.getPosAtDepth(0) > key) {
524 break;
525 }
526 }
527
528 *err = BAD_INDEX;
529 return 0;
530 }
531
GetString(size_t key,status_t * err) const532 const char* LogEvent::GetString(size_t key, status_t* err) const {
533 int field = getSimpleField(key);
534 for (const auto& value : mValues) {
535 if (value.mField.getField() == field) {
536 if (value.mValue.getType() == STRING) {
537 return value.mValue.str_value.c_str();
538 } else {
539 *err = BAD_TYPE;
540 return 0;
541 }
542 }
543 if ((size_t)value.mField.getPosAtDepth(0) > key) {
544 break;
545 }
546 }
547
548 *err = BAD_INDEX;
549 return NULL;
550 }
551
GetBool(size_t key,status_t * err) const552 bool LogEvent::GetBool(size_t key, status_t* err) const {
553 int field = getSimpleField(key);
554 for (const auto& value : mValues) {
555 if (value.mField.getField() == field) {
556 if (value.mValue.getType() == INT) {
557 return value.mValue.int_value != 0;
558 } else if (value.mValue.getType() == LONG) {
559 return value.mValue.long_value != 0;
560 } else {
561 *err = BAD_TYPE;
562 return false;
563 }
564 }
565 if ((size_t)value.mField.getPosAtDepth(0) > key) {
566 break;
567 }
568 }
569
570 *err = BAD_INDEX;
571 return false;
572 }
573
GetFloat(size_t key,status_t * err) const574 float LogEvent::GetFloat(size_t key, status_t* err) const {
575 int field = getSimpleField(key);
576 for (const auto& value : mValues) {
577 if (value.mField.getField() == field) {
578 if (value.mValue.getType() == FLOAT) {
579 return value.mValue.float_value;
580 } else {
581 *err = BAD_TYPE;
582 return 0.0;
583 }
584 }
585 if ((size_t)value.mField.getPosAtDepth(0) > key) {
586 break;
587 }
588 }
589
590 *err = BAD_INDEX;
591 return 0.0;
592 }
593
GetStorage(size_t key,status_t * err) const594 std::vector<uint8_t> LogEvent::GetStorage(size_t key, status_t* err) const {
595 int field = getSimpleField(key);
596 for (const auto& value : mValues) {
597 if (value.mField.getField() == field) {
598 if (value.mValue.getType() == STORAGE) {
599 return value.mValue.storage_value;
600 } else {
601 *err = BAD_TYPE;
602 return vector<uint8_t>();
603 }
604 }
605 if ((size_t)value.mField.getPosAtDepth(0) > key) {
606 break;
607 }
608 }
609
610 *err = BAD_INDEX;
611 return vector<uint8_t>();
612 }
613
ToString() const614 string LogEvent::ToString() const {
615 string result;
616 result += StringPrintf("{ uid(%d) %lld %lld (%d)", mLogUid, (long long)mLogdTimestampNs,
617 (long long)mElapsedTimestampNs, mTagId);
618 for (const auto& value : mValues) {
619 result +=
620 StringPrintf("%#x", value.mField.getField()) + "->" + value.mValue.toString() + " ";
621 }
622 result += " }";
623 return result;
624 }
625
ToProto(ProtoOutputStream & protoOutput) const626 void LogEvent::ToProto(ProtoOutputStream& protoOutput) const {
627 writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput);
628 }
629
hasAttributionChain(std::pair<size_t,size_t> * indexRange) const630 bool LogEvent::hasAttributionChain(std::pair<size_t, size_t>* indexRange) const {
631 if (!mAttributionChainStartIndex || !mAttributionChainEndIndex) {
632 return false;
633 }
634
635 if (nullptr != indexRange) {
636 indexRange->first = mAttributionChainStartIndex.value();
637 indexRange->second = mAttributionChainEndIndex.value();
638 }
639
640 return true;
641 }
642
writeExperimentIdsToProto(const std::vector<int64_t> & experimentIds,std::vector<uint8_t> * protoOut)643 void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds,
644 std::vector<uint8_t>* protoOut) {
645 ProtoOutputStream proto;
646 for (const auto& expId : experimentIds) {
647 proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
648 (long long)expId);
649 }
650
651 protoOut->resize(proto.size());
652 size_t pos = 0;
653 sp<ProtoReader> reader = proto.data();
654 while (reader->readBuffer() != NULL) {
655 size_t toRead = reader->currentToRead();
656 std::memcpy(protoOut->data() + pos, reader->readBuffer(), toRead);
657 pos += toRead;
658 reader->move(toRead);
659 }
660 }
661
662 } // namespace statsd
663 } // namespace os
664 } // namespace android
665