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