Merge "Store annotation info in LogEvent/FieldValue" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c0a892456b
@@ -16,6 +16,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
|
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
|
||||||
|
#include "annotations.h"
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace os {
|
namespace os {
|
||||||
@@ -357,6 +358,56 @@ struct Value {
|
|||||||
Value& operator=(const Value& that);
|
Value& operator=(const Value& that);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Annotations {
|
||||||
|
public:
|
||||||
|
Annotations() {}
|
||||||
|
|
||||||
|
// This enum stores where particular annotations can be found in the
|
||||||
|
// bitmask. Note that these pos do not correspond to annotation ids.
|
||||||
|
enum {
|
||||||
|
NESTED_POS = 0x0,
|
||||||
|
PRIMARY_POS = 0x1,
|
||||||
|
EXCLUSIVE_POS = 0x2
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void setNested(bool nested) { setBitmaskAtPos(NESTED_POS, nested); }
|
||||||
|
|
||||||
|
inline void setPrimaryField(bool primary) { setBitmaskAtPos(PRIMARY_POS, primary); }
|
||||||
|
|
||||||
|
inline void setExclusiveState(bool exclusive) { setBitmaskAtPos(EXCLUSIVE_POS, exclusive); }
|
||||||
|
|
||||||
|
inline void setResetState(int resetState) { mResetState = resetState; }
|
||||||
|
|
||||||
|
// Default value = false
|
||||||
|
inline bool isNested() const { return getValueFromBitmask(NESTED_POS); }
|
||||||
|
|
||||||
|
// Default value = false
|
||||||
|
inline bool isPrimaryField() const { return getValueFromBitmask(PRIMARY_POS); }
|
||||||
|
|
||||||
|
// Default value = false
|
||||||
|
inline bool isExclusiveState() const { return getValueFromBitmask(EXCLUSIVE_POS); }
|
||||||
|
|
||||||
|
// If a reset state is not sent in the StatsEvent, returns -1. Note that a
|
||||||
|
// reset satate is only sent if and only if a reset should be triggered.
|
||||||
|
inline int getResetState() const { return mResetState; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void setBitmaskAtPos(int pos, bool value) {
|
||||||
|
mBooleanBitmask &= ~(1 << pos); // clear
|
||||||
|
mBooleanBitmask |= (value << pos); // set
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool getValueFromBitmask(int pos) const {
|
||||||
|
return (mBooleanBitmask >> pos) & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a bitmask over all annotations stored in boolean form. Because
|
||||||
|
// there are only 3 booleans, just one byte is required.
|
||||||
|
uint8_t mBooleanBitmask = 0;
|
||||||
|
|
||||||
|
int mResetState = -1;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a log item, or a dimension item (They are essentially the same).
|
* Represents a log item, or a dimension item (They are essentially the same).
|
||||||
*/
|
*/
|
||||||
@@ -384,6 +435,7 @@ struct FieldValue {
|
|||||||
|
|
||||||
Field mField;
|
Field mField;
|
||||||
Value mValue;
|
Value mValue;
|
||||||
|
Annotations mAnnotations;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool HasPositionANY(const FieldMatcher& matcher);
|
bool HasPositionANY(const FieldMatcher& matcher);
|
||||||
|
|||||||
35
cmds/statsd/src/annotations.h
Normal file
35
cmds/statsd/src/annotations.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
namespace os {
|
||||||
|
namespace statsd {
|
||||||
|
|
||||||
|
const uint8_t ANNOTATION_ID_IS_UID = 1;
|
||||||
|
const uint8_t ANNOTATION_ID_TRUNCATE_TIMESTAMP = 2;
|
||||||
|
const uint8_t ANNOTATION_ID_STATE_OPTION = 3;
|
||||||
|
const uint8_t ANNOTATION_ID_RESET_STATE = 5;
|
||||||
|
const uint8_t ANNOTATION_ID_STATE_NESTED = 6;
|
||||||
|
|
||||||
|
const int32_t STATE_OPTION_PRIMARY_FIELD = 1;
|
||||||
|
const int32_t STATE_OPTION_EXCLUSIVE_STATE = 2;
|
||||||
|
const int32_t STATE_OPTION_PRIMARY_FIELD_FIRST_UID = 3;
|
||||||
|
|
||||||
|
} // namespace statsd
|
||||||
|
} // namespace os
|
||||||
|
} // namespace android
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#define DEBUG false // STOPSHIP if true
|
#define DEBUG false // STOPSHIP if true
|
||||||
#include "logd/LogEvent.h"
|
#include "logd/LogEvent.h"
|
||||||
|
|
||||||
|
#include "annotations.h"
|
||||||
#include "stats_log_util.h"
|
#include "stats_log_util.h"
|
||||||
#include "statslog_statsd.h"
|
#include "statslog_statsd.h"
|
||||||
|
|
||||||
@@ -447,6 +448,7 @@ void LogEvent::parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8
|
|||||||
|
|
||||||
void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last,
|
void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last,
|
||||||
uint8_t numAnnotations) {
|
uint8_t numAnnotations) {
|
||||||
|
int firstUidInChainIndex = mValues.size();
|
||||||
int32_t numNodes = readNextValue<uint8_t>();
|
int32_t numNodes = readNextValue<uint8_t>();
|
||||||
for (pos[1] = 1; pos[1] <= numNodes; pos[1]++) {
|
for (pos[1] = 1; pos[1] <= numNodes; pos[1]++) {
|
||||||
last[1] = (pos[1] == numNodes);
|
last[1] = (pos[1] == numNodes);
|
||||||
@@ -461,26 +463,103 @@ void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last,
|
|||||||
parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
|
parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseAnnotations(numAnnotations);
|
parseAnnotations(numAnnotations, firstUidInChainIndex);
|
||||||
|
|
||||||
pos[1] = pos[2] = 1;
|
pos[1] = pos[2] = 1;
|
||||||
last[1] = last[2] = false;
|
last[1] = last[2] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(b/151109630): store annotation information within LogEvent
|
void LogEvent::parseIsUidAnnotation(uint8_t annotationType) {
|
||||||
void LogEvent::parseAnnotations(uint8_t numAnnotations) {
|
if (mValues.empty() || annotationType != BOOL_TYPE) {
|
||||||
|
mValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isUid = readNextValue<uint8_t>();
|
||||||
|
if (isUid) mUidFieldIndex = mValues.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogEvent::parseTruncateTimestampAnnotation(uint8_t annotationType) {
|
||||||
|
if (!mValues.empty() || annotationType != BOOL_TYPE) {
|
||||||
|
mValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTruncateTimestamp = readNextValue<uint8_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogEvent::parseStateOptionAnnotation(uint8_t annotationType, int firstUidInChainIndex) {
|
||||||
|
if (mValues.empty() || annotationType != INT32_TYPE) {
|
||||||
|
mValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t stateOption = readNextValue<int32_t>();
|
||||||
|
switch (stateOption) {
|
||||||
|
case STATE_OPTION_EXCLUSIVE_STATE:
|
||||||
|
mValues[mValues.size() - 1].mAnnotations.setExclusiveState(true);
|
||||||
|
break;
|
||||||
|
case STATE_OPTION_PRIMARY_FIELD:
|
||||||
|
mValues[mValues.size() - 1].mAnnotations.setPrimaryField(true);
|
||||||
|
break;
|
||||||
|
case STATE_OPTION_PRIMARY_FIELD_FIRST_UID:
|
||||||
|
if (firstUidInChainIndex == -1) {
|
||||||
|
mValid = false;
|
||||||
|
} else {
|
||||||
|
mValues[firstUidInChainIndex].mAnnotations.setPrimaryField(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogEvent::parseResetStateAnnotation(uint8_t annotationType) {
|
||||||
|
if (mValues.empty() || annotationType != INT32_TYPE) {
|
||||||
|
mValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t resetState = readNextValue<int32_t>();
|
||||||
|
mValues[mValues.size() - 1].mAnnotations.setResetState(resetState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogEvent::parseStateNestedAnnotation(uint8_t annotationType) {
|
||||||
|
if (mValues.empty() || annotationType != BOOL_TYPE) {
|
||||||
|
mValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nested = readNextValue<uint8_t>();
|
||||||
|
mValues[mValues.size() - 1].mAnnotations.setNested(nested);
|
||||||
|
}
|
||||||
|
|
||||||
|
// firstUidInChainIndex is a default parameter that is only needed when parsing
|
||||||
|
// annotations for attribution chains.
|
||||||
|
void LogEvent::parseAnnotations(uint8_t numAnnotations, int firstUidInChainIndex) {
|
||||||
for (uint8_t i = 0; i < numAnnotations; i++) {
|
for (uint8_t i = 0; i < numAnnotations; i++) {
|
||||||
/*uint8_t annotationId = */ readNextValue<uint8_t>();
|
uint8_t annotationId = readNextValue<uint8_t>();
|
||||||
uint8_t annotationType = readNextValue<uint8_t>();
|
uint8_t annotationType = readNextValue<uint8_t>();
|
||||||
switch (annotationType) {
|
|
||||||
case BOOL_TYPE:
|
switch (annotationId) {
|
||||||
/*bool annotationValue = */ readNextValue<uint8_t>();
|
case ANNOTATION_ID_IS_UID:
|
||||||
|
parseIsUidAnnotation(annotationType);
|
||||||
break;
|
break;
|
||||||
case INT32_TYPE:
|
case ANNOTATION_ID_TRUNCATE_TIMESTAMP:
|
||||||
/*int32_t annotationValue =*/ readNextValue<int32_t>();
|
parseTruncateTimestampAnnotation(annotationType);
|
||||||
|
break;
|
||||||
|
case ANNOTATION_ID_STATE_OPTION:
|
||||||
|
parseStateOptionAnnotation(annotationType, firstUidInChainIndex);
|
||||||
|
break;
|
||||||
|
case ANNOTATION_ID_RESET_STATE:
|
||||||
|
parseResetStateAnnotation(annotationType);
|
||||||
|
break;
|
||||||
|
case ANNOTATION_ID_STATE_NESTED:
|
||||||
|
parseStateNestedAnnotation(annotationType);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mValid = false;
|
mValid = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -509,8 +588,8 @@ bool LogEvent::parseBuffer(uint8_t* buf, size_t len) {
|
|||||||
typeInfo = readNextValue<uint8_t>();
|
typeInfo = readNextValue<uint8_t>();
|
||||||
if (getTypeId(typeInfo) != INT32_TYPE) mValid = false;
|
if (getTypeId(typeInfo) != INT32_TYPE) mValid = false;
|
||||||
mTagId = readNextValue<int32_t>();
|
mTagId = readNextValue<int32_t>();
|
||||||
parseAnnotations(getNumAnnotations(typeInfo)); // atom-level annotations
|
|
||||||
numElements--;
|
numElements--;
|
||||||
|
parseAnnotations(getNumAnnotations(typeInfo)); // atom-level annotations
|
||||||
|
|
||||||
|
|
||||||
for (pos[0] = 1; pos[0] <= numElements && mValid; pos[0]++) {
|
for (pos[0] = 1; pos[0] <= numElements && mValid; pos[0]++) {
|
||||||
@@ -544,6 +623,7 @@ bool LogEvent::parseBuffer(uint8_t* buf, size_t len) {
|
|||||||
break;
|
break;
|
||||||
case ATTRIBUTION_CHAIN_TYPE:
|
case ATTRIBUTION_CHAIN_TYPE:
|
||||||
parseAttributionChain(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
|
parseAttributionChain(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
|
||||||
|
if (mAttributionChainIndex == -1) mAttributionChainIndex = pos[0];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mValid = false;
|
mValid = false;
|
||||||
|
|||||||
@@ -206,6 +206,32 @@ public:
|
|||||||
return &mValues;
|
return &mValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default value = false
|
||||||
|
inline bool shouldTruncateTimestamp() {
|
||||||
|
return mTruncateTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the index of the uid field within the FieldValues vector if the
|
||||||
|
// uid exists. If there is no uid field, returns -1.
|
||||||
|
//
|
||||||
|
// If the index within the atom definition is desired, do the following:
|
||||||
|
// int vectorIndex = LogEvent.getUidFieldIndex();
|
||||||
|
// if (vectorIndex != -1) {
|
||||||
|
// FieldValue& v = LogEvent.getValues()[vectorIndex];
|
||||||
|
// int atomIndex = v.mField.getPosAtDepth(0);
|
||||||
|
// }
|
||||||
|
// Note that atomIndex is 1-indexed.
|
||||||
|
inline int getUidFieldIndex() {
|
||||||
|
return mUidFieldIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the index of (the first) attribution chain within the atom
|
||||||
|
// definition. Note that the value is 1-indexed. If there is no attribution
|
||||||
|
// chain, returns -1.
|
||||||
|
inline int getAttributionChainIndex() {
|
||||||
|
return mAttributionChainIndex;
|
||||||
|
}
|
||||||
|
|
||||||
inline LogEvent makeCopy() {
|
inline LogEvent makeCopy() {
|
||||||
return LogEvent(*this);
|
return LogEvent(*this);
|
||||||
}
|
}
|
||||||
@@ -240,7 +266,13 @@ private:
|
|||||||
void parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
|
void parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
|
||||||
void parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
|
void parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
|
||||||
void parseAttributionChain(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
|
void parseAttributionChain(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
|
||||||
void parseAnnotations(uint8_t numAnnotations);
|
|
||||||
|
void parseAnnotations(uint8_t numAnnotations, int firstUidInChainIndex = -1);
|
||||||
|
void parseIsUidAnnotation(uint8_t annotationType);
|
||||||
|
void parseTruncateTimestampAnnotation(uint8_t annotationType);
|
||||||
|
void parseStateOptionAnnotation(uint8_t annotationType, int firstUidInChainIndex);
|
||||||
|
void parseResetStateAnnotation(uint8_t annotationType);
|
||||||
|
void parseStateNestedAnnotation(uint8_t annotationType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The below three variables are only valid during the execution of
|
* The below three variables are only valid during the execution of
|
||||||
@@ -322,6 +354,11 @@ private:
|
|||||||
|
|
||||||
// The pid of the logging client (defaults to -1).
|
// The pid of the logging client (defaults to -1).
|
||||||
int32_t mLogPid = -1;
|
int32_t mLogPid = -1;
|
||||||
|
|
||||||
|
// Annotations
|
||||||
|
bool mTruncateTimestamp = false;
|
||||||
|
int mUidFieldIndex = -1;
|
||||||
|
int mAttributionChainIndex = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
|
void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
|
||||||
|
|||||||
@@ -12,12 +12,13 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "src/logd/LogEvent.h"
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <log/log_event_list.h>
|
|
||||||
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
|
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
|
||||||
#include "frameworks/base/core/proto/android/stats/launcher/launcher.pb.h"
|
#include "frameworks/base/core/proto/android/stats/launcher/launcher.pb.h"
|
||||||
#include <stats_event.h>
|
#include "log/log_event_list.h"
|
||||||
|
#include "src/logd/LogEvent.h"
|
||||||
|
#include "stats_event.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
@@ -243,6 +244,117 @@ TEST(LogEventTest, TestAttributionChain) {
|
|||||||
AStatsEvent_release(event);
|
AStatsEvent_release(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void createIntWithBoolAnnotationLogEvent(LogEvent* logEvent, uint8_t annotationId,
|
||||||
|
bool annotationValue) {
|
||||||
|
AStatsEvent* statsEvent = AStatsEvent_obtain();
|
||||||
|
AStatsEvent_setAtomId(statsEvent, /*atomId=*/100);
|
||||||
|
AStatsEvent_writeInt32(statsEvent, 10);
|
||||||
|
AStatsEvent_addBoolAnnotation(statsEvent, annotationId, annotationValue);
|
||||||
|
AStatsEvent_build(statsEvent);
|
||||||
|
|
||||||
|
size_t size;
|
||||||
|
uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
|
||||||
|
EXPECT_TRUE(logEvent->parseBuffer(buf, size));
|
||||||
|
|
||||||
|
AStatsEvent_release(statsEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LogEventTest, TestAnnotationIdIsUid) {
|
||||||
|
LogEvent event(/*uid=*/0, /*pid=*/0);
|
||||||
|
createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_IS_UID, true);
|
||||||
|
|
||||||
|
const vector<FieldValue>& values = event.getValues();
|
||||||
|
EXPECT_EQ(values.size(), 1);
|
||||||
|
EXPECT_EQ(event.getUidFieldIndex(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LogEventTest, TestAnnotationIdStateNested) {
|
||||||
|
LogEvent event(/*uid=*/0, /*pid=*/0);
|
||||||
|
createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_STATE_NESTED, true);
|
||||||
|
|
||||||
|
const vector<FieldValue>& values = event.getValues();
|
||||||
|
EXPECT_EQ(values.size(), 1);
|
||||||
|
EXPECT_TRUE(values[0].mAnnotations.isNested());
|
||||||
|
}
|
||||||
|
|
||||||
|
void createIntWithIntAnnotationLogEvent(LogEvent* logEvent, uint8_t annotationId,
|
||||||
|
int annotationValue) {
|
||||||
|
AStatsEvent* statsEvent = AStatsEvent_obtain();
|
||||||
|
AStatsEvent_setAtomId(statsEvent, /*atomId=*/100);
|
||||||
|
AStatsEvent_writeInt32(statsEvent, 10);
|
||||||
|
AStatsEvent_addInt32Annotation(statsEvent, annotationId, annotationValue);
|
||||||
|
AStatsEvent_build(statsEvent);
|
||||||
|
|
||||||
|
size_t size;
|
||||||
|
uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
|
||||||
|
EXPECT_TRUE(logEvent->parseBuffer(buf, size));
|
||||||
|
|
||||||
|
AStatsEvent_release(statsEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LogEventTest, TestPrimaryFieldAnnotation) {
|
||||||
|
LogEvent event(/*uid=*/0, /*pid=*/0);
|
||||||
|
createIntWithIntAnnotationLogEvent(&event, ANNOTATION_ID_STATE_OPTION,
|
||||||
|
STATE_OPTION_PRIMARY_FIELD);
|
||||||
|
|
||||||
|
const vector<FieldValue>& values = event.getValues();
|
||||||
|
EXPECT_EQ(values.size(), 1);
|
||||||
|
EXPECT_TRUE(values[0].mAnnotations.isPrimaryField());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LogEventTest, TestExclusiveStateAnnotation) {
|
||||||
|
LogEvent event(/*uid=*/0, /*pid=*/0);
|
||||||
|
createIntWithIntAnnotationLogEvent(&event, ANNOTATION_ID_STATE_OPTION,
|
||||||
|
STATE_OPTION_EXCLUSIVE_STATE);
|
||||||
|
|
||||||
|
const vector<FieldValue>& values = event.getValues();
|
||||||
|
EXPECT_EQ(values.size(), 1);
|
||||||
|
EXPECT_TRUE(values[0].mAnnotations.isExclusiveState());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LogEventTest, TestPrimaryFieldFirstUidAnnotation) {
|
||||||
|
// Event has 10 ints and then an attribution chain
|
||||||
|
int numInts = 10;
|
||||||
|
int firstUidInChainIndex = numInts;
|
||||||
|
string tag1 = "tag1";
|
||||||
|
string tag2 = "tag2";
|
||||||
|
uint32_t uids[] = {1001, 1002};
|
||||||
|
const char* tags[] = {tag1.c_str(), tag2.c_str()};
|
||||||
|
|
||||||
|
// Construct AStatsEvent
|
||||||
|
AStatsEvent* statsEvent = AStatsEvent_obtain();
|
||||||
|
AStatsEvent_setAtomId(statsEvent, 100);
|
||||||
|
for (int i = 0; i < numInts; i++) {
|
||||||
|
AStatsEvent_writeInt32(statsEvent, 10);
|
||||||
|
}
|
||||||
|
AStatsEvent_writeAttributionChain(statsEvent, uids, tags, 2);
|
||||||
|
AStatsEvent_addInt32Annotation(statsEvent, ANNOTATION_ID_STATE_OPTION,
|
||||||
|
STATE_OPTION_PRIMARY_FIELD_FIRST_UID);
|
||||||
|
AStatsEvent_build(statsEvent);
|
||||||
|
|
||||||
|
// Construct LogEvent
|
||||||
|
size_t size;
|
||||||
|
uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
|
||||||
|
LogEvent logEvent(/*uid=*/0, /*pid=*/0);
|
||||||
|
EXPECT_TRUE(logEvent.parseBuffer(buf, size));
|
||||||
|
AStatsEvent_release(statsEvent);
|
||||||
|
|
||||||
|
// Check annotation
|
||||||
|
const vector<FieldValue>& values = logEvent.getValues();
|
||||||
|
EXPECT_EQ(values.size(), numInts + 4);
|
||||||
|
EXPECT_TRUE(values[firstUidInChainIndex].mAnnotations.isPrimaryField());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LogEventTest, TestResetStateAnnotation) {
|
||||||
|
int32_t resetState = 10;
|
||||||
|
LogEvent event(/*uid=*/0, /*pid=*/0);
|
||||||
|
createIntWithIntAnnotationLogEvent(&event, ANNOTATION_ID_RESET_STATE, resetState);
|
||||||
|
|
||||||
|
const vector<FieldValue>& values = event.getValues();
|
||||||
|
EXPECT_EQ(values.size(), 1);
|
||||||
|
EXPECT_EQ(values[0].mAnnotations.getResetState(), resetState);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace statsd
|
} // namespace statsd
|
||||||
} // namespace os
|
} // namespace os
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|||||||
Reference in New Issue
Block a user