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