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 "Log.h"
19
20 #include "logd/LogEvent.h"
21
22 #include <android-base/stringprintf.h>
23 #include <android-modules-utils/sdk_level.h>
24 #include <android/binder_ibinder.h>
25 #include <private/android_filesystem_config.h>
26
27 #include "flags/FlagProvider.h"
28 #include "stats_annotations.h"
29 #include "stats_log_util.h"
30 #include "statslog_statsd.h"
31
32 namespace android {
33 namespace os {
34 namespace statsd {
35
36 // for TrainInfo experiment id serialization
37 const int FIELD_ID_EXPERIMENT_ID = 1;
38
39 using namespace android::util;
40 using android::base::StringPrintf;
41 using android::modules::sdklevel::IsAtLeastU;
42 using android::util::ProtoOutputStream;
43 using std::string;
44 using std::vector;
45
46 namespace {
47
getTypeId(uint8_t typeInfo)48 uint8_t getTypeId(uint8_t typeInfo) {
49 return typeInfo & 0x0F; // type id in lower 4 bytes
50 }
51
getNumAnnotations(uint8_t typeInfo)52 uint8_t getNumAnnotations(uint8_t typeInfo) {
53 return (typeInfo >> 4) & 0x0F; // num annotations in upper 4 bytes
54 }
55
56 } // namespace
57
LogEvent(int32_t uid,int32_t pid)58 LogEvent::LogEvent(int32_t uid, int32_t pid)
59 : mLogdTimestampNs(getWallClockNs()), mLogUid(uid), mLogPid(pid) {
60 }
61
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)62 LogEvent::LogEvent(const string& trainName, int64_t trainVersionCode, bool requiresStaging,
63 bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
64 const std::vector<uint8_t>& experimentIds, int32_t userId) {
65 mLogdTimestampNs = getWallClockNs();
66 mElapsedTimestampNs = getElapsedRealtimeNs();
67 mTagId = util::BINARY_PUSH_STATE_CHANGED;
68 mLogUid = AIBinder_getCallingUid();
69 mLogPid = AIBinder_getCallingPid();
70
71 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), Value(trainName)));
72 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainVersionCode)));
73 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value((int)requiresStaging)));
74 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value((int)rollbackEnabled)));
75 mValues.push_back(
76 FieldValue(Field(mTagId, getSimpleField(5)), Value((int)requiresLowLatencyMonitor)));
77 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(6)), Value(state)));
78 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(7)), Value(experimentIds)));
79 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(8)), Value(userId)));
80 }
81
LogEvent(int64_t wallClockTimestampNs,int64_t elapsedTimestampNs,const InstallTrainInfo & trainInfo)82 LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
83 const InstallTrainInfo& trainInfo) {
84 mLogdTimestampNs = wallClockTimestampNs;
85 mElapsedTimestampNs = elapsedTimestampNs;
86 mTagId = util::TRAIN_INFO;
87
88 mValues.push_back(
89 FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode)));
90 std::vector<uint8_t> experimentIdsProto;
91 writeExperimentIdsToProto(trainInfo.experimentIds, &experimentIdsProto);
92 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(experimentIdsProto)));
93 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value(trainInfo.trainName)));
94 mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value(trainInfo.status)));
95 }
96
parseInt32(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)97 void LogEvent::parseInt32(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
98 int32_t value = readNextValue<int32_t>();
99 addToValues(pos, depth, value, last);
100 parseAnnotations(numAnnotations);
101 }
102
parseInt64(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)103 void LogEvent::parseInt64(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
104 int64_t value = readNextValue<int64_t>();
105 addToValues(pos, depth, value, last);
106 parseAnnotations(numAnnotations);
107 }
108
parseString(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)109 void LogEvent::parseString(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
110 int32_t numBytes = readNextValue<int32_t>();
111 if ((uint32_t)numBytes > mRemainingLen) {
112 mValid = false;
113 return;
114 }
115
116 string value = string((char*)mBuf, numBytes);
117 mBuf += numBytes;
118 mRemainingLen -= numBytes;
119 addToValues(pos, depth, value, last);
120 parseAnnotations(numAnnotations);
121 }
122
parseFloat(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)123 void LogEvent::parseFloat(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
124 float value = readNextValue<float>();
125 addToValues(pos, depth, value, last);
126 parseAnnotations(numAnnotations);
127 }
128
parseBool(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)129 void LogEvent::parseBool(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
130 // cast to int32_t because FieldValue does not support bools
131 int32_t value = (int32_t)readNextValue<uint8_t>();
132 addToValues(pos, depth, value, last);
133 parseAnnotations(numAnnotations);
134 }
135
parseByteArray(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)136 void LogEvent::parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
137 int32_t numBytes = readNextValue<int32_t>();
138 if ((uint32_t)numBytes > mRemainingLen) {
139 mValid = false;
140 return;
141 }
142
143 vector<uint8_t> value(mBuf, mBuf + numBytes);
144 mBuf += numBytes;
145 mRemainingLen -= numBytes;
146 addToValues(pos, depth, value, last);
147 parseAnnotations(numAnnotations);
148 }
149
parseKeyValuePairs(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)150 void LogEvent::parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
151 int32_t numPairs = readNextValue<uint8_t>();
152
153 for (pos[1] = 1; pos[1] <= numPairs; pos[1]++) {
154 last[1] = (pos[1] == numPairs);
155
156 // parse key
157 pos[2] = 1;
158 parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
159
160 // parse value
161 last[2] = true;
162
163 uint8_t typeInfo = readNextValue<uint8_t>();
164 switch (getTypeId(typeInfo)) {
165 case INT32_TYPE:
166 pos[2] = 2; // pos[2] determined by index of type in KeyValuePair in atoms.proto
167 parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
168 break;
169 case INT64_TYPE:
170 pos[2] = 3;
171 parseInt64(pos, /*depth=*/2, last, /*numAnnotations=*/0);
172 break;
173 case STRING_TYPE:
174 pos[2] = 4;
175 parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
176 break;
177 case FLOAT_TYPE:
178 pos[2] = 5;
179 parseFloat(pos, /*depth=*/2, last, /*numAnnotations=*/0);
180 break;
181 default:
182 mValid = false;
183 }
184 }
185
186 parseAnnotations(numAnnotations);
187
188 pos[1] = pos[2] = 1;
189 last[1] = last[2] = false;
190 }
191
parseAttributionChain(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)192 void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last,
193 uint8_t numAnnotations) {
194 std::optional<size_t> firstUidInChainIndex = mValues.size();
195 const uint8_t numNodes = readNextValue<uint8_t>();
196
197 if (numNodes > INT8_MAX) mValid = false;
198
199 for (pos[1] = 1; pos[1] <= numNodes; pos[1]++) {
200 last[1] = (pos[1] == numNodes);
201
202 // parse uid
203 pos[2] = 1;
204 parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
205
206 // parse tag
207 pos[2] = 2;
208 last[2] = true;
209 parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
210 }
211
212 if (mValues.size() > (firstUidInChainIndex.value() + 1)) {
213 // At least one node was successfully parsed.
214 mAttributionChainStartIndex = firstUidInChainIndex;
215 mAttributionChainEndIndex = mValues.size() - 1;
216 } else {
217 firstUidInChainIndex = std::nullopt;
218 mValid = false;
219 }
220
221 if (mValid) {
222 parseAnnotations(numAnnotations, /*numElements*/ std::nullopt, firstUidInChainIndex);
223 }
224
225 pos[1] = pos[2] = 1;
226 last[1] = last[2] = false;
227 }
228
parseArray(int32_t * pos,int32_t depth,bool * last,uint8_t numAnnotations)229 void LogEvent::parseArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
230 const uint8_t numElements = readNextValue<uint8_t>();
231 const uint8_t typeInfo = readNextValue<uint8_t>();
232 const uint8_t typeId = getTypeId(typeInfo);
233
234 if (numElements > INT8_MAX) mValid = false;
235
236 for (pos[1] = 1; pos[1] <= numElements; pos[1]++) {
237 last[1] = (pos[1] == numElements);
238
239 // The top-level array is at depth 0, and all of its elements are at depth 1.
240 // Once nested fields are supported, array elements will be at top-level depth + 1.
241
242 switch (typeId) {
243 case INT32_TYPE:
244 parseInt32(pos, /*depth=*/1, last, /*numAnnotations=*/0);
245 break;
246 case INT64_TYPE:
247 parseInt64(pos, /*depth=*/1, last, /*numAnnotations=*/0);
248 break;
249 case FLOAT_TYPE:
250 parseFloat(pos, /*depth=*/1, last, /*numAnnotations=*/0);
251 break;
252 case BOOL_TYPE:
253 parseBool(pos, /*depth=*/1, last, /*numAnnotations=*/0);
254 break;
255 case STRING_TYPE:
256 parseString(pos, /*depth=*/1, last, /*numAnnotations=*/0);
257 break;
258 default:
259 mValid = false;
260 break;
261 }
262 }
263
264 parseAnnotations(numAnnotations, numElements);
265
266 pos[1] = 1;
267 last[1] = false;
268 }
269
270 // Assumes that mValues is not empty
checkPreviousValueType(Type expected)271 bool LogEvent::checkPreviousValueType(Type expected) {
272 return mValues[mValues.size() - 1].mValue.getType() == expected;
273 }
274
parseIsUidAnnotation(uint8_t annotationType,std::optional<uint8_t> numElements)275 void LogEvent::parseIsUidAnnotation(uint8_t annotationType, std::optional<uint8_t> numElements) {
276 // Need to set numElements if not an array.
277 if (!numElements) {
278 numElements = 1;
279 }
280
281 // If array is empty, skip uid parsing.
282 if (numElements == 0 && annotationType == BOOL_TYPE) {
283 readNextValue<uint8_t>();
284 return;
285 }
286
287 // Allowed types: INT, repeated INT
288 if (numElements > mValues.size() || !checkPreviousValueType(INT) ||
289 annotationType != BOOL_TYPE) {
290 VLOG("Atom ID %d error while parseIsUidAnnotation()", mTagId);
291 mValid = false;
292 return;
293 }
294
295 bool isUid = readNextValue<uint8_t>();
296 if (isUid) {
297 mNumUidFields += numElements.value();
298 }
299
300 for (int i = 1; i <= numElements; i++) {
301 mValues[mValues.size() - i].mAnnotations.setUidField(isUid);
302 }
303 }
304
parseTruncateTimestampAnnotation(uint8_t annotationType)305 void LogEvent::parseTruncateTimestampAnnotation(uint8_t annotationType) {
306 if (!mValues.empty() || annotationType != BOOL_TYPE) {
307 VLOG("Atom ID %d error while parseTruncateTimestampAnnotation()", mTagId);
308 mValid = false;
309 return;
310 }
311
312 mTruncateTimestamp = readNextValue<uint8_t>();
313 }
314
parsePrimaryFieldAnnotation(uint8_t annotationType,std::optional<uint8_t> numElements,std::optional<size_t> firstUidInChainIndex)315 void LogEvent::parsePrimaryFieldAnnotation(uint8_t annotationType,
316 std::optional<uint8_t> numElements,
317 std::optional<size_t> firstUidInChainIndex) {
318 // Allowed types: all types except for attribution chains and repeated fields.
319 if (mValues.empty() || annotationType != BOOL_TYPE || firstUidInChainIndex || numElements) {
320 VLOG("Atom ID %d error while parsePrimaryFieldAnnotation()", mTagId);
321 mValid = false;
322 return;
323 }
324
325 const bool primaryField = readNextValue<uint8_t>();
326 mValues[mValues.size() - 1].mAnnotations.setPrimaryField(primaryField);
327 }
328
parsePrimaryFieldFirstUidAnnotation(uint8_t annotationType,std::optional<size_t> firstUidInChainIndex)329 void LogEvent::parsePrimaryFieldFirstUidAnnotation(uint8_t annotationType,
330 std::optional<size_t> firstUidInChainIndex) {
331 // Allowed types: attribution chains
332 if (mValues.empty() || annotationType != BOOL_TYPE || !firstUidInChainIndex) {
333 VLOG("Atom ID %d error while parsePrimaryFieldFirstUidAnnotation()", mTagId);
334 mValid = false;
335 return;
336 }
337
338 if (mValues.size() < firstUidInChainIndex.value() + 1) { // AttributionChain is empty.
339 VLOG("Atom ID %d error while parsePrimaryFieldFirstUidAnnotation()", mTagId);
340 mValid = false;
341 android_errorWriteLog(0x534e4554, "174485572");
342 return;
343 }
344
345 const bool primaryField = readNextValue<uint8_t>();
346 mValues[firstUidInChainIndex.value()].mAnnotations.setPrimaryField(primaryField);
347 }
348
parseExclusiveStateAnnotation(uint8_t annotationType,std::optional<uint8_t> numElements)349 void LogEvent::parseExclusiveStateAnnotation(uint8_t annotationType,
350 std::optional<uint8_t> numElements) {
351 // Allowed types: BOOL
352 if (mValues.empty() || annotationType != BOOL_TYPE || !checkPreviousValueType(INT) ||
353 numElements) {
354 VLOG("Atom ID %d error while parseExclusiveStateAnnotation()", mTagId);
355 mValid = false;
356 return;
357 }
358
359 const bool exclusiveState = readNextValue<uint8_t>();
360 mExclusiveStateFieldIndex = mValues.size() - 1;
361 mValues[getExclusiveStateFieldIndex().value()].mAnnotations.setExclusiveState(exclusiveState);
362 }
363
parseTriggerStateResetAnnotation(uint8_t annotationType,std::optional<uint8_t> numElements)364 void LogEvent::parseTriggerStateResetAnnotation(uint8_t annotationType,
365 std::optional<uint8_t> numElements) {
366 // Allowed types: INT
367 if (mValues.empty() || annotationType != INT32_TYPE || !checkPreviousValueType(INT) ||
368 numElements) {
369 VLOG("Atom ID %d error while parseTriggerStateResetAnnotation()", mTagId);
370 mValid = false;
371 return;
372 }
373
374 mResetState = readNextValue<int32_t>();
375 }
376
parseStateNestedAnnotation(uint8_t annotationType,std::optional<uint8_t> numElements)377 void LogEvent::parseStateNestedAnnotation(uint8_t annotationType,
378 std::optional<uint8_t> numElements) {
379 // Allowed types: BOOL
380 if (mValues.empty() || annotationType != BOOL_TYPE || !checkPreviousValueType(INT) ||
381 numElements) {
382 VLOG("Atom ID %d error while parseStateNestedAnnotation()", mTagId);
383 mValid = false;
384 return;
385 }
386
387 bool nested = readNextValue<uint8_t>();
388 mValues[mValues.size() - 1].mAnnotations.setNested(nested);
389 }
390
parseRestrictionCategoryAnnotation(uint8_t annotationType)391 void LogEvent::parseRestrictionCategoryAnnotation(uint8_t annotationType) {
392 // Allowed types: INT, field value should be empty since this is atom-level annotation.
393 if (!mValues.empty() || annotationType != INT32_TYPE) {
394 mValid = false;
395 return;
396 }
397 int value = readNextValue<int32_t>();
398 // should be one of predefined category in StatsLog.java
399 switch (value) {
400 // Only diagnostic is currently supported for use.
401 case ASTATSLOG_RESTRICTION_CATEGORY_DIAGNOSTIC:
402 break;
403 default:
404 mValid = false;
405 return;
406 }
407 mRestrictionCategory = static_cast<StatsdRestrictionCategory>(value);
408 return;
409 }
410
parseFieldRestrictionAnnotation(uint8_t annotationType)411 void LogEvent::parseFieldRestrictionAnnotation(uint8_t annotationType) {
412 // Allowed types: BOOL
413 if (mValues.empty() || annotationType != BOOL_TYPE) {
414 mValid = false;
415 return;
416 }
417 // Read the value so that the rest of the event is correctly parsed
418 // TODO: store the field annotations once the metrics need to parse them.
419 readNextValue<uint8_t>();
420 return;
421 }
422
423 // firstUidInChainIndex is a default parameter that is only needed when parsing
424 // annotations for attribution chains.
425 // 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)426 void LogEvent::parseAnnotations(uint8_t numAnnotations, std::optional<uint8_t> numElements,
427 std::optional<size_t> firstUidInChainIndex) {
428 for (uint8_t i = 0; i < numAnnotations; i++) {
429 uint8_t annotationId = readNextValue<uint8_t>();
430 uint8_t annotationType = readNextValue<uint8_t>();
431
432 switch (annotationId) {
433 case ASTATSLOG_ANNOTATION_ID_IS_UID:
434 parseIsUidAnnotation(annotationType, numElements);
435 break;
436 case ASTATSLOG_ANNOTATION_ID_TRUNCATE_TIMESTAMP:
437 parseTruncateTimestampAnnotation(annotationType);
438 break;
439 case ASTATSLOG_ANNOTATION_ID_PRIMARY_FIELD:
440 parsePrimaryFieldAnnotation(annotationType, numElements, firstUidInChainIndex);
441 break;
442 case ASTATSLOG_ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID:
443 parsePrimaryFieldFirstUidAnnotation(annotationType, firstUidInChainIndex);
444 break;
445 case ASTATSLOG_ANNOTATION_ID_EXCLUSIVE_STATE:
446 parseExclusiveStateAnnotation(annotationType, numElements);
447 break;
448 case ASTATSLOG_ANNOTATION_ID_TRIGGER_STATE_RESET:
449 parseTriggerStateResetAnnotation(annotationType, numElements);
450 break;
451 case ASTATSLOG_ANNOTATION_ID_STATE_NESTED:
452 parseStateNestedAnnotation(annotationType, numElements);
453 break;
454 case ASTATSLOG_ANNOTATION_ID_RESTRICTION_CATEGORY:
455 if (IsAtLeastU()) {
456 parseRestrictionCategoryAnnotation(annotationType);
457 } else {
458 mValid = false;
459 }
460 break;
461 // Currently field restrictions are ignored, so we parse but do not store them.
462 case ASTATSLOG_ANNOTATION_ID_FIELD_RESTRICTION_PERIPHERAL_DEVICE_INFO:
463 case ASTATSLOG_ANNOTATION_ID_FIELD_RESTRICTION_APP_USAGE:
464 case ASTATSLOG_ANNOTATION_ID_FIELD_RESTRICTION_APP_ACTIVITY:
465 case ASTATSLOG_ANNOTATION_ID_FIELD_RESTRICTION_HEALTH_CONNECT:
466 case ASTATSLOG_ANNOTATION_ID_FIELD_RESTRICTION_ACCESSIBILITY:
467 case ASTATSLOG_ANNOTATION_ID_FIELD_RESTRICTION_SYSTEM_SEARCH:
468 case ASTATSLOG_ANNOTATION_ID_FIELD_RESTRICTION_USER_ENGAGEMENT:
469 case ASTATSLOG_ANNOTATION_ID_FIELD_RESTRICTION_AMBIENT_SENSING:
470 case ASTATSLOG_ANNOTATION_ID_FIELD_RESTRICTION_DEMOGRAPHIC_CLASSIFICATION:
471 if (IsAtLeastU()) {
472 parseFieldRestrictionAnnotation(annotationType);
473 } else {
474 mValid = false;
475 }
476 break;
477 default:
478 VLOG("Atom ID %d error while parseAnnotations() - wrong annotationId(%d)", mTagId,
479 annotationId);
480 mValid = false;
481 return;
482 }
483 }
484 }
485
parseHeader(const uint8_t * buf,size_t len)486 LogEvent::BodyBufferInfo LogEvent::parseHeader(const uint8_t* buf, size_t len) {
487 BodyBufferInfo bodyInfo;
488
489 mParsedHeaderOnly = true;
490
491 mBuf = buf;
492 mRemainingLen = (uint32_t)len;
493
494 // Beginning of buffer is OBJECT_TYPE | NUM_FIELDS | TIMESTAMP | ATOM_ID
495 uint8_t typeInfo = readNextValue<uint8_t>();
496 if (getTypeId(typeInfo) != OBJECT_TYPE) {
497 mValid = false;
498 mBuf = nullptr;
499 return bodyInfo;
500 }
501
502 uint8_t numElements = readNextValue<uint8_t>();
503 if (numElements < 2 || numElements > INT8_MAX) {
504 mValid = false;
505 mBuf = nullptr;
506 return bodyInfo;
507 }
508
509 typeInfo = readNextValue<uint8_t>();
510 if (getTypeId(typeInfo) != INT64_TYPE) {
511 mValid = false;
512 mBuf = nullptr;
513 return bodyInfo;
514 }
515 mElapsedTimestampNs = readNextValue<int64_t>();
516 numElements--;
517
518 typeInfo = readNextValue<uint8_t>();
519 if (getTypeId(typeInfo) != INT32_TYPE) {
520 mValid = false;
521 mBuf = nullptr;
522 return bodyInfo;
523 }
524 mTagId = readNextValue<int32_t>();
525 numElements--;
526
527 parseAnnotations(getNumAnnotations(typeInfo)); // atom-level annotations
528
529 bodyInfo.numElements = numElements;
530 bodyInfo.buffer = mBuf;
531 bodyInfo.bufferSize = mRemainingLen;
532
533 mBuf = nullptr;
534 return bodyInfo;
535 }
536
parseBody(const BodyBufferInfo & bodyInfo)537 bool LogEvent::parseBody(const BodyBufferInfo& bodyInfo) {
538 mParsedHeaderOnly = false;
539
540 mBuf = bodyInfo.buffer;
541 mRemainingLen = (uint32_t)bodyInfo.bufferSize;
542
543 int32_t pos[] = {1, 1, 1};
544 bool last[] = {false, false, false};
545
546 for (pos[0] = 1; pos[0] <= bodyInfo.numElements && mValid; pos[0]++) {
547 last[0] = (pos[0] == bodyInfo.numElements);
548
549 uint8_t typeInfo = readNextValue<uint8_t>();
550 uint8_t typeId = getTypeId(typeInfo);
551
552 switch (typeId) {
553 case BOOL_TYPE:
554 parseBool(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
555 break;
556 case INT32_TYPE:
557 parseInt32(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
558 break;
559 case INT64_TYPE:
560 parseInt64(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
561 break;
562 case FLOAT_TYPE:
563 parseFloat(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
564 break;
565 case BYTE_ARRAY_TYPE:
566 parseByteArray(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
567 break;
568 case STRING_TYPE:
569 parseString(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
570 break;
571 case KEY_VALUE_PAIRS_TYPE:
572 parseKeyValuePairs(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
573 break;
574 case ATTRIBUTION_CHAIN_TYPE:
575 parseAttributionChain(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
576 break;
577 case LIST_TYPE:
578 parseArray(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
579 break;
580 case ERROR_TYPE:
581 /* mErrorBitmask =*/readNextValue<int32_t>();
582 mValid = false;
583 break;
584 default:
585 mValid = false;
586 break;
587 }
588 }
589
590 if (mRemainingLen != 0) mValid = false;
591 mBuf = nullptr;
592 return mValid;
593 }
594
595 // This parsing logic is tied to the encoding scheme used in StatsEvent.java and
596 // stats_event.c
parseBuffer(const uint8_t * buf,size_t len)597 bool LogEvent::parseBuffer(const uint8_t* buf, size_t len) {
598 BodyBufferInfo bodyInfo = parseHeader(buf, len);
599
600 // emphasize intention to parse the body, however atom data could be incomplete
601 // if header/body parsing was failed due to invalid buffer content for example
602 mParsedHeaderOnly = false;
603
604 // early termination if header is invalid
605 if (!mValid) {
606 mBuf = nullptr;
607 return false;
608 }
609
610 return parseBody(bodyInfo);
611 }
612
GetLong(size_t key,status_t * err) const613 int64_t LogEvent::GetLong(size_t key, status_t* err) const {
614 // TODO(b/110561208): encapsulate the magical operations in Field struct as static functions
615 int field = getSimpleField(key);
616 for (const auto& value : mValues) {
617 if (value.mField.getField() == field) {
618 if (value.mValue.getType() == LONG) {
619 return value.mValue.long_value;
620 } else if (value.mValue.getType() == INT) {
621 return value.mValue.int_value;
622 } else {
623 *err = BAD_TYPE;
624 return 0;
625 }
626 }
627 if ((size_t)value.mField.getPosAtDepth(0) > key) {
628 break;
629 }
630 }
631
632 *err = BAD_INDEX;
633 return 0;
634 }
635
GetInt(size_t key,status_t * err) const636 int LogEvent::GetInt(size_t key, status_t* err) const {
637 int field = getSimpleField(key);
638 for (const auto& value : mValues) {
639 if (value.mField.getField() == field) {
640 if (value.mValue.getType() == INT) {
641 return value.mValue.int_value;
642 } else {
643 *err = BAD_TYPE;
644 return 0;
645 }
646 }
647 if ((size_t)value.mField.getPosAtDepth(0) > key) {
648 break;
649 }
650 }
651
652 *err = BAD_INDEX;
653 return 0;
654 }
655
GetString(size_t key,status_t * err) const656 const char* LogEvent::GetString(size_t key, status_t* err) const {
657 int field = getSimpleField(key);
658 for (const auto& value : mValues) {
659 if (value.mField.getField() == field) {
660 if (value.mValue.getType() == STRING) {
661 return value.mValue.str_value.c_str();
662 } else {
663 *err = BAD_TYPE;
664 return 0;
665 }
666 }
667 if ((size_t)value.mField.getPosAtDepth(0) > key) {
668 break;
669 }
670 }
671
672 *err = BAD_INDEX;
673 return NULL;
674 }
675
GetBool(size_t key,status_t * err) const676 bool LogEvent::GetBool(size_t key, status_t* err) const {
677 int field = getSimpleField(key);
678 for (const auto& value : mValues) {
679 if (value.mField.getField() == field) {
680 if (value.mValue.getType() == INT) {
681 return value.mValue.int_value != 0;
682 } else if (value.mValue.getType() == LONG) {
683 return value.mValue.long_value != 0;
684 } else {
685 *err = BAD_TYPE;
686 return false;
687 }
688 }
689 if ((size_t)value.mField.getPosAtDepth(0) > key) {
690 break;
691 }
692 }
693
694 *err = BAD_INDEX;
695 return false;
696 }
697
GetFloat(size_t key,status_t * err) const698 float LogEvent::GetFloat(size_t key, status_t* err) const {
699 int field = getSimpleField(key);
700 for (const auto& value : mValues) {
701 if (value.mField.getField() == field) {
702 if (value.mValue.getType() == FLOAT) {
703 return value.mValue.float_value;
704 } else {
705 *err = BAD_TYPE;
706 return 0.0;
707 }
708 }
709 if ((size_t)value.mField.getPosAtDepth(0) > key) {
710 break;
711 }
712 }
713
714 *err = BAD_INDEX;
715 return 0.0;
716 }
717
GetStorage(size_t key,status_t * err) const718 std::vector<uint8_t> LogEvent::GetStorage(size_t key, status_t* err) const {
719 int field = getSimpleField(key);
720 for (const auto& value : mValues) {
721 if (value.mField.getField() == field) {
722 if (value.mValue.getType() == STORAGE) {
723 return value.mValue.storage_value;
724 } else {
725 *err = BAD_TYPE;
726 return vector<uint8_t>();
727 }
728 }
729 if ((size_t)value.mField.getPosAtDepth(0) > key) {
730 break;
731 }
732 }
733
734 *err = BAD_INDEX;
735 return vector<uint8_t>();
736 }
737
ToString() const738 string LogEvent::ToString() const {
739 string result;
740 result += StringPrintf("{ uid(%d) %lld %lld (%d)", mLogUid, (long long)mLogdTimestampNs,
741 (long long)mElapsedTimestampNs, mTagId);
742 string annotations;
743 if (mTruncateTimestamp) {
744 annotations = "TRUNCATE_TS";
745 }
746 if (mResetState != -1) {
747 annotations += annotations.size() ? ", RESET_STATE" : "RESET_STATE";
748 }
749 if (annotations.size()) {
750 result += " [" + annotations + "] ";
751 }
752
753 if (isParsedHeaderOnly()) {
754 result += " ParsedHeaderOnly }";
755 return result;
756 }
757
758 for (const auto& value : mValues) {
759 result += StringPrintf("%#x", value.mField.getField()) + "->" + value.mValue.toString();
760 result += value.mAnnotations.toString() + " ";
761 }
762 result += " }";
763 return result;
764 }
765
ToProto(ProtoOutputStream & protoOutput) const766 void LogEvent::ToProto(ProtoOutputStream& protoOutput) const {
767 writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput);
768 }
769
hasAttributionChain(std::pair<size_t,size_t> * indexRange) const770 bool LogEvent::hasAttributionChain(std::pair<size_t, size_t>* indexRange) const {
771 if (!mAttributionChainStartIndex || !mAttributionChainEndIndex) {
772 return false;
773 }
774
775 if (nullptr != indexRange) {
776 indexRange->first = mAttributionChainStartIndex.value();
777 indexRange->second = mAttributionChainEndIndex.value();
778 }
779
780 return true;
781 }
782
writeExperimentIdsToProto(const std::vector<int64_t> & experimentIds,std::vector<uint8_t> * protoOut)783 void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds,
784 std::vector<uint8_t>* protoOut) {
785 ProtoOutputStream proto;
786 for (const auto& expId : experimentIds) {
787 proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
788 (long long)expId);
789 }
790
791 protoOut->resize(proto.size());
792 size_t pos = 0;
793 sp<ProtoReader> reader = proto.data();
794 while (reader->readBuffer() != NULL) {
795 size_t toRead = reader->currentToRead();
796 std::memcpy(protoOut->data() + pos, reader->readBuffer(), toRead);
797 pos += toRead;
798 reader->move(toRead);
799 }
800 }
801
802 } // namespace statsd
803 } // namespace os
804 } // namespace android
805