blob: 8406cc0a7de17811c49628a0e7f8f006fbc97dbd [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "FieldValue.h"
#include <android/frameworks/stats/1.0/types.h>
#include <android/os/StatsLogEventWrapper.h>
#include <android/util/ProtoOutputStream.h>
#include <log/log_read.h>
#include <private/android_logger.h>
#include <stats_event_list.h>
#include "stats_event.h"
#include <utils/Errors.h>
#include <string>
#include <vector>
using namespace android::frameworks::stats::V1_0;
namespace android {
namespace os {
namespace statsd {
struct AttributionNodeInternal {
void set_uid(int32_t id) {
mUid = id;
}
void set_tag(const std::string& value) {
mTag = value;
}
int32_t uid() const {
return mUid;
}
const std::string& tag() const {
return mTag;
}
int32_t mUid;
std::string mTag;
};
struct InstallTrainInfo {
int64_t trainVersionCode;
std::string trainName;
int32_t status;
std::vector<int64_t> experimentIds;
};
/**
* Wrapper for the log_msg structure.
*/
class LogEvent {
public:
/**
* Read a LogEvent from the socket
*/
explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid);
/**
* Creates LogEvent from StatsLogEventWrapper.
*/
static void createLogEvents(const StatsLogEventWrapper& statsLogEventWrapper,
std::vector<std::shared_ptr<LogEvent>>& logEvents);
/**
* Construct one LogEvent from a StatsLogEventWrapper with the i-th work chain. -1 if no chain.
*/
explicit LogEvent(const StatsLogEventWrapper& statsLogEventWrapper, int workChainIndex);
/**
* Constructs a LogEvent with synthetic data for testing. Must call init() before reading.
*/
explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs);
// For testing. The timestamp is used as both elapsed real time and logd timestamp.
explicit LogEvent(int32_t tagId, int64_t timestampNs);
// For testing. The timestamp is used as both elapsed real time and logd timestamp.
explicit LogEvent(int32_t tagId, int64_t timestampNs, int32_t uid);
/**
* Constructs a KeyValuePairsAtom LogEvent from value maps.
*/
explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
int32_t uid,
const std::map<int32_t, int32_t>& int_map,
const std::map<int32_t, int64_t>& long_map,
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map);
// Constructs a BinaryPushStateChanged LogEvent from API call.
explicit LogEvent(const std::string& trainName, int64_t trainVersionCode, bool requiresStaging,
bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
const std::vector<uint8_t>& experimentIds, int32_t userId);
explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
const VendorAtom& vendorAtom);
explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
const InstallTrainInfo& installTrainInfo);
~LogEvent();
/**
* Get the timestamp associated with this event.
*/
inline int64_t GetLogdTimestampNs() const { return mLogdTimestampNs; }
inline int64_t GetElapsedTimestampNs() const { return mElapsedTimestampNs; }
/**
* Get the tag for this event.
*/
inline int GetTagId() const { return mTagId; }
inline uint32_t GetUid() const {
return mLogUid;
}
/**
* Get the nth value, starting at 1.
*
* Returns BAD_INDEX if the index is larger than the number of elements.
* Returns BAD_TYPE if the index is available but the data is the wrong type.
*/
int64_t GetLong(size_t key, status_t* err) const;
int GetInt(size_t key, status_t* err) const;
const char* GetString(size_t key, status_t* err) const;
bool GetBool(size_t key, status_t* err) const;
float GetFloat(size_t key, status_t* err) const;
/**
* Write test data to the LogEvent. This can only be used when the LogEvent is constructed
* using LogEvent(tagId, timestampNs). You need to call init() before you can read from it.
*/
bool write(uint32_t value);
bool write(int32_t value);
bool write(uint64_t value);
bool write(int64_t value);
bool write(const std::string& value);
bool write(float value);
bool write(const std::vector<AttributionNodeInternal>& nodes);
bool write(const AttributionNodeInternal& node);
bool writeBytes(const std::string& value);
bool writeKeyValuePairs(int32_t uid,
const std::map<int32_t, int32_t>& int_map,
const std::map<int32_t, int64_t>& long_map,
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map);
/**
* Return a string representation of this event.
*/
std::string ToString() const;
/**
* Write this object to a ProtoOutputStream.
*/
void ToProto(android::util::ProtoOutputStream& out) const;
/**
* Used with the constructor where tag is passed in. Converts the log_event_list to read mode
* and prepares the list for reading.
*/
void init();
/**
* Set elapsed timestamp if the original timestamp is missing.
*/
void setElapsedTimestampNs(int64_t timestampNs) {
mElapsedTimestampNs = timestampNs;
}
/**
* Set the timestamp if the original logd timestamp is missing.
*/
void setLogdWallClockTimestampNs(int64_t timestampNs) {
mLogdTimestampNs = timestampNs;
}
inline int size() const {
return mValues.size();
}
const std::vector<FieldValue>& getValues() const {
return mValues;
}
std::vector<FieldValue>* getMutableValues() {
return &mValues;
}
bool isValid() {
return mValid;
}
inline LogEvent makeCopy() {
return LogEvent(*this);
}
private:
/**
* Only use this if copy is absolutely needed.
*/
LogEvent(const LogEvent&);
/**
* Parsing function for new encoding scheme.
*/
void initNew();
void parseInt32(int32_t* pos, int32_t depth, bool* last);
void parseInt64(int32_t* pos, int32_t depth, bool* last);
void parseString(int32_t* pos, int32_t depth, bool* last);
void parseFloat(int32_t* pos, int32_t depth, bool* last);
void parseBool(int32_t* pos, int32_t depth, bool* last);
void parseByteArray(int32_t* pos, int32_t depth, bool* last);
void parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last);
void parseAttributionChain(int32_t* pos, int32_t depth, bool* last);
/**
* mBuf is a pointer to the current location in the buffer being parsed.
* Because the buffer lives on the StatsSocketListener stack, this pointer
* is only valid during the LogEvent constructor. It will be set to null at
* the end of initNew.
*/
uint8_t* mBuf;
uint32_t mRemainingLen; // number of valid bytes left in the buffer being parsed
bool mValid = true; // stores whether the event we received from the socket is valid
/**
* Side-effects:
* If there is enough space in buffer to read value of type T
* - move mBuf past the value that was just read
* - decrement mRemainingLen by size of T
* Else
* - set mValid to false
*/
template <class T>
T readNextValue() {
T value;
if (mRemainingLen < sizeof(T)) {
mValid = false;
value = 0; // all primitive types can successfully cast 0
} else {
value = *((T*)mBuf);
mBuf += sizeof(T);
mRemainingLen -= sizeof(T);
}
return value;
}
template <class T>
void addToValues(int32_t* pos, int32_t depth, T& value, bool* last) {
Field f = Field(mTagId, pos, depth);
// do not decorate last position at depth 0
for (int i = 1; i < depth; i++) {
if (last[i]) f.decorateLastPos(i);
}
Value v = Value(value);
mValues.push_back(FieldValue(f, v));
}
uint8_t getTypeId(uint8_t typeInfo);
uint8_t getNumAnnotations(uint8_t typeInfo);
/**
* Parses a log_msg into a LogEvent object.
*/
void init(android_log_context context);
// The items are naturally sorted in DFS order as we read them. this allows us to do fast
// matching.
std::vector<FieldValue> mValues;
// This field is used when statsD wants to create log event object and write fields to it. After
// calling init() function, this object would be destroyed to save memory usage.
// When the log event is created from log msg, this field is never initiated.
android_log_context mContext = NULL;
// The timestamp set by the logd.
int64_t mLogdTimestampNs;
// The elapsed timestamp set by statsd log writer.
int64_t mElapsedTimestampNs;
int mTagId;
uint32_t mLogUid;
};
void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
} // namespace statsd
} // namespace os
} // namespace android