blob: 53fb5d93e3acdcf4da5fce2c5baa7678e0a63485 [file] [log] [blame]
Joe Onoratoc4dfae52017-10-17 23:38:21 -07001/*
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
Yao Chen8a8d16c2018-02-08 14:50:40 -080019#include "FieldValue.h"
Joe Onoratoc4dfae52017-10-17 23:38:21 -070020
Yao Chen5110bed2017-10-23 12:50:02 -070021#include <android/util/ProtoOutputStream.h>
Yao Chen80235402017-11-13 20:42:25 -080022#include <private/android_logger.h>
Joe Onoratoc4dfae52017-10-17 23:38:21 -070023
24#include <string>
25#include <vector>
26
27namespace android {
28namespace os {
29namespace statsd {
30
Chenjie Yu97dbb202019-02-13 16:42:04 -080031struct InstallTrainInfo {
32 int64_t trainVersionCode;
Muhammad Qureshif4ca8242019-03-01 09:20:15 -080033 std::string trainName;
34 int32_t status;
Jeff Hamiltonfa2f91c2019-03-22 00:25:02 -040035 std::vector<int64_t> experimentIds;
Jonathan Nguyen703c42f2020-02-04 15:54:26 -080036 bool requiresStaging;
37 bool rollbackEnabled;
38 bool requiresLowLatencyMonitor;
Chenjie Yu97dbb202019-02-13 16:42:04 -080039};
Jeff Hamiltonfa2f91c2019-03-22 00:25:02 -040040
Joe Onoratoc4dfae52017-10-17 23:38:21 -070041/**
Ruchir Rastogidfd63d42020-02-20 17:54:13 -080042 * This class decodes the structured, serialized encoding of an atom into a
43 * vector of FieldValues.
Joe Onoratoc4dfae52017-10-17 23:38:21 -070044 */
45class LogEvent {
46public:
47 /**
Ruchir Rastogidfd63d42020-02-20 17:54:13 -080048 * \param uid user id of the logging caller
49 * \param pid process id of the logging caller
Joe Onoratoc4dfae52017-10-17 23:38:21 -070050 */
Ruchir Rastogidfd63d42020-02-20 17:54:13 -080051 explicit LogEvent(int32_t uid, int32_t pid);
52
53 /**
54 * Parses the atomId, timestamp, and vector of values from a buffer
55 * containing the StatsEvent/AStatsEvent encoding of an atom.
56 *
57 * \param buf a buffer that begins at the start of the serialized atom (it
58 * should not include the android_log_header_t or the StatsEventTag)
59 * \param len size of the buffer
60 *
61 * \return success of the initialization
62 */
63 bool parseBuffer(uint8_t* buf, size_t len);
64
Chenjie Yu6b1667c2019-01-18 10:09:33 -080065 // Constructs a BinaryPushStateChanged LogEvent from API call.
66 explicit LogEvent(const std::string& trainName, int64_t trainVersionCode, bool requiresStaging,
67 bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
68 const std::vector<uint8_t>& experimentIds, int32_t userId);
69
Howard Roa46b6582018-09-18 16:45:02 -070070 explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
Chenjie Yu97dbb202019-02-13 16:42:04 -080071 const InstallTrainInfo& installTrainInfo);
72
Ruchir Rastogi48dbf832020-04-20 16:50:46 -070073 ~LogEvent() {}
Joe Onoratoc4dfae52017-10-17 23:38:21 -070074
75 /**
76 * Get the timestamp associated with this event.
77 */
Yangster-mac330af582018-02-08 15:24:38 -080078 inline int64_t GetLogdTimestampNs() const { return mLogdTimestampNs; }
79 inline int64_t GetElapsedTimestampNs() const { return mElapsedTimestampNs; }
Joe Onoratoc4dfae52017-10-17 23:38:21 -070080
81 /**
82 * Get the tag for this event.
83 */
Yangster-mac68985802018-01-21 10:05:09 -080084 inline int GetTagId() const { return mTagId; }
Joe Onoratoc4dfae52017-10-17 23:38:21 -070085
Ruchir Rastogiab71ef02020-01-30 01:24:50 -080086 /**
87 * Get the uid of the logging client.
88 * Returns -1 if the uid is unknown/has not been set.
89 */
90 inline int32_t GetUid() const { return mLogUid; }
91
92 /**
93 * Get the pid of the logging client.
94 * Returns -1 if the pid is unknown/has not been set.
95 */
96 inline int32_t GetPid() const { return mLogPid; }
Yao Chend10f7b12017-12-18 12:53:50 -080097
Joe Onoratoc4dfae52017-10-17 23:38:21 -070098 /**
99 * Get the nth value, starting at 1.
100 *
101 * Returns BAD_INDEX if the index is larger than the number of elements.
102 * Returns BAD_TYPE if the index is available but the data is the wrong type.
103 */
104 int64_t GetLong(size_t key, status_t* err) const;
Chenjie Yu80f91122018-01-31 20:24:50 -0800105 int GetInt(size_t key, status_t* err) const;
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700106 const char* GetString(size_t key, status_t* err) const;
107 bool GetBool(size_t key, status_t* err) const;
108 float GetFloat(size_t key, status_t* err) const;
Jonathan Nguyena0e6de12020-01-28 18:33:55 -0800109 std::vector<uint8_t> GetStorage(size_t key, status_t* err) const;
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700110
111 /**
112 * Return a string representation of this event.
113 */
Yao Chen9c1debe2018-02-19 14:39:19 -0800114 std::string ToString() const;
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700115
116 /**
Yao Chen5110bed2017-10-23 12:50:02 -0700117 * Write this object to a ProtoOutputStream.
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700118 */
Yao Chen5110bed2017-10-23 12:50:02 -0700119 void ToProto(android::util::ProtoOutputStream& out) const;
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700120
David Chen1481fe12017-10-16 13:16:34 -0700121 /**
Yangster-mac330af582018-02-08 15:24:38 -0800122 * Set elapsed timestamp if the original timestamp is missing.
Chenjie Yua7259ab2017-12-10 08:31:05 -0800123 */
Yangster-mac330af582018-02-08 15:24:38 -0800124 void setElapsedTimestampNs(int64_t timestampNs) {
125 mElapsedTimestampNs = timestampNs;
126 }
127
128 /**
129 * Set the timestamp if the original logd timestamp is missing.
130 */
131 void setLogdWallClockTimestampNs(int64_t timestampNs) {
132 mLogdTimestampNs = timestampNs;
133 }
Chenjie Yua7259ab2017-12-10 08:31:05 -0800134
Yangster-mac20877162017-12-22 17:19:39 -0800135 inline int size() const {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800136 return mValues.size();
Chenjie Yud9dfda72017-12-11 17:41:20 -0800137 }
138
Yao Chen8a8d16c2018-02-08 14:50:40 -0800139 const std::vector<FieldValue>& getValues() const {
140 return mValues;
141 }
Yangster-macd40053e2018-01-09 16:29:22 -0800142
Yao Chen8a8d16c2018-02-08 14:50:40 -0800143 std::vector<FieldValue>* getMutableValues() {
144 return &mValues;
145 }
Yangster-mac20877162017-12-22 17:19:39 -0800146
Ruchir Rastogi13296512020-03-24 10:59:49 -0700147 // Default value = false
Muhammad Qureshia7de0002020-04-15 11:34:35 -0700148 inline bool shouldTruncateTimestamp() const {
Ruchir Rastogi13296512020-03-24 10:59:49 -0700149 return mTruncateTimestamp;
150 }
151
152 // Returns the index of the uid field within the FieldValues vector if the
153 // uid exists. If there is no uid field, returns -1.
154 //
155 // If the index within the atom definition is desired, do the following:
156 // int vectorIndex = LogEvent.getUidFieldIndex();
157 // if (vectorIndex != -1) {
158 // FieldValue& v = LogEvent.getValues()[vectorIndex];
159 // int atomIndex = v.mField.getPosAtDepth(0);
160 // }
161 // Note that atomIndex is 1-indexed.
162 inline int getUidFieldIndex() {
Ruchir Rastogi1e8c57f2020-04-27 17:41:58 -0700163 return static_cast<int>(mUidFieldIndex);
Ruchir Rastogi13296512020-03-24 10:59:49 -0700164 }
165
Muhammad Qureshi83aaa662020-04-21 12:51:36 -0700166 // Returns whether this LogEvent has an AttributionChain.
167 // If it does and indexRange is not a nullptr, populate indexRange with the start and end index
168 // of the AttributionChain within mValues.
169 bool hasAttributionChain(std::pair<int, int>* indexRange = nullptr) const;
Ruchir Rastogi13296512020-03-24 10:59:49 -0700170
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700171 // Returns the index of the exclusive state field within the FieldValues vector if
172 // an exclusive state exists. If there is no exclusive state field, returns -1.
173 //
174 // If the index within the atom definition is desired, do the following:
175 // int vectorIndex = LogEvent.getExclusiveStateFieldIndex();
176 // if (vectorIndex != -1) {
177 // FieldValue& v = LogEvent.getValues()[vectorIndex];
178 // int atomIndex = v.mField.getPosAtDepth(0);
179 // }
180 // Note that atomIndex is 1-indexed.
181 inline int getExclusiveStateFieldIndex() const {
Ruchir Rastogi1e8c57f2020-04-27 17:41:58 -0700182 return static_cast<int>(mExclusiveStateFieldIndex);
Muhammad Qureshibfc4bdb2020-04-08 06:26:49 -0700183 }
184
Ruchir Rastogi48dbf832020-04-20 16:50:46 -0700185 // If a reset state is not sent in the StatsEvent, returns -1. Note that a
186 // reset state is sent if and only if a reset should be triggered.
187 inline int getResetState() const {
188 return mResetState;
189 }
190
Chenjie Yu0bd73db2018-12-16 07:37:04 -0800191 inline LogEvent makeCopy() {
192 return LogEvent(*this);
193 }
194
Jonathan Nguyena0e6de12020-01-28 18:33:55 -0800195 template <class T>
196 status_t updateValue(size_t key, T& value, Type type) {
197 int field = getSimpleField(key);
198 for (auto& fieldValue : mValues) {
199 if (fieldValue.mField.getField() == field) {
200 if (fieldValue.mValue.getType() == type) {
201 fieldValue.mValue = Value(value);
202 return OK;
203 } else {
204 return BAD_TYPE;
205 }
206 }
207 }
208 return BAD_INDEX;
209 }
210
Ruchir Rastogi07f7adb2020-04-16 17:46:12 -0700211 bool isValid() const {
212 return mValid;
213 }
214
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700215private:
216 /**
Chenjie Yu0bd73db2018-12-16 07:37:04 -0800217 * Only use this if copy is absolutely needed.
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700218 */
Chih-Hung Hsieh3227aab2018-12-20 13:42:28 -0800219 LogEvent(const LogEvent&);
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700220
Ruchir Rastogi84eb44b2020-03-12 18:48:48 -0700221 void parseInt32(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
222 void parseInt64(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
223 void parseString(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
224 void parseFloat(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
225 void parseBool(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
226 void parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
227 void parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
228 void parseAttributionChain(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
Ruchir Rastogi13296512020-03-24 10:59:49 -0700229
230 void parseAnnotations(uint8_t numAnnotations, int firstUidInChainIndex = -1);
231 void parseIsUidAnnotation(uint8_t annotationType);
232 void parseTruncateTimestampAnnotation(uint8_t annotationType);
Muhammad Qureshi3f9c3302020-04-01 16:11:53 -0700233 void parsePrimaryFieldAnnotation(uint8_t annotationType);
234 void parsePrimaryFieldFirstUidAnnotation(uint8_t annotationType, int firstUidInChainIndex);
235 void parseExclusiveStateAnnotation(uint8_t annotationType);
236 void parseTriggerStateResetAnnotation(uint8_t annotationType);
Ruchir Rastogi13296512020-03-24 10:59:49 -0700237 void parseStateNestedAnnotation(uint8_t annotationType);
Ruchir Rastogiffa34f02020-04-04 15:30:11 -0700238 bool checkPreviousValueType(Type expected);
Ruchir Rastogi1736ba42019-11-04 14:37:13 -0800239
240 /**
Ruchir Rastogi07f7adb2020-04-16 17:46:12 -0700241 * The below two variables are only valid during the execution of
Ruchir Rastogidfd63d42020-02-20 17:54:13 -0800242 * parseBuffer. There are no guarantees about the state of these variables
243 * before/after.
Ruchir Rastogi1736ba42019-11-04 14:37:13 -0800244 */
245 uint8_t* mBuf;
Ruchir Rastogi1736ba42019-11-04 14:37:13 -0800246 uint32_t mRemainingLen; // number of valid bytes left in the buffer being parsed
Ruchir Rastogi07f7adb2020-04-16 17:46:12 -0700247
Ruchir Rastogi1736ba42019-11-04 14:37:13 -0800248 bool mValid = true; // stores whether the event we received from the socket is valid
249
250 /**
251 * Side-effects:
252 * If there is enough space in buffer to read value of type T
253 * - move mBuf past the value that was just read
254 * - decrement mRemainingLen by size of T
255 * Else
256 * - set mValid to false
257 */
258 template <class T>
259 T readNextValue() {
260 T value;
261 if (mRemainingLen < sizeof(T)) {
262 mValid = false;
263 value = 0; // all primitive types can successfully cast 0
264 } else {
Greg Kaiser19a88662020-01-29 13:48:09 -0800265 // When alignof(T) == 1, hopefully the compiler can optimize away
266 // this conditional as always true.
267 if ((reinterpret_cast<uintptr_t>(mBuf) % alignof(T)) == 0) {
268 // We're properly aligned, and can safely make this assignment.
269 value = *((T*)mBuf);
270 } else {
271 // We need to use memcpy. It's slower, but safe.
272 memcpy(&value, mBuf, sizeof(T));
273 }
Ruchir Rastogi1736ba42019-11-04 14:37:13 -0800274 mBuf += sizeof(T);
275 mRemainingLen -= sizeof(T);
276 }
277 return value;
278 }
279
280 template <class T>
281 void addToValues(int32_t* pos, int32_t depth, T& value, bool* last) {
282 Field f = Field(mTagId, pos, depth);
283 // do not decorate last position at depth 0
284 for (int i = 1; i < depth; i++) {
285 if (last[i]) f.decorateLastPos(i);
286 }
287
288 Value v = Value(value);
289 mValues.push_back(FieldValue(f, v));
290 }
291
292 uint8_t getTypeId(uint8_t typeInfo);
293 uint8_t getNumAnnotations(uint8_t typeInfo);
294
Yao Chen8a8d16c2018-02-08 14:50:40 -0800295 // The items are naturally sorted in DFS order as we read them. this allows us to do fast
296 // matching.
297 std::vector<FieldValue> mValues;
Yao Chen80235402017-11-13 20:42:25 -0800298
Yangster-mac330af582018-02-08 15:24:38 -0800299 // The timestamp set by the logd.
300 int64_t mLogdTimestampNs;
301
302 // The elapsed timestamp set by statsd log writer.
303 int64_t mElapsedTimestampNs;
Yao Chen93fe3a32017-11-02 13:52:59 -0700304
Ruchir Rastogi07f7adb2020-04-16 17:46:12 -0700305 // The atom tag of the event (defaults to 0 if client does not
306 // appropriately set the atom id).
307 int mTagId = 0;
Yao Chend10f7b12017-12-18 12:53:50 -0800308
Ruchir Rastogiab71ef02020-01-30 01:24:50 -0800309 // The uid of the logging client (defaults to -1).
310 int32_t mLogUid = -1;
311
312 // The pid of the logging client (defaults to -1).
313 int32_t mLogPid = -1;
Ruchir Rastogi13296512020-03-24 10:59:49 -0700314
315 // Annotations
316 bool mTruncateTimestamp = false;
Ruchir Rastogi48dbf832020-04-20 16:50:46 -0700317 int mResetState = -1;
Ruchir Rastogi1e8c57f2020-04-27 17:41:58 -0700318
319 // Indexes within the FieldValue vector can be stored in 7 bits because
320 // that's the assumption enforced by the encoding used in FieldValue.
321 int8_t mUidFieldIndex = -1;
322 int8_t mAttributionChainStartIndex = -1;
323 int8_t mAttributionChainEndIndex = -1;
324 int8_t mExclusiveStateFieldIndex = -1;
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700325};
326
Jeff Hamiltonfa2f91c2019-03-22 00:25:02 -0400327void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
328
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700329} // namespace statsd
330} // namespace os
331} // namespace android