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