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