• 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 #pragma once
18 
19 #include <android/util/ProtoOutputStream.h>
20 #include <private/android_logger.h>
21 
22 #include <optional>
23 #include <string>
24 #include <vector>
25 
26 #include "FieldValue.h"
27 
28 namespace android {
29 namespace os {
30 namespace statsd {
31 
32 // stats_event.h socket types. Keep in sync.
33 /* ERRORS */
34 #define ERROR_NO_TIMESTAMP 0x1
35 #define ERROR_NO_ATOM_ID 0x2
36 #define ERROR_OVERFLOW 0x4
37 #define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
38 #define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
39 #define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
40 #define ERROR_INVALID_ANNOTATION_ID 0x40
41 #define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
42 #define ERROR_TOO_MANY_ANNOTATIONS 0x100
43 #define ERROR_TOO_MANY_FIELDS 0x200
44 #define ERROR_INVALID_VALUE_TYPE 0x400
45 #define ERROR_STRING_NOT_NULL_TERMINATED 0x800
46 #define ERROR_ATOM_ID_INVALID_POSITION 0x2000
47 #define ERROR_LIST_TOO_LONG 0x4000
48 
49 /* TYPE IDS */
50 #define INT32_TYPE 0x00
51 #define INT64_TYPE 0x01
52 #define STRING_TYPE 0x02
53 #define LIST_TYPE 0x03
54 #define FLOAT_TYPE 0x04
55 #define BOOL_TYPE 0x05
56 #define BYTE_ARRAY_TYPE 0x06
57 #define OBJECT_TYPE 0x07
58 #define KEY_VALUE_PAIRS_TYPE 0x08
59 #define ATTRIBUTION_CHAIN_TYPE 0x09
60 #define ERROR_TYPE 0x0F
61 
62 struct InstallTrainInfo {
63     int64_t trainVersionCode;
64     std::string trainName;
65     int32_t status;
66     std::vector<int64_t> experimentIds;
67     bool requiresStaging;
68     bool rollbackEnabled;
69     bool requiresLowLatencyMonitor;
70 };
71 
72 /**
73  * This class decodes the structured, serialized encoding of an atom into a
74  * vector of FieldValues.
75  */
76 class LogEvent {
77 public:
78     /**
79      * \param uid user id of the logging caller
80      * \param pid process id of the logging caller
81      */
82     explicit LogEvent(int32_t uid, int32_t pid);
83 
84     /**
85      * Parses the atomId, timestamp, and vector of values from a buffer
86      * containing the StatsEvent/AStatsEvent encoding of an atom.
87      *
88      * \param buf a buffer that begins at the start of the serialized atom (it
89      * should not include the android_log_header_t or the StatsEventTag)
90      * \param len size of the buffer
91      *
92      * \return success of the initialization
93      */
94     bool parseBuffer(uint8_t* buf, size_t len);
95 
96     // Constructs a BinaryPushStateChanged LogEvent from API call.
97     explicit LogEvent(const std::string& trainName, int64_t trainVersionCode, bool requiresStaging,
98                       bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
99                       const std::vector<uint8_t>& experimentIds, int32_t userId);
100 
101     explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
102                       const InstallTrainInfo& installTrainInfo);
103 
~LogEvent()104     ~LogEvent() {}
105 
106     /**
107      * Get the timestamp associated with this event.
108      */
GetLogdTimestampNs()109     inline int64_t GetLogdTimestampNs() const { return mLogdTimestampNs; }
GetElapsedTimestampNs()110     inline int64_t GetElapsedTimestampNs() const { return mElapsedTimestampNs; }
111 
112     /**
113      * Get the tag for this event.
114      */
GetTagId()115     inline int GetTagId() const { return mTagId; }
116 
117     /**
118      * Get the uid of the logging client.
119      * Returns -1 if the uid is unknown/has not been set.
120      */
GetUid()121     inline int32_t GetUid() const { return mLogUid; }
122 
123     /**
124      * Get the pid of the logging client.
125      * Returns -1 if the pid is unknown/has not been set.
126      */
GetPid()127     inline int32_t GetPid() const { return mLogPid; }
128 
129     /**
130      * Get the nth value, starting at 1.
131      *
132      * Returns BAD_INDEX if the index is larger than the number of elements.
133      * Returns BAD_TYPE if the index is available but the data is the wrong type.
134      */
135     int64_t GetLong(size_t key, status_t* err) const;
136     int GetInt(size_t key, status_t* err) const;
137     const char* GetString(size_t key, status_t* err) const;
138     bool GetBool(size_t key, status_t* err) const;
139     float GetFloat(size_t key, status_t* err) const;
140     std::vector<uint8_t> GetStorage(size_t key, status_t* err) const;
141 
142     /**
143      * Return a string representation of this event.
144      */
145     std::string ToString() const;
146 
147     /**
148      * Write this object to a ProtoOutputStream.
149      */
150     void ToProto(android::util::ProtoOutputStream& out) const;
151 
152     /**
153      * Set elapsed timestamp if the original timestamp is missing.
154      */
setElapsedTimestampNs(int64_t timestampNs)155     void setElapsedTimestampNs(int64_t timestampNs) {
156         mElapsedTimestampNs = timestampNs;
157     }
158 
159     /**
160      * Set the timestamp if the original logd timestamp is missing.
161      */
setLogdWallClockTimestampNs(int64_t timestampNs)162     void setLogdWallClockTimestampNs(int64_t timestampNs) {
163         mLogdTimestampNs = timestampNs;
164     }
165 
size()166     inline int size() const {
167         return mValues.size();
168     }
169 
getValues()170     const std::vector<FieldValue>& getValues() const {
171         return mValues;
172     }
173 
getMutableValues()174     std::vector<FieldValue>* getMutableValues() {
175         return &mValues;
176     }
177 
178     // Default value = false
shouldTruncateTimestamp()179     inline bool shouldTruncateTimestamp() const {
180         return mTruncateTimestamp;
181     }
182 
getNumUidFields()183     inline uint8_t getNumUidFields() const {
184         return mNumUidFields;
185     }
186 
187     // Returns whether this LogEvent has an AttributionChain.
188     // If it does and indexRange is not a nullptr, populate indexRange with the start and end index
189     // of the AttributionChain within mValues.
190     bool hasAttributionChain(std::pair<size_t, size_t>* indexRange = nullptr) const;
191 
192     // Returns the index of the exclusive state field within the FieldValues vector if
193     // an exclusive state exists. If there is no exclusive state field, returns -1.
194     //
195     // If the index within the atom definition is desired, do the following:
196     //    const std::optional<size_t>& vectorIndex = LogEvent.getExclusiveStateFieldIndex();
197     //    if (!vectorIndex) {
198     //        FieldValue& v = LogEvent.getValues()[vectorIndex.value()];
199     //        int atomIndex = v.mField.getPosAtDepth(0);
200     //    }
201     // Note that atomIndex is 1-indexed.
getExclusiveStateFieldIndex()202     inline std::optional<size_t> getExclusiveStateFieldIndex() const {
203         return mExclusiveStateFieldIndex;
204     }
205 
206     // If a reset state is not sent in the StatsEvent, returns -1. Note that a
207     // reset state is sent if and only if a reset should be triggered.
getResetState()208     inline int getResetState() const {
209         return mResetState;
210     }
211 
212     template <class T>
updateValue(size_t key,T & value,Type type)213     status_t updateValue(size_t key, T& value, Type type) {
214         int field = getSimpleField(key);
215         for (auto& fieldValue : mValues) {
216             if (fieldValue.mField.getField() == field) {
217                 if (fieldValue.mValue.getType() == type) {
218                     fieldValue.mValue = Value(value);
219                    return OK;
220                } else {
221                    return BAD_TYPE;
222                 }
223             }
224         }
225         return BAD_INDEX;
226     }
227 
isValid()228     bool isValid() const {
229         return mValid;
230     }
231 
232     /**
233      * Only use this if copy is absolutely needed.
234      */
235     LogEvent(const LogEvent&) = default;
236 
237 private:
238     void parseInt32(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
239     void parseInt64(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
240     void parseString(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
241     void parseFloat(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
242     void parseBool(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
243     void parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
244     void parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
245     void parseAttributionChain(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
246     void parseArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
247 
248     void parseAnnotations(uint8_t numAnnotations, std::optional<uint8_t> numElements = std::nullopt,
249                           std::optional<size_t> firstUidInChainIndex = std::nullopt);
250     void parseIsUidAnnotation(uint8_t annotationType, std::optional<uint8_t> numElements);
251     void parseTruncateTimestampAnnotation(uint8_t annotationType);
252     void parsePrimaryFieldAnnotation(uint8_t annotationType, std::optional<uint8_t> numElements,
253                                      std::optional<size_t> firstUidInChainIndex);
254     void parsePrimaryFieldFirstUidAnnotation(uint8_t annotationType,
255                                              std::optional<size_t> firstUidInChainIndex);
256     void parseExclusiveStateAnnotation(uint8_t annotationType, std::optional<uint8_t> numElements);
257     void parseTriggerStateResetAnnotation(uint8_t annotationType,
258                                           std::optional<uint8_t> numElements);
259     void parseStateNestedAnnotation(uint8_t annotationType, std::optional<uint8_t> numElements);
260     bool checkPreviousValueType(Type expected);
261 
262     /**
263      * The below two variables are only valid during the execution of
264      * parseBuffer. There are no guarantees about the state of these variables
265      * before/after.
266      */
267     uint8_t* mBuf;
268     uint32_t mRemainingLen; // number of valid bytes left in the buffer being parsed
269 
270     bool mValid = true; // stores whether the event we received from the socket is valid
271 
272     /**
273      * Side-effects:
274      *    If there is enough space in buffer to read value of type T
275      *        - move mBuf past the value that was just read
276      *        - decrement mRemainingLen by size of T
277      *    Else
278      *        - set mValid to false
279      */
280     template <class T>
readNextValue()281     T readNextValue() {
282         T value;
283         if (mRemainingLen < sizeof(T)) {
284             mValid = false;
285             value = 0; // all primitive types can successfully cast 0
286         } else {
287             // When alignof(T) == 1, hopefully the compiler can optimize away
288             // this conditional as always true.
289             if ((reinterpret_cast<uintptr_t>(mBuf) % alignof(T)) == 0) {
290                 // We're properly aligned, and can safely make this assignment.
291                 value = *((T*)mBuf);
292             } else {
293                 // We need to use memcpy.  It's slower, but safe.
294                 memcpy(&value, mBuf, sizeof(T));
295             }
296             mBuf += sizeof(T);
297             mRemainingLen -= sizeof(T);
298         }
299         return value;
300     }
301 
302     template <class T>
addToValues(int32_t * pos,int32_t depth,T & value,bool * last)303     void addToValues(int32_t* pos, int32_t depth, T& value, bool* last) {
304         Field f = Field(mTagId, pos, depth);
305         // only decorate last position for depths with repeated fields (depth 1)
306         if (depth > 0 && last[1]) f.decorateLastPos(1);
307 
308         Value v = Value(value);
309         mValues.push_back(FieldValue(f, v));
310     }
311 
312     uint8_t getTypeId(uint8_t typeInfo);
313     uint8_t getNumAnnotations(uint8_t typeInfo);
314 
315     // The items are naturally sorted in DFS order as we read them. this allows us to do fast
316     // matching.
317     std::vector<FieldValue> mValues;
318 
319     // The timestamp set by the logd.
320     int64_t mLogdTimestampNs;
321 
322     // The elapsed timestamp set by statsd log writer.
323     int64_t mElapsedTimestampNs;
324 
325     // The atom tag of the event (defaults to 0 if client does not
326     // appropriately set the atom id).
327     int mTagId = 0;
328 
329     // The uid of the logging client (defaults to -1).
330     int32_t mLogUid = -1;
331 
332     // The pid of the logging client (defaults to -1).
333     int32_t mLogPid = -1;
334 
335     // Annotations
336     bool mTruncateTimestamp = false;
337     int mResetState = -1;
338 
339     size_t mNumUidFields = 0;
340 
341     std::optional<size_t> mAttributionChainStartIndex;
342     std::optional<size_t> mAttributionChainEndIndex;
343     std::optional<size_t> mExclusiveStateFieldIndex;
344 };
345 
346 void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
347 
348 }  // namespace statsd
349 }  // namespace os
350 }  // namespace android
351