Remove dimensions_in_condition from statsd metrics
The dimensions_in_condition field is not used for any configs in statsd. The functionality that it was intended to provide will be replaced by StateTracker which is being tracked in b/136566566. go/remove-dic contains background information on what was removed/changed and why Test: bit statsd_test:* && atest CtsStatsdHostTestCases && atest GtsStatsdHostTestCases Change-Id: Ic328fa5fe027377380ba57363d9bc77985f18376
This commit is contained in:
@@ -253,9 +253,6 @@ cc_test {
|
||||
"tests/e2e/GaugeMetric_e2e_push_test.cpp",
|
||||
"tests/e2e/GaugeMetric_e2e_pull_test.cpp",
|
||||
"tests/e2e/ValueMetric_pull_e2e_test.cpp",
|
||||
"tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp",
|
||||
"tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp",
|
||||
"tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp",
|
||||
"tests/e2e/Anomaly_count_e2e_test.cpp",
|
||||
"tests/e2e/Anomaly_duration_sum_e2e_test.cpp",
|
||||
"tests/e2e/ConfigTtl_e2e_test.cpp",
|
||||
|
||||
@@ -110,20 +110,14 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf
|
||||
|
||||
void CombinationConditionTracker::isConditionMet(
|
||||
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
|
||||
const std::vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
const bool isPartialLink,
|
||||
vector<ConditionState>& conditionCache,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
|
||||
vector<ConditionState>& conditionCache) const {
|
||||
// So far, this is fine as there is at most one child having sliced output.
|
||||
for (const int childIndex : mChildren) {
|
||||
if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
|
||||
allConditions[childIndex]->isConditionMet(conditionParameters, allConditions,
|
||||
dimensionFields,
|
||||
isSubOutputDimensionFields,
|
||||
isPartialLink,
|
||||
conditionCache,
|
||||
dimensionsKeySet);
|
||||
conditionCache);
|
||||
}
|
||||
}
|
||||
conditionCache[mIndex] =
|
||||
@@ -178,25 +172,6 @@ void CombinationConditionTracker::evaluateCondition(
|
||||
}
|
||||
}
|
||||
|
||||
ConditionState CombinationConditionTracker::getMetConditionDimension(
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const std::vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
|
||||
vector<ConditionState> conditionCache(allConditions.size(), ConditionState::kNotEvaluated);
|
||||
// So far, this is fine as there is at most one child having sliced output.
|
||||
for (const int childIndex : mChildren) {
|
||||
conditionCache[childIndex] = conditionCache[childIndex] |
|
||||
allConditions[childIndex]->getMetConditionDimension(
|
||||
allConditions, dimensionFields, isSubOutputDimensionFields, dimensionsKeySet);
|
||||
}
|
||||
evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
|
||||
if (conditionCache[mIndex] == ConditionState::kTrue && dimensionsKeySet.empty()) {
|
||||
dimensionsKeySet.insert(DEFAULT_DIMENSION_KEY);
|
||||
}
|
||||
return conditionCache[mIndex];
|
||||
}
|
||||
|
||||
bool CombinationConditionTracker::equalOutputDimensions(
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensions) const {
|
||||
|
||||
@@ -43,17 +43,8 @@ public:
|
||||
|
||||
void isConditionMet(const ConditionKey& conditionParameters,
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
const bool isPartialLink,
|
||||
std::vector<ConditionState>& conditionCache,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
|
||||
|
||||
ConditionState getMetConditionDimension(
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
|
||||
std::vector<ConditionState>& conditionCache) const override;
|
||||
|
||||
// Only one child predicate can have dimension.
|
||||
const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
|
||||
|
||||
@@ -84,29 +84,14 @@ public:
|
||||
// condition.
|
||||
// [allConditions]: all condition trackers. This is needed because the condition evaluation is
|
||||
// done recursively
|
||||
// [dimensionFields]: the needed dimension fields which should be all or subset of the condition
|
||||
// tracker output dimension.
|
||||
// [isSubOutputDimensionFields]: true if the needed dimension fields which is strictly subset of
|
||||
// the condition tracker output dimension.
|
||||
// [isPartialLink]: true if the link specified by 'conditionParameters' contains all the fields
|
||||
// in the condition tracker output dimension.
|
||||
// [conditionCache]: the cache holding the condition evaluation values.
|
||||
// [dimensionsKeySet]: the dimensions where the sliced condition is true. For combination
|
||||
// condition, it assumes that only one child predicate is sliced.
|
||||
virtual void isConditionMet(
|
||||
const ConditionKey& conditionParameters,
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
const bool isPartialLink,
|
||||
std::vector<ConditionState>& conditionCache,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const = 0;
|
||||
|
||||
virtual ConditionState getMetConditionDimension(
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const = 0;
|
||||
std::vector<ConditionState>& conditionCache) const = 0;
|
||||
|
||||
// return the list of LogMatchingTracker index that this ConditionTracker uses.
|
||||
virtual const std::set<int>& getLogTrackerIndex() const {
|
||||
|
||||
@@ -25,27 +25,15 @@ using std::string;
|
||||
using std::vector;
|
||||
|
||||
ConditionState ConditionWizard::query(const int index, const ConditionKey& parameters,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
const bool isPartialLink,
|
||||
std::unordered_set<HashableDimensionKey>* dimensionKeySet) {
|
||||
const bool isPartialLink) {
|
||||
vector<ConditionState> cache(mAllConditions.size(), ConditionState::kNotEvaluated);
|
||||
|
||||
mAllConditions[index]->isConditionMet(
|
||||
parameters, mAllConditions, dimensionFields, isSubOutputDimensionFields, isPartialLink,
|
||||
cache, *dimensionKeySet);
|
||||
parameters, mAllConditions, isPartialLink,
|
||||
cache);
|
||||
return cache[index];
|
||||
}
|
||||
|
||||
ConditionState ConditionWizard::getMetConditionDimension(
|
||||
const int index, const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
std::unordered_set<HashableDimensionKey>* dimensionsKeySet) const {
|
||||
return mAllConditions[index]->getMetConditionDimension(mAllConditions, dimensionFields,
|
||||
isSubOutputDimensionFields,
|
||||
*dimensionsKeySet);
|
||||
}
|
||||
|
||||
const set<HashableDimensionKey>* ConditionWizard::getChangedToTrueDimensions(
|
||||
const int index) const {
|
||||
return mAllConditions[index]->getChangedToTrueDimensions(mAllConditions);
|
||||
@@ -82,4 +70,4 @@ bool ConditionWizard::equalOutputDimensions(const int index, const vector<Matche
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
} // namespace android
|
||||
|
||||
@@ -40,15 +40,7 @@ public:
|
||||
// The ConditionTracker at [conditionIndex] can be a CombinationConditionTracker. In this case,
|
||||
// the conditionParameters contains the parameters for it's children SimpleConditionTrackers.
|
||||
virtual ConditionState query(const int conditionIndex, const ConditionKey& conditionParameters,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
const bool isPartialLink,
|
||||
std::unordered_set<HashableDimensionKey>* dimensionKeySet);
|
||||
|
||||
virtual ConditionState getMetConditionDimension(
|
||||
const int index, const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
std::unordered_set<HashableDimensionKey>* dimensionsKeySet) const;
|
||||
const bool isPartialLink);
|
||||
|
||||
virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(const int index) const;
|
||||
virtual const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
|
||||
|
||||
@@ -344,11 +344,8 @@ void SimpleConditionTracker::evaluateCondition(
|
||||
|
||||
void SimpleConditionTracker::isConditionMet(
|
||||
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
const bool isPartialLink,
|
||||
vector<ConditionState>& conditionCache,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
|
||||
vector<ConditionState>& conditionCache) const {
|
||||
|
||||
if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
|
||||
// it has been evaluated.
|
||||
@@ -360,18 +357,13 @@ void SimpleConditionTracker::isConditionMet(
|
||||
|
||||
if (pair == conditionParameters.end()) {
|
||||
ConditionState conditionState = ConditionState::kNotEvaluated;
|
||||
if (dimensionFields.size() > 0 && dimensionFields[0].mMatcher.getTag() == mDimensionTag) {
|
||||
conditionState = conditionState | getMetConditionDimension(
|
||||
allConditions, dimensionFields, isSubOutputDimensionFields, dimensionsKeySet);
|
||||
} else {
|
||||
conditionState = conditionState | mInitialValue;
|
||||
if (!mSliced) {
|
||||
const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
|
||||
if (itr != mSlicedConditionState.end()) {
|
||||
ConditionState sliceState =
|
||||
itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
|
||||
conditionState = conditionState | sliceState;
|
||||
}
|
||||
conditionState = conditionState | mInitialValue;
|
||||
if (!mSliced) {
|
||||
const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
|
||||
if (itr != mSlicedConditionState.end()) {
|
||||
ConditionState sliceState =
|
||||
itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
|
||||
conditionState = conditionState | sliceState;
|
||||
}
|
||||
}
|
||||
conditionCache[mIndex] = conditionState;
|
||||
@@ -389,15 +381,6 @@ void SimpleConditionTracker::isConditionMet(
|
||||
slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
|
||||
if (slice.first.contains(key)) {
|
||||
conditionState = conditionState | sliceState;
|
||||
if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
|
||||
if (isSubOutputDimensionFields) {
|
||||
HashableDimensionKey dimensionKey;
|
||||
filterValues(dimensionFields, slice.first.getValues(), &dimensionKey);
|
||||
dimensionsKeySet.insert(dimensionKey);
|
||||
} else {
|
||||
dimensionsKeySet.insert(slice.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -407,15 +390,6 @@ void SimpleConditionTracker::isConditionMet(
|
||||
ConditionState sliceState =
|
||||
startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
|
||||
conditionState = conditionState | sliceState;
|
||||
if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
|
||||
if (isSubOutputDimensionFields) {
|
||||
HashableDimensionKey dimensionKey;
|
||||
filterValues(dimensionFields, startedCountIt->first.getValues(), &dimensionKey);
|
||||
dimensionsKeySet.insert(dimensionKey);
|
||||
} else {
|
||||
dimensionsKeySet.insert(startedCountIt->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -423,41 +397,6 @@ void SimpleConditionTracker::isConditionMet(
|
||||
VLOG("Predicate %lld return %d", (long long)mConditionId, conditionCache[mIndex]);
|
||||
}
|
||||
|
||||
ConditionState SimpleConditionTracker::getMetConditionDimension(
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
|
||||
ConditionState conditionState = mInitialValue;
|
||||
if (dimensionFields.size() == 0 || mOutputDimensions.size() == 0 ||
|
||||
dimensionFields[0].mMatcher.getTag() != mOutputDimensions[0].mMatcher.getTag()) {
|
||||
const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
|
||||
if (itr != mSlicedConditionState.end()) {
|
||||
ConditionState sliceState =
|
||||
itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
|
||||
conditionState = conditionState | sliceState;
|
||||
}
|
||||
return conditionState;
|
||||
}
|
||||
|
||||
for (const auto& slice : mSlicedConditionState) {
|
||||
ConditionState sliceState =
|
||||
slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
|
||||
conditionState = conditionState | sliceState;
|
||||
|
||||
if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
|
||||
if (isSubOutputDimensionFields) {
|
||||
HashableDimensionKey dimensionKey;
|
||||
filterValues(dimensionFields, slice.first.getValues(), &dimensionKey);
|
||||
dimensionsKeySet.insert(dimensionKey);
|
||||
} else {
|
||||
dimensionsKeySet.insert(slice.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
return conditionState;
|
||||
}
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
|
||||
@@ -48,17 +48,8 @@ public:
|
||||
|
||||
void isConditionMet(const ConditionKey& conditionParameters,
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
const bool isPartialLink,
|
||||
std::vector<ConditionState>& conditionCache,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
|
||||
|
||||
ConditionState getMetConditionDimension(
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
|
||||
std::vector<ConditionState>& conditionCache) const override;
|
||||
|
||||
virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
|
||||
const std::vector<sp<ConditionTracker>>& allConditions) const {
|
||||
|
||||
@@ -178,11 +178,8 @@ void StateTracker::evaluateCondition(const LogEvent& event,
|
||||
|
||||
void StateTracker::isConditionMet(
|
||||
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
const bool isPartialLink,
|
||||
vector<ConditionState>& conditionCache,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
|
||||
vector<ConditionState>& conditionCache) const {
|
||||
if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
|
||||
// it has been evaluated.
|
||||
VLOG("Yes, already evaluated, %lld %d", (long long)mConditionId, conditionCache[mIndex]);
|
||||
@@ -193,10 +190,6 @@ void StateTracker::isConditionMet(
|
||||
if (pair == conditionParameters.end()) {
|
||||
if (mSlicedState.size() > 0) {
|
||||
conditionCache[mIndex] = ConditionState::kTrue;
|
||||
|
||||
for (const auto& state : mSlicedState) {
|
||||
dimensionsKeySet.insert(state.second);
|
||||
}
|
||||
} else {
|
||||
conditionCache[mIndex] = ConditionState::kUnknown;
|
||||
}
|
||||
@@ -208,25 +201,9 @@ void StateTracker::isConditionMet(
|
||||
auto it = mSlicedState.find(primaryKey);
|
||||
if (it != mSlicedState.end()) {
|
||||
conditionCache[mIndex] = ConditionState::kTrue;
|
||||
dimensionsKeySet.insert(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
ConditionState StateTracker::getMetConditionDimension(
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
|
||||
if (mSlicedState.size() > 0) {
|
||||
for (const auto& state : mSlicedState) {
|
||||
dimensionsKeySet.insert(state.second);
|
||||
}
|
||||
return ConditionState::kTrue;
|
||||
}
|
||||
|
||||
return mInitialValue;
|
||||
}
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
} // namespace android
|
||||
|
||||
@@ -55,22 +55,8 @@ public:
|
||||
*/
|
||||
void isConditionMet(const ConditionKey& conditionParameters,
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
const bool isPartialLink,
|
||||
std::vector<ConditionState>& conditionCache,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
|
||||
|
||||
/**
|
||||
* Note: dimensionFields will be ignored in StateTracker, because we demand metrics
|
||||
* must take the entire dimension fields from StateTracker. This is to make implementation
|
||||
* simple and efficient.
|
||||
*/
|
||||
ConditionState getMetConditionDimension(
|
||||
const std::vector<sp<ConditionTracker>>& allConditions,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubOutputDimensionFields,
|
||||
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
|
||||
std::vector<ConditionState>& conditionCache) const override;
|
||||
|
||||
virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
|
||||
const std::vector<sp<ConditionTracker>>& allConditions) const {
|
||||
@@ -128,4 +114,4 @@ private:
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
} // namespace android
|
||||
|
||||
@@ -48,7 +48,6 @@ const int FIELD_ID_COUNT_METRICS = 5;
|
||||
const int FIELD_ID_TIME_BASE = 9;
|
||||
const int FIELD_ID_BUCKET_SIZE = 10;
|
||||
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
|
||||
const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
|
||||
const int FIELD_ID_IS_ACTIVE = 14;
|
||||
|
||||
// for CountMetricDataWrapper
|
||||
@@ -82,12 +81,7 @@ CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric
|
||||
mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
|
||||
}
|
||||
|
||||
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
|
||||
HasPositionALL(metric.dimensions_in_condition());
|
||||
|
||||
if (metric.has_dimensions_in_condition()) {
|
||||
translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
|
||||
}
|
||||
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
|
||||
|
||||
if (metric.links().size() > 0) {
|
||||
for (const auto& link : metric.links()) {
|
||||
@@ -100,8 +94,6 @@ CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric
|
||||
mConditionSliced = true;
|
||||
}
|
||||
|
||||
mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
|
||||
|
||||
flushIfNeededLocked(startTimeNs);
|
||||
// Adjust start for partial bucket
|
||||
mCurrentBucketStartTimeNs = startTimeNs;
|
||||
@@ -171,13 +163,6 @@ void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
|
||||
writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
|
||||
protoOutput->end(dimenPathToken);
|
||||
}
|
||||
if (!mDimensionsInCondition.empty()) {
|
||||
uint64_t dimenPathToken = protoOutput->start(
|
||||
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
|
||||
writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
|
||||
protoOutput->end(dimenPathToken);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
|
||||
|
||||
@@ -47,7 +47,6 @@ const int FIELD_ID_DURATION_METRICS = 6;
|
||||
const int FIELD_ID_TIME_BASE = 9;
|
||||
const int FIELD_ID_BUCKET_SIZE = 10;
|
||||
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
|
||||
const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
|
||||
const int FIELD_ID_IS_ACTIVE = 14;
|
||||
// for DurationMetricDataWrapper
|
||||
const int FIELD_ID_DATA = 1;
|
||||
@@ -100,12 +99,7 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat
|
||||
ALOGE("Position ANY in dimension_in_what not supported.");
|
||||
}
|
||||
|
||||
if (metric.has_dimensions_in_condition()) {
|
||||
translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
|
||||
}
|
||||
|
||||
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
|
||||
HasPositionALL(metric.dimensions_in_condition());
|
||||
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
|
||||
|
||||
if (metric.links().size() > 0) {
|
||||
for (const auto& link : metric.links()) {
|
||||
@@ -115,19 +109,16 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat
|
||||
translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
|
||||
mMetric2ConditionLinks.push_back(mc);
|
||||
}
|
||||
mConditionSliced = true;
|
||||
}
|
||||
mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
|
||||
mUnSlicedPartCondition = ConditionState::kUnknown;
|
||||
|
||||
mUseWhatDimensionAsInternalDimension = equalDimensions(mDimensionsInWhat, mInternalDimensions);
|
||||
if (mWizard != nullptr && mConditionTrackerIndex >= 0) {
|
||||
mSameConditionDimensionsInTracker =
|
||||
mWizard->equalOutputDimensions(mConditionTrackerIndex, mDimensionsInCondition);
|
||||
if (mMetric2ConditionLinks.size() == 1) {
|
||||
mHasLinksToAllConditionDimensionsInTracker =
|
||||
mWizard->equalOutputDimensions(mConditionTrackerIndex,
|
||||
mMetric2ConditionLinks.begin()->conditionFields);
|
||||
}
|
||||
if (mWizard != nullptr && mConditionTrackerIndex >= 0 &&
|
||||
mMetric2ConditionLinks.size() == 1) {
|
||||
mHasLinksToAllConditionDimensionsInTracker =
|
||||
mWizard->equalOutputDimensions(mConditionTrackerIndex,
|
||||
mMetric2ConditionLinks.begin()->conditionFields);
|
||||
}
|
||||
flushIfNeededLocked(startTimeNs);
|
||||
// Adjust start for partial bucket
|
||||
@@ -164,13 +155,13 @@ unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
|
||||
case DurationMetric_AggregationType_SUM:
|
||||
return make_unique<OringDurationTracker>(
|
||||
mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
|
||||
mDimensionsInCondition, mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
|
||||
mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
|
||||
mTimeBaseNs, mBucketSizeNs, mConditionSliced,
|
||||
mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
|
||||
case DurationMetric_AggregationType_MAX_SPARSE:
|
||||
return make_unique<MaxDurationTracker>(
|
||||
mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
|
||||
mDimensionsInCondition, mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
|
||||
mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
|
||||
mTimeBaseNs, mBucketSizeNs, mConditionSliced,
|
||||
mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
|
||||
}
|
||||
@@ -178,13 +169,11 @@ unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
|
||||
|
||||
// SlicedConditionChange optimization case 1:
|
||||
// 1. If combination condition, logical operation is AND, only one sliced child predicate.
|
||||
// 2. No condition in dimension
|
||||
// 3. The links covers all dimension fields in the sliced child condition predicate.
|
||||
// 2. The links covers all dimension fields in the sliced child condition predicate.
|
||||
void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool condition,
|
||||
const int64_t eventTime) {
|
||||
if (mMetric2ConditionLinks.size() != 1 ||
|
||||
!mHasLinksToAllConditionDimensionsInTracker ||
|
||||
!mDimensionsInCondition.empty()) {
|
||||
!mHasLinksToAllConditionDimensionsInTracker) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -249,178 +238,20 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// SlicedConditionChange optimization case 2:
|
||||
// 1. If combination condition, logical operation is AND, only one sliced child predicate.
|
||||
// 2. Has dimensions_in_condition and it equals to the output dimensions of the sliced predicate.
|
||||
void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt2(bool condition,
|
||||
const int64_t eventTime) {
|
||||
if (mMetric2ConditionLinks.size() > 1 || !mSameConditionDimensionsInTracker) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto dimensionsChangedToTrue = mWizard->getChangedToTrueDimensions(mConditionTrackerIndex);
|
||||
auto dimensionsChangedToFalse = mWizard->getChangedToFalseDimensions(mConditionTrackerIndex);
|
||||
|
||||
bool currentUnSlicedPartCondition = true;
|
||||
if (!mWizard->IsSimpleCondition(mConditionTrackerIndex)) {
|
||||
ConditionState unslicedPartState =
|
||||
mWizard->getUnSlicedPartConditionState(mConditionTrackerIndex);
|
||||
// When the unsliced part is still false, return directly.
|
||||
if (mUnSlicedPartCondition == ConditionState::kFalse &&
|
||||
unslicedPartState == ConditionState::kFalse) {
|
||||
return;
|
||||
}
|
||||
mUnSlicedPartCondition = unslicedPartState;
|
||||
currentUnSlicedPartCondition = mUnSlicedPartCondition > 0;
|
||||
}
|
||||
|
||||
const std::set<HashableDimensionKey>* trueDimensionsToProcess = nullptr;
|
||||
const std::set<HashableDimensionKey>* falseDimensionsToProcess = nullptr;
|
||||
|
||||
std::set<HashableDimensionKey> currentTrueConditionDimensions;
|
||||
if (dimensionsChangedToTrue == nullptr || dimensionsChangedToFalse == nullptr ||
|
||||
(dimensionsChangedToTrue->empty() && dimensionsChangedToFalse->empty())) {
|
||||
mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, ¤tTrueConditionDimensions);
|
||||
trueDimensionsToProcess = ¤tTrueConditionDimensions;
|
||||
} else if (currentUnSlicedPartCondition) {
|
||||
// Handles the condition change from the sliced predicate. If the unsliced condition state
|
||||
// is not true, not need to do anything.
|
||||
trueDimensionsToProcess = dimensionsChangedToTrue;
|
||||
falseDimensionsToProcess = dimensionsChangedToFalse;
|
||||
}
|
||||
|
||||
if (trueDimensionsToProcess == nullptr && falseDimensionsToProcess == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
|
||||
if (falseDimensionsToProcess != nullptr) {
|
||||
for (const auto& changedDim : *falseDimensionsToProcess) {
|
||||
auto condIt = whatIt.second.find(changedDim);
|
||||
if (condIt != whatIt.second.end()) {
|
||||
condIt->second->onConditionChanged(false, eventTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trueDimensionsToProcess != nullptr) {
|
||||
HashableDimensionKey linkedConditionDimensionKey;
|
||||
if (!trueDimensionsToProcess->empty() && mMetric2ConditionLinks.size() == 1) {
|
||||
getDimensionForCondition(whatIt.first.getValues(),
|
||||
mMetric2ConditionLinks[0],
|
||||
&linkedConditionDimensionKey);
|
||||
}
|
||||
for (auto& trueDim : *trueDimensionsToProcess) {
|
||||
auto condIt = whatIt.second.find(trueDim);
|
||||
if (condIt != whatIt.second.end()) {
|
||||
condIt->second->onConditionChanged(
|
||||
currentUnSlicedPartCondition, eventTime);
|
||||
} else {
|
||||
if (mMetric2ConditionLinks.size() == 0 ||
|
||||
trueDim.contains(linkedConditionDimensionKey)) {
|
||||
if (!whatIt.second.empty()) {
|
||||
auto newEventKey = MetricDimensionKey(whatIt.first, trueDim);
|
||||
if (hitGuardRailLocked(newEventKey)) {
|
||||
continue;
|
||||
}
|
||||
unique_ptr<DurationTracker> newTracker =
|
||||
whatIt.second.begin()->second->clone(eventTime);
|
||||
if (newTracker != nullptr) {
|
||||
newTracker->setEventKey(newEventKey);
|
||||
newTracker->onConditionChanged(true, eventTime);
|
||||
whatIt.second[trueDim] = std::move(newTracker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DurationMetricProducer::onSlicedConditionMayChangeInternalLocked(bool overallCondition,
|
||||
const int64_t eventTimeNs) {
|
||||
bool changeDimTrackable = mWizard->IsChangedDimensionTrackable(mConditionTrackerIndex);
|
||||
if (changeDimTrackable && mHasLinksToAllConditionDimensionsInTracker &&
|
||||
mDimensionsInCondition.empty()) {
|
||||
if (changeDimTrackable && mHasLinksToAllConditionDimensionsInTracker) {
|
||||
onSlicedConditionMayChangeLocked_opt1(overallCondition, eventTimeNs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (changeDimTrackable && mSameConditionDimensionsInTracker &&
|
||||
mMetric2ConditionLinks.size() <= 1) {
|
||||
onSlicedConditionMayChangeLocked_opt2(overallCondition, eventTimeNs);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now for each of the on-going event, check if the condition has changed for them.
|
||||
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
|
||||
for (auto& pair : whatIt.second) {
|
||||
pair.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDimensionsInCondition.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mMetric2ConditionLinks.empty()) {
|
||||
std::unordered_set<HashableDimensionKey> conditionDimensionsKeySet;
|
||||
mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition,
|
||||
!mSameConditionDimensionsInTracker,
|
||||
&conditionDimensionsKeySet);
|
||||
for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
|
||||
for (const auto& pair : whatIt.second) {
|
||||
conditionDimensionsKeySet.erase(pair.first);
|
||||
}
|
||||
}
|
||||
for (const auto& conditionDimension : conditionDimensionsKeySet) {
|
||||
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
|
||||
if (!whatIt.second.empty()) {
|
||||
auto newEventKey = MetricDimensionKey(whatIt.first, conditionDimension);
|
||||
if (hitGuardRailLocked(newEventKey)) {
|
||||
continue;
|
||||
}
|
||||
unique_ptr<DurationTracker> newTracker =
|
||||
whatIt.second.begin()->second->clone(eventTimeNs);
|
||||
if (newTracker != nullptr) {
|
||||
newTracker->setEventKey(MetricDimensionKey(newEventKey));
|
||||
newTracker->onSlicedConditionMayChange(overallCondition, eventTimeNs);
|
||||
whatIt.second[conditionDimension] = std::move(newTracker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
|
||||
ConditionKey conditionKey;
|
||||
for (const auto& link : mMetric2ConditionLinks) {
|
||||
getDimensionForCondition(whatIt.first.getValues(), link,
|
||||
&conditionKey[link.conditionId]);
|
||||
}
|
||||
std::unordered_set<HashableDimensionKey> conditionDimensionsKeys;
|
||||
mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
|
||||
!mSameConditionDimensionsInTracker,
|
||||
!mHasLinksToAllConditionDimensionsInTracker,
|
||||
&conditionDimensionsKeys);
|
||||
|
||||
for (const auto& conditionDimension : conditionDimensionsKeys) {
|
||||
if (!whatIt.second.empty() &&
|
||||
whatIt.second.find(conditionDimension) == whatIt.second.end()) {
|
||||
auto newEventKey = MetricDimensionKey(whatIt.first, conditionDimension);
|
||||
if (hitGuardRailLocked(newEventKey)) {
|
||||
continue;
|
||||
}
|
||||
auto newTracker = whatIt.second.begin()->second->clone(eventTimeNs);
|
||||
if (newTracker != nullptr) {
|
||||
newTracker->setEventKey(newEventKey);
|
||||
newTracker->onSlicedConditionMayChange(overallCondition, eventTimeNs);
|
||||
whatIt.second[conditionDimension] = std::move(newTracker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DurationMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
|
||||
@@ -526,12 +357,6 @@ void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
|
||||
writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
|
||||
protoOutput->end(dimenPathToken);
|
||||
}
|
||||
if (!mDimensionsInCondition.empty()) {
|
||||
uint64_t dimenPathToken = protoOutput->start(
|
||||
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
|
||||
writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
|
||||
protoOutput->end(dimenPathToken);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
|
||||
@@ -790,52 +615,24 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
|
||||
|
||||
bool condition;
|
||||
ConditionKey conditionKey;
|
||||
std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
|
||||
if (mConditionSliced) {
|
||||
for (const auto& link : mMetric2ConditionLinks) {
|
||||
getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
|
||||
}
|
||||
|
||||
auto conditionState =
|
||||
mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
|
||||
!mSameConditionDimensionsInTracker,
|
||||
!mHasLinksToAllConditionDimensionsInTracker,
|
||||
&dimensionKeysInCondition);
|
||||
mWizard->query(mConditionTrackerIndex, conditionKey,
|
||||
!mHasLinksToAllConditionDimensionsInTracker);
|
||||
condition = conditionState == ConditionState::kTrue;
|
||||
if (mDimensionsInCondition.empty() && condition) {
|
||||
dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
|
||||
}
|
||||
} else {
|
||||
// TODO: The unknown condition state is not handled here, we should fix it.
|
||||
condition = mCondition == ConditionState::kTrue;
|
||||
if (condition) {
|
||||
dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
condition = condition && mIsActive;
|
||||
|
||||
if (dimensionKeysInCondition.empty()) {
|
||||
handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY),
|
||||
conditionKey, condition, event);
|
||||
} else {
|
||||
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
|
||||
// If the what dimension is already there, we should update all the trackers even
|
||||
// the condition is false.
|
||||
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
|
||||
for (const auto& condIt : whatIt->second) {
|
||||
const bool cond = dimensionKeysInCondition.find(condIt.first) !=
|
||||
dimensionKeysInCondition.end() && condition;
|
||||
handleStartEvent(MetricDimensionKey(dimensionInWhat, condIt.first),
|
||||
conditionKey, cond, event);
|
||||
dimensionKeysInCondition.erase(condIt.first);
|
||||
}
|
||||
}
|
||||
for (const auto& conditionDimension : dimensionKeysInCondition) {
|
||||
handleStartEvent(MetricDimensionKey(dimensionInWhat, conditionDimension), conditionKey,
|
||||
condition, event);
|
||||
}
|
||||
}
|
||||
handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY),
|
||||
conditionKey, condition, event);
|
||||
}
|
||||
|
||||
size_t DurationMetricProducer::byteSizeLocked() const {
|
||||
|
||||
@@ -48,7 +48,6 @@ const int FIELD_ID_GAUGE_METRICS = 8;
|
||||
const int FIELD_ID_TIME_BASE = 9;
|
||||
const int FIELD_ID_BUCKET_SIZE = 10;
|
||||
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
|
||||
const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
|
||||
const int FIELD_ID_IS_ACTIVE = 14;
|
||||
// for GaugeMetricDataWrapper
|
||||
const int FIELD_ID_DATA = 1;
|
||||
@@ -115,10 +114,6 @@ GaugeMetricProducer::GaugeMetricProducer(
|
||||
mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
|
||||
}
|
||||
|
||||
if (metric.has_dimensions_in_condition()) {
|
||||
translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
|
||||
}
|
||||
|
||||
if (metric.links().size() > 0) {
|
||||
for (const auto& link : metric.links()) {
|
||||
Metric2Condition mc;
|
||||
@@ -127,10 +122,9 @@ GaugeMetricProducer::GaugeMetricProducer(
|
||||
translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
|
||||
mMetric2ConditionLinks.push_back(mc);
|
||||
}
|
||||
mConditionSliced = true;
|
||||
}
|
||||
mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
|
||||
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
|
||||
HasPositionALL(metric.dimensions_in_condition());
|
||||
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
|
||||
|
||||
flushIfNeededLocked(startTimeNs);
|
||||
// Kicks off the puller immediately.
|
||||
@@ -209,12 +203,6 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
|
||||
writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
|
||||
protoOutput->end(dimenPathToken);
|
||||
}
|
||||
if (!mDimensionsInCondition.empty()) {
|
||||
uint64_t dimenPathToken = protoOutput->start(
|
||||
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
|
||||
writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
|
||||
protoOutput->end(dimenPathToken);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
|
||||
|
||||
@@ -52,38 +52,24 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
|
||||
|
||||
bool condition;
|
||||
ConditionKey conditionKey;
|
||||
std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
|
||||
if (mConditionSliced) {
|
||||
for (const auto& link : mMetric2ConditionLinks) {
|
||||
getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
|
||||
}
|
||||
auto conditionState =
|
||||
mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
|
||||
!mSameConditionDimensionsInTracker,
|
||||
!mHasLinksToAllConditionDimensionsInTracker,
|
||||
&dimensionKeysInCondition);
|
||||
mWizard->query(mConditionTrackerIndex, conditionKey,
|
||||
!mHasLinksToAllConditionDimensionsInTracker);
|
||||
condition = (conditionState == ConditionState::kTrue);
|
||||
} else {
|
||||
// TODO: The unknown condition state is not handled here, we should fix it.
|
||||
condition = mCondition == ConditionState::kTrue;
|
||||
}
|
||||
|
||||
if (mDimensionsInCondition.empty() && condition) {
|
||||
dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
|
||||
}
|
||||
|
||||
HashableDimensionKey dimensionInWhat;
|
||||
filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
|
||||
MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY);
|
||||
for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
|
||||
metricKey.setDimensionKeyInCondition(conditionDimensionKey);
|
||||
onMatchedLogEventInternalLocked(
|
||||
matcherIndex, metricKey, conditionKey, condition, event);
|
||||
}
|
||||
if (dimensionKeysInCondition.empty()) {
|
||||
onMatchedLogEventInternalLocked(
|
||||
matcherIndex, metricKey, conditionKey, condition, event);
|
||||
}
|
||||
onMatchedLogEventInternalLocked(
|
||||
matcherIndex, metricKey, conditionKey, condition, event);
|
||||
}
|
||||
|
||||
bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
|
||||
|
||||
@@ -88,7 +88,6 @@ public:
|
||||
mConditionTrackerIndex(conditionIndex),
|
||||
mContainANYPositionInDimensionsInWhat(false),
|
||||
mSliceByPositionALL(false),
|
||||
mSameConditionDimensionsInTracker(false),
|
||||
mHasLinksToAllConditionDimensionsInTracker(false),
|
||||
mIsActive(true) {
|
||||
}
|
||||
@@ -349,15 +348,10 @@ protected:
|
||||
int mConditionTrackerIndex;
|
||||
|
||||
vector<Matcher> mDimensionsInWhat; // The dimensions_in_what defined in statsd_config
|
||||
vector<Matcher> mDimensionsInCondition; // The dimensions_in_condition defined in statsd_config
|
||||
|
||||
bool mContainANYPositionInDimensionsInWhat;
|
||||
bool mSliceByPositionALL;
|
||||
|
||||
// True iff the condition dimensions equal to the sliced dimensions in the simple condition
|
||||
// tracker. This field is always false for combinational condition trackers.
|
||||
bool mSameConditionDimensionsInTracker;
|
||||
|
||||
// True iff the metric to condition links cover all dimension fields in the condition tracker.
|
||||
// This field is always false for combinational condition trackers.
|
||||
bool mHasLinksToAllConditionDimensionsInTracker;
|
||||
|
||||
@@ -260,17 +260,6 @@ private:
|
||||
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
|
||||
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
|
||||
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
|
||||
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
|
||||
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
|
||||
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition);
|
||||
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition);
|
||||
|
||||
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition);
|
||||
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition);
|
||||
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition);
|
||||
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition);
|
||||
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
|
||||
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition);
|
||||
|
||||
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
|
||||
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
|
||||
|
||||
@@ -51,7 +51,6 @@ const int FIELD_ID_VALUE_METRICS = 7;
|
||||
const int FIELD_ID_TIME_BASE = 9;
|
||||
const int FIELD_ID_BUCKET_SIZE = 10;
|
||||
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
|
||||
const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
|
||||
const int FIELD_ID_IS_ACTIVE = 14;
|
||||
// for ValueMetricDataWrapper
|
||||
const int FIELD_ID_DATA = 1;
|
||||
@@ -127,10 +126,6 @@ ValueMetricProducer::ValueMetricProducer(
|
||||
mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
|
||||
}
|
||||
|
||||
if (metric.has_dimensions_in_condition()) {
|
||||
translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
|
||||
}
|
||||
|
||||
if (metric.links().size() > 0) {
|
||||
for (const auto& link : metric.links()) {
|
||||
Metric2Condition mc;
|
||||
@@ -139,11 +134,10 @@ ValueMetricProducer::ValueMetricProducer(
|
||||
translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
|
||||
mMetric2ConditionLinks.push_back(mc);
|
||||
}
|
||||
mConditionSliced = true;
|
||||
}
|
||||
|
||||
mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
|
||||
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
|
||||
HasPositionALL(metric.dimensions_in_condition());
|
||||
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
|
||||
|
||||
int64_t numBucketsForward = calcBucketsForwardCount(startTimeNs);
|
||||
mCurrentBucketNum += numBucketsForward;
|
||||
@@ -243,12 +237,6 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
|
||||
writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
|
||||
protoOutput->end(dimenPathToken);
|
||||
}
|
||||
if (!mDimensionsInCondition.empty()) {
|
||||
uint64_t dimenPathToken =
|
||||
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
|
||||
writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
|
||||
protoOutput->end(dimenPathToken);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
|
||||
|
||||
@@ -60,7 +60,7 @@ class DurationTracker {
|
||||
public:
|
||||
DurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
|
||||
sp<ConditionWizard> wizard, int conditionIndex,
|
||||
const std::vector<Matcher>& dimensionInCondition, bool nesting,
|
||||
bool nesting,
|
||||
int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs,
|
||||
int64_t bucketSizeNs, bool conditionSliced, bool fullLink,
|
||||
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
|
||||
@@ -70,7 +70,6 @@ public:
|
||||
mWizard(wizard),
|
||||
mConditionTrackerIndex(conditionIndex),
|
||||
mBucketSizeNs(bucketSizeNs),
|
||||
mDimensionInCondition(dimensionInCondition),
|
||||
mNested(nesting),
|
||||
mCurrentBucketStartTimeNs(currentBucketStartNs),
|
||||
mDuration(0),
|
||||
@@ -180,8 +179,6 @@ protected:
|
||||
|
||||
const int64_t mBucketSizeNs;
|
||||
|
||||
const std::vector<Matcher>& mDimensionInCondition;
|
||||
|
||||
const bool mNested;
|
||||
|
||||
int64_t mCurrentBucketStartTimeNs;
|
||||
@@ -196,7 +193,6 @@ protected:
|
||||
|
||||
const bool mConditionSliced;
|
||||
|
||||
bool mSameConditionDimensionsInTracker;
|
||||
bool mHasLinksToAllConditionDimensionsInTracker;
|
||||
|
||||
std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
|
||||
|
||||
@@ -27,18 +27,14 @@ namespace statsd {
|
||||
MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id,
|
||||
const MetricDimensionKey& eventKey,
|
||||
sp<ConditionWizard> wizard, int conditionIndex,
|
||||
const vector<Matcher>& dimensionInCondition, bool nesting,
|
||||
bool nesting,
|
||||
int64_t currentBucketStartNs, int64_t currentBucketNum,
|
||||
int64_t startTimeNs, int64_t bucketSizeNs,
|
||||
bool conditionSliced, bool fullLink,
|
||||
const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
|
||||
: DurationTracker(key, id, eventKey, wizard, conditionIndex, dimensionInCondition, nesting,
|
||||
: DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting,
|
||||
currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs,
|
||||
conditionSliced, fullLink, anomalyTrackers) {
|
||||
if (mWizard != nullptr) {
|
||||
mSameConditionDimensionsInTracker =
|
||||
mWizard->equalOutputDimensions(conditionIndex, mDimensionInCondition);
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<DurationTracker> MaxDurationTracker::clone(const int64_t eventTime) {
|
||||
@@ -252,17 +248,11 @@ void MaxDurationTracker::onSlicedConditionMayChange(bool overallCondition,
|
||||
if (pair.second.state == kStopped) {
|
||||
continue;
|
||||
}
|
||||
std::unordered_set<HashableDimensionKey> conditionDimensionKeySet;
|
||||
ConditionState conditionState = mWizard->query(
|
||||
mConditionTrackerIndex, pair.second.conditionKeys, mDimensionInCondition,
|
||||
!mSameConditionDimensionsInTracker,
|
||||
!mHasLinksToAllConditionDimensionsInTracker,
|
||||
&conditionDimensionKeySet);
|
||||
bool conditionMet =
|
||||
(conditionState == ConditionState::kTrue) &&
|
||||
(mDimensionInCondition.size() == 0 ||
|
||||
conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) !=
|
||||
conditionDimensionKeySet.end());
|
||||
mConditionTrackerIndex, pair.second.conditionKeys,
|
||||
!mHasLinksToAllConditionDimensionsInTracker);
|
||||
bool conditionMet = (conditionState == ConditionState::kTrue);
|
||||
|
||||
VLOG("key: %s, condition: %d", pair.first.toString().c_str(), conditionMet);
|
||||
noteConditionChanged(pair.first, conditionMet, timestamp);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class MaxDurationTracker : public DurationTracker {
|
||||
public:
|
||||
MaxDurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
|
||||
sp<ConditionWizard> wizard, int conditionIndex,
|
||||
const std::vector<Matcher>& dimensionInCondition, bool nesting,
|
||||
bool nesting,
|
||||
int64_t currentBucketStartNs, int64_t currentBucketNum,
|
||||
int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced,
|
||||
bool fullLink,
|
||||
|
||||
@@ -26,20 +26,16 @@ using std::pair;
|
||||
|
||||
OringDurationTracker::OringDurationTracker(
|
||||
const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
|
||||
sp<ConditionWizard> wizard, int conditionIndex, const vector<Matcher>& dimensionInCondition,
|
||||
sp<ConditionWizard> wizard, int conditionIndex,
|
||||
bool nesting, int64_t currentBucketStartNs, int64_t currentBucketNum,
|
||||
int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced, bool fullLink,
|
||||
const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
|
||||
: DurationTracker(key, id, eventKey, wizard, conditionIndex, dimensionInCondition, nesting,
|
||||
: DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting,
|
||||
currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs,
|
||||
conditionSliced, fullLink, anomalyTrackers),
|
||||
mStarted(),
|
||||
mPaused() {
|
||||
mLastStartTime = 0;
|
||||
if (mWizard != nullptr) {
|
||||
mSameConditionDimensionsInTracker =
|
||||
mWizard->equalOutputDimensions(conditionIndex, mDimensionInCondition);
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<DurationTracker> OringDurationTracker::clone(const int64_t eventTime) {
|
||||
@@ -227,17 +223,10 @@ void OringDurationTracker::onSlicedConditionMayChange(bool overallCondition,
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
std::unordered_set<HashableDimensionKey> conditionDimensionKeySet;
|
||||
ConditionState conditionState =
|
||||
mWizard->query(mConditionTrackerIndex, condIt->second,
|
||||
mDimensionInCondition,
|
||||
!mSameConditionDimensionsInTracker,
|
||||
!mHasLinksToAllConditionDimensionsInTracker,
|
||||
&conditionDimensionKeySet);
|
||||
if (conditionState != ConditionState::kTrue ||
|
||||
(mDimensionInCondition.size() != 0 &&
|
||||
conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) ==
|
||||
conditionDimensionKeySet.end())) {
|
||||
!mHasLinksToAllConditionDimensionsInTracker);
|
||||
if (conditionState != ConditionState::kTrue) {
|
||||
startedToPaused.push_back(*it);
|
||||
it = mStarted.erase(it);
|
||||
VLOG("Key %s started -> paused", key.toString().c_str());
|
||||
@@ -262,17 +251,10 @@ void OringDurationTracker::onSlicedConditionMayChange(bool overallCondition,
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
std::unordered_set<HashableDimensionKey> conditionDimensionKeySet;
|
||||
ConditionState conditionState =
|
||||
mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key],
|
||||
mDimensionInCondition,
|
||||
!mSameConditionDimensionsInTracker,
|
||||
!mHasLinksToAllConditionDimensionsInTracker,
|
||||
&conditionDimensionKeySet);
|
||||
if (conditionState == ConditionState::kTrue &&
|
||||
(mDimensionInCondition.size() == 0 ||
|
||||
conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) !=
|
||||
conditionDimensionKeySet.end())) {
|
||||
!mHasLinksToAllConditionDimensionsInTracker);
|
||||
if (conditionState == ConditionState::kTrue) {
|
||||
pausedToStarted.push_back(*it);
|
||||
it = mPaused.erase(it);
|
||||
VLOG("Key %s paused -> started", key.toString().c_str());
|
||||
|
||||
@@ -29,7 +29,7 @@ class OringDurationTracker : public DurationTracker {
|
||||
public:
|
||||
OringDurationTracker(const ConfigKey& key, const int64_t& id,
|
||||
const MetricDimensionKey& eventKey, sp<ConditionWizard> wizard,
|
||||
int conditionIndex, const std::vector<Matcher>& dimensionInCondition,
|
||||
int conditionIndex,
|
||||
bool nesting, int64_t currentBucketStartNs, int64_t currentBucketNum,
|
||||
int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced,
|
||||
bool fullLink,
|
||||
|
||||
@@ -268,8 +268,6 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
|
||||
std::vector<sp<ConditionTracker>> allConditions;
|
||||
for (Position position :
|
||||
{ Position::FIRST, Position::LAST}) {
|
||||
vector<Matcher> dimensionInCondition;
|
||||
std::unordered_set<HashableDimensionKey> dimensionKeys;
|
||||
|
||||
SimplePredicate simplePredicate = getWakeLockHeldCondition(
|
||||
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
|
||||
@@ -321,9 +319,9 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
|
||||
const auto queryKey = getWakeLockQueryKey(position, uids, conditionName);
|
||||
conditionCache[0] = ConditionState::kNotEvaluated;
|
||||
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
||||
false, false,
|
||||
conditionCache, dimensionKeys);
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates,
|
||||
false,
|
||||
conditionCache);
|
||||
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
|
||||
|
||||
// another wake lock acquired by this uid
|
||||
@@ -389,9 +387,9 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
|
||||
|
||||
// query again
|
||||
conditionCache[0] = ConditionState::kNotEvaluated;
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
||||
false, false,
|
||||
conditionCache, dimensionKeys);
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates,
|
||||
false,
|
||||
conditionCache);
|
||||
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
|
||||
}
|
||||
|
||||
@@ -399,8 +397,6 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
|
||||
|
||||
TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
|
||||
std::vector<sp<ConditionTracker>> allConditions;
|
||||
vector<Matcher> dimensionInCondition;
|
||||
std::unordered_set<HashableDimensionKey> dimensionKeys;
|
||||
|
||||
SimplePredicate simplePredicate = getWakeLockHeldCondition(
|
||||
true /*nesting*/, true /*default to false*/, false /*slice output by uid*/,
|
||||
@@ -445,9 +441,9 @@ TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
|
||||
ConditionKey queryKey;
|
||||
conditionCache[0] = ConditionState::kNotEvaluated;
|
||||
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
||||
true, true,
|
||||
conditionCache, dimensionKeys);
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates,
|
||||
true,
|
||||
conditionCache);
|
||||
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
|
||||
|
||||
// another wake lock acquired by this uid
|
||||
@@ -489,10 +485,9 @@ TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
|
||||
|
||||
// query again
|
||||
conditionCache[0] = ConditionState::kNotEvaluated;
|
||||
dimensionKeys.clear();
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
||||
true, true,
|
||||
conditionCache, dimensionKeys);
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates,
|
||||
true,
|
||||
conditionCache);
|
||||
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
|
||||
}
|
||||
|
||||
@@ -500,8 +495,6 @@ TEST(SimpleConditionTrackerTest, TestStopAll) {
|
||||
std::vector<sp<ConditionTracker>> allConditions;
|
||||
for (Position position :
|
||||
{ Position::FIRST, Position::LAST }) {
|
||||
vector<Matcher> dimensionInCondition;
|
||||
std::unordered_set<HashableDimensionKey> dimensionKeys;
|
||||
SimplePredicate simplePredicate = getWakeLockHeldCondition(
|
||||
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
|
||||
position);
|
||||
@@ -555,9 +548,9 @@ TEST(SimpleConditionTrackerTest, TestStopAll) {
|
||||
const auto queryKey = getWakeLockQueryKey(position, uid_list1, conditionName);
|
||||
conditionCache[0] = ConditionState::kNotEvaluated;
|
||||
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
||||
false, false,
|
||||
conditionCache, dimensionKeys);
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates,
|
||||
false,
|
||||
conditionCache);
|
||||
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
|
||||
|
||||
// another wake lock acquired by uid2
|
||||
@@ -594,9 +587,9 @@ TEST(SimpleConditionTrackerTest, TestStopAll) {
|
||||
// TEST QUERY
|
||||
const auto queryKey2 = getWakeLockQueryKey(position, uid_list2, conditionName);
|
||||
conditionCache[0] = ConditionState::kNotEvaluated;
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
||||
false, false,
|
||||
conditionCache, dimensionKeys);
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates,
|
||||
false,
|
||||
conditionCache);
|
||||
|
||||
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
|
||||
|
||||
@@ -628,17 +621,17 @@ TEST(SimpleConditionTrackerTest, TestStopAll) {
|
||||
// TEST QUERY
|
||||
const auto queryKey3 = getWakeLockQueryKey(position, uid_list1, conditionName);
|
||||
conditionCache[0] = ConditionState::kNotEvaluated;
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
||||
false, false,
|
||||
conditionCache, dimensionKeys);
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates,
|
||||
false,
|
||||
conditionCache);
|
||||
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
|
||||
|
||||
// TEST QUERY
|
||||
const auto queryKey4 = getWakeLockQueryKey(position, uid_list2, conditionName);
|
||||
conditionCache[0] = ConditionState::kNotEvaluated;
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
||||
false, false,
|
||||
conditionCache, dimensionKeys);
|
||||
conditionTracker.isConditionMet(queryKey, allPredicates,
|
||||
false,
|
||||
conditionCache);
|
||||
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,961 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "src/StatsLogProcessor.h"
|
||||
#include "src/stats_log_util.h"
|
||||
#include "tests/statsd_test_util.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
namespace {
|
||||
|
||||
StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
|
||||
DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition,
|
||||
bool hashStringInReport) {
|
||||
StatsdConfig config;
|
||||
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
||||
*config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncStartAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncEndAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
|
||||
|
||||
auto scheduledJobPredicate = CreateScheduledJobPredicate();
|
||||
auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
dimensions->add_child()->set_field(2); // job name field.
|
||||
|
||||
auto screenIsOffPredicate = CreateScreenIsOffPredicate();
|
||||
|
||||
auto isSyncingPredicate = CreateIsSyncingPredicate();
|
||||
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
|
||||
{Position::FIRST});
|
||||
if (addExtraDimensionInCondition) {
|
||||
syncDimension->add_child()->set_field(2 /* name field*/);
|
||||
}
|
||||
|
||||
config.set_hash_strings_in_metric_report(hashStringInReport);
|
||||
*config.add_predicate() = scheduledJobPredicate;
|
||||
*config.add_predicate() = screenIsOffPredicate;
|
||||
*config.add_predicate() = isSyncingPredicate;
|
||||
auto combinationPredicate = config.add_predicate();
|
||||
combinationPredicate->set_id(StringToId("CombinationPredicate"));
|
||||
combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
|
||||
addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
|
||||
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
|
||||
|
||||
auto metric = config.add_duration_metric();
|
||||
metric->set_bucket(FIVE_MINUTES);
|
||||
metric->set_id(StringToId("scheduledJob"));
|
||||
metric->set_what(scheduledJobPredicate.id());
|
||||
metric->set_condition(combinationPredicate->id());
|
||||
metric->set_aggregation_type(aggregationType);
|
||||
auto dimensionWhat = metric->mutable_dimensions_in_what();
|
||||
dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
dimensionWhat->add_child()->set_field(2); // job name field.
|
||||
*metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
|
||||
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*
|
||||
The following test has the following input.
|
||||
|
||||
{ 10000000002 10000000002 (8)9999[I], [S], job0[S], 1[I], }
|
||||
{ 10000000010 10000000010 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 1[I], }
|
||||
{ 10000000011 10000000011 (29)1[I], }
|
||||
{ 10000000040 10000000040 (29)2[I], }
|
||||
{ 10000000050 10000000050 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 0[I], }
|
||||
{ 10000000101 10000000101 (8)9999[I], [S], job0[S], 0[I], }
|
||||
{ 10000000102 10000000102 (29)1[I], }
|
||||
{ 10000000200 10000000200 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 1[I], }
|
||||
{ 10000000201 10000000201 (8)9999[I], [S], job2[S], 1[I], }
|
||||
{ 10000000400 10000000400 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadDoc[S], 1[I], }
|
||||
{ 10000000401 10000000401 (7)333[I], App2[S], 222[I], GMSCoreModule1[S], 555[I], GMSCoreModule2[S], ReadEmail[S], 1[I], }
|
||||
{ 10000000450 10000000450 (29)2[I], }
|
||||
{ 10000000500 10000000500 (8)9999[I], [S], job2[S], 0[I], }
|
||||
{ 10000000600 10000000600 (8)8888[I], [S], job2[S], 1[I], }
|
||||
{ 10000000650 10000000650 (29)1[I], }
|
||||
{ 309999999999 309999999999 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadDoc[S], 0[I], }
|
||||
{ 310000000100 310000000100 (29)2[I], }
|
||||
{ 310000000300 310000000300 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 0[I], }
|
||||
{ 310000000600 310000000600 (8)8888[I], [S], job1[S], 1[I], }
|
||||
{ 310000000640 310000000640 (29)1[I], }
|
||||
{ 310000000650 310000000650 (29)2[I], }
|
||||
{ 310000000700 310000000700 (7)333[I], App2[S], 222[I], GMSCoreModule1[S], 555[I], GMSCoreModule2[S], ReadEmail[S], 0[I], }
|
||||
{ 310000000850 310000000850 (8)8888[I], [S], job2[S], 0[I], }
|
||||
{ 310000000900 310000000900 (8)8888[I], [S], job1[S], 0[I], }
|
||||
*/
|
||||
TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition) {
|
||||
for (const bool hashStringInReport : { true, false }) {
|
||||
for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : { true, false }) {
|
||||
for (auto aggregationType : {DurationMetric::MAX_SPARSE, DurationMetric::SUM}) {
|
||||
ConfigKey cfgKey;
|
||||
auto config = CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
|
||||
aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension,
|
||||
hashStringInReport);
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
int64_t bucketSizeNs =
|
||||
TimeUnitToBucketSizeInMillis(
|
||||
config.duration_metric(0).bucket()) * 1000000LL;
|
||||
|
||||
auto processor = CreateStatsLogProcessor(
|
||||
bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
||||
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
|
||||
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions1 = {
|
||||
CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(222, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions2 = {
|
||||
CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<std::unique_ptr<LogEvent>> events;
|
||||
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 11));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 40));
|
||||
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 102));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 450));
|
||||
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 650));
|
||||
events.push_back(CreateScreenStateChangedEvent(
|
||||
android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + bucketSizeNs + 100));
|
||||
|
||||
events.push_back(CreateScreenStateChangedEvent(
|
||||
android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + bucketSizeNs + 640));
|
||||
events.push_back(CreateScreenStateChangedEvent(
|
||||
android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + bucketSizeNs + 650));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(8888, "")}, "job2",
|
||||
bucketStartTimeNs + bucketSizeNs + 850));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(8888, "")}, "job1",
|
||||
bucketStartTimeNs + bucketSizeNs + 600));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(8888, "")}, "job1",
|
||||
bucketStartTimeNs + bucketSizeNs + 900));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 10));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 50));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 200));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 300));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
|
||||
bucketStartTimeNs + 400));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs - 1));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + 401));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
|
||||
sortLogEventsByTimestamp(&events);
|
||||
|
||||
for (const auto& event : events) {
|
||||
processor->OnLogEvent(event.get());
|
||||
}
|
||||
|
||||
ConfigMetricsReportList reports;
|
||||
vector<uint8_t> buffer;
|
||||
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
|
||||
true, ADB_DUMP, FAST, &buffer);
|
||||
EXPECT_TRUE(buffer.size() > 0);
|
||||
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
|
||||
backfillDimensionPath(&reports);
|
||||
backfillStringInReport(&reports);
|
||||
backfillStartEndTimestamp(&reports);
|
||||
|
||||
EXPECT_EQ(reports.reports_size(), 1);
|
||||
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
|
||||
StatsLogReport::DurationMetricDataWrapper metrics;
|
||||
sortMetricDataByDimensionsValue(
|
||||
reports.reports(0).metrics(0).duration_metrics(), &metrics);
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(metrics.data_size(), 4);
|
||||
auto data = metrics.data(0);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().
|
||||
dimensions_value(0).value_str(),
|
||||
"job0"); // job name
|
||||
ValidateAttributionUidAndTagDimension(
|
||||
data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
|
||||
data = metrics.data(1);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().
|
||||
dimensions_value(0).value_str(),
|
||||
"job1"); // job name
|
||||
ValidateAttributionUidAndTagDimension(
|
||||
data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(2);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().
|
||||
dimensions_value(0).value_str(),
|
||||
"job2"); // job name
|
||||
ValidateAttributionUidAndTagDimension(
|
||||
data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201 + bucketSizeNs - 650);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(3);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().
|
||||
dimensions_value(0).value_str(),
|
||||
"job2"); // job name
|
||||
ValidateAttributionUidAndTagDimension(
|
||||
data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401 + bucketSizeNs - 650);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100 + 650 - 640);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
} else {
|
||||
EXPECT_EQ(metrics.data_size(), 4);
|
||||
auto data = metrics.data(0);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().
|
||||
dimensions_value(0).value_str(),
|
||||
"job0"); // job name
|
||||
ValidateAttributionUidAndTagDimension(
|
||||
data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().
|
||||
dimensions_value(0).value_str(),
|
||||
"job1"); // job name
|
||||
ValidateAttributionUidAndTagDimension(
|
||||
data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(2);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
|
||||
"job2"); // job name
|
||||
ValidateAttributionUidAndTagDimension(
|
||||
data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 650 + 100);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(3);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().
|
||||
dimensions_value(0).value_str(),
|
||||
"job2"); // job name
|
||||
ValidateAttributionUidAndTagDimension(
|
||||
data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 650 + 110);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
StatsdConfig CreateDurationMetricConfig_Link_AND_CombinationCondition(
|
||||
DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
|
||||
StatsdConfig config;
|
||||
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
||||
*config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncStartAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncEndAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
|
||||
|
||||
auto scheduledJobPredicate = CreateScheduledJobPredicate();
|
||||
auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*dimensions = CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
dimensions->add_child()->set_field(2); // job name field.
|
||||
|
||||
auto isSyncingPredicate = CreateIsSyncingPredicate();
|
||||
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*syncDimension = CreateAttributionUidDimensions(
|
||||
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
if (addExtraDimensionInCondition) {
|
||||
syncDimension->add_child()->set_field(2 /* name field*/);
|
||||
}
|
||||
|
||||
auto screenIsOffPredicate = CreateScreenIsOffPredicate();
|
||||
|
||||
*config.add_predicate() = scheduledJobPredicate;
|
||||
*config.add_predicate() = screenIsOffPredicate;
|
||||
*config.add_predicate() = isSyncingPredicate;
|
||||
auto combinationPredicate = config.add_predicate();
|
||||
combinationPredicate->set_id(StringToId("CombinationPredicate"));
|
||||
combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
|
||||
addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
|
||||
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
|
||||
|
||||
auto metric = config.add_duration_metric();
|
||||
metric->set_bucket(FIVE_MINUTES);
|
||||
metric->set_id(StringToId("scheduledJob"));
|
||||
metric->set_what(scheduledJobPredicate.id());
|
||||
metric->set_condition(combinationPredicate->id());
|
||||
metric->set_aggregation_type(aggregationType);
|
||||
*metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
|
||||
auto links = metric->add_links();
|
||||
links->set_condition(isSyncingPredicate.id());
|
||||
*links->mutable_fields_in_what() =
|
||||
CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
*links->mutable_fields_in_condition() =
|
||||
CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition) {
|
||||
for (bool isFullLink : {true, false}) {
|
||||
for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
|
||||
ConfigKey cfgKey;
|
||||
auto config = CreateDurationMetricConfig_Link_AND_CombinationCondition(
|
||||
aggregationType, !isFullLink);
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
int64_t bucketSizeNs =
|
||||
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
|
||||
|
||||
auto processor = CreateStatsLogProcessor(
|
||||
bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
||||
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
|
||||
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions1 = {
|
||||
CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(222, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions2 = {
|
||||
CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions3 = {
|
||||
CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<std::unique_ptr<LogEvent>> events;
|
||||
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 55));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 120));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 121));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 450));
|
||||
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 501));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + bucketSizeNs + 100));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2",
|
||||
bucketStartTimeNs + bucketSizeNs + 850));
|
||||
|
||||
events.push_back(
|
||||
CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
|
||||
bucketStartTimeNs + bucketSizeNs - 2));
|
||||
events.push_back(
|
||||
CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
|
||||
bucketStartTimeNs + bucketSizeNs + 900));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 50));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 110));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + 300));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
|
||||
bucketStartTimeNs + 400));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs - 1));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + 550));
|
||||
events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + 800));
|
||||
events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs - 1));
|
||||
events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
|
||||
sortLogEventsByTimestamp(&events);
|
||||
|
||||
for (const auto& event : events) {
|
||||
processor->OnLogEvent(event.get());
|
||||
}
|
||||
|
||||
ConfigMetricsReportList reports;
|
||||
vector<uint8_t> buffer;
|
||||
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
|
||||
true, ADB_DUMP, FAST, &buffer);
|
||||
EXPECT_TRUE(buffer.size() > 0);
|
||||
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
|
||||
backfillDimensionPath(&reports);
|
||||
backfillStringInReport(&reports);
|
||||
backfillStartEndTimestamp(&reports);
|
||||
|
||||
EXPECT_EQ(reports.reports_size(), 1);
|
||||
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
|
||||
StatsLogReport::DurationMetricDataWrapper metrics;
|
||||
sortMetricDataByDimensionsValue(
|
||||
reports.reports(0).metrics(0).duration_metrics(), &metrics);
|
||||
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(metrics.data_size(), 3);
|
||||
auto data = metrics.data(0);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300 + bucketSizeNs - 600);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(2);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
} else {
|
||||
EXPECT_EQ(metrics.data_size(), 3);
|
||||
auto data = metrics.data(0);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(2);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
StatsdConfig CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(
|
||||
DurationMetric::AggregationType aggregationType, bool hashStringInReport) {
|
||||
StatsdConfig config;
|
||||
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
||||
*config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncStartAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncEndAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
|
||||
|
||||
auto scheduledJobPredicate = CreateScheduledJobPredicate();
|
||||
auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*dimensions = CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
dimensions->add_child()->set_field(2); // job name field.
|
||||
|
||||
auto isSyncingPredicate = CreateIsSyncingPredicate();
|
||||
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*syncDimension = CreateAttributionUidDimensions(
|
||||
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
syncDimension->add_child()->set_field(2 /* name field*/);
|
||||
|
||||
auto screenIsOffPredicate = CreateScreenIsOffPredicate();
|
||||
|
||||
config.set_hash_strings_in_metric_report(hashStringInReport);
|
||||
*config.add_predicate() = scheduledJobPredicate;
|
||||
*config.add_predicate() = screenIsOffPredicate;
|
||||
*config.add_predicate() = isSyncingPredicate;
|
||||
auto combinationPredicate = config.add_predicate();
|
||||
combinationPredicate->set_id(StringToId("CombinationPredicate"));
|
||||
combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
|
||||
addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
|
||||
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
|
||||
|
||||
auto metric = config.add_duration_metric();
|
||||
metric->set_bucket(FIVE_MINUTES);
|
||||
metric->set_id(StringToId("scheduledJob"));
|
||||
metric->set_what(scheduledJobPredicate.id());
|
||||
metric->set_condition(combinationPredicate->id());
|
||||
metric->set_aggregation_type(aggregationType);
|
||||
*metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
*metric->mutable_dimensions_in_condition() = *syncDimension;
|
||||
|
||||
|
||||
auto links = metric->add_links();
|
||||
links->set_condition(isSyncingPredicate.id());
|
||||
*links->mutable_fields_in_what() =
|
||||
CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
*links->mutable_fields_in_condition() =
|
||||
CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition) {
|
||||
for (const bool hashStringInReport : {true, false}) {
|
||||
for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
|
||||
ConfigKey cfgKey;
|
||||
auto config =
|
||||
CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(
|
||||
aggregationType, hashStringInReport);
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
int64_t bucketSizeNs =
|
||||
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
|
||||
|
||||
auto processor = CreateStatsLogProcessor(
|
||||
bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
||||
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
|
||||
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions1 = {
|
||||
CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(222, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions2 = {
|
||||
CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions3 = {
|
||||
CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<std::unique_ptr<LogEvent>> events;
|
||||
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 55));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 120));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 121));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 450));
|
||||
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 501));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + bucketSizeNs + 100));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2",
|
||||
bucketStartTimeNs + bucketSizeNs + 850));
|
||||
|
||||
events.push_back(
|
||||
CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
|
||||
bucketStartTimeNs + bucketSizeNs - 2));
|
||||
events.push_back(
|
||||
CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
|
||||
bucketStartTimeNs + bucketSizeNs + 900));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 50));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 110));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + 300));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
|
||||
bucketStartTimeNs + 400));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs - 1));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + 550));
|
||||
events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + 800));
|
||||
events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs - 1));
|
||||
events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
|
||||
sortLogEventsByTimestamp(&events);
|
||||
|
||||
for (const auto& event : events) {
|
||||
processor->OnLogEvent(event.get());
|
||||
}
|
||||
|
||||
ConfigMetricsReportList reports;
|
||||
vector<uint8_t> buffer;
|
||||
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
|
||||
true, ADB_DUMP, FAST, &buffer);
|
||||
EXPECT_TRUE(buffer.size() > 0);
|
||||
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
|
||||
backfillDimensionPath(&reports);
|
||||
backfillStringInReport(&reports);
|
||||
backfillStartEndTimestamp(&reports);
|
||||
|
||||
EXPECT_EQ(reports.reports_size(), 1);
|
||||
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
|
||||
StatsLogReport::DurationMetricDataWrapper metrics;
|
||||
sortMetricDataByDimensionsValue(
|
||||
reports.reports(0).metrics(0).duration_metrics(), &metrics);
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(metrics.data_size(), 4);
|
||||
auto data = metrics.data(0);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
|
||||
EXPECT_EQ("ReadEmail",
|
||||
data.dimensions_in_condition().value_tuple().
|
||||
dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
|
||||
EXPECT_EQ("ReadDoc",
|
||||
data.dimensions_in_condition().value_tuple().
|
||||
dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 600 + 50);
|
||||
|
||||
data = metrics.data(2);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
|
||||
EXPECT_EQ("ReadEmail",
|
||||
data.dimensions_in_condition().value_tuple().
|
||||
dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300 + bucketSizeNs - 600);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(3);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
|
||||
EXPECT_EQ("ReadDoc",
|
||||
data.dimensions_in_condition().value_tuple().
|
||||
dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
} else {
|
||||
EXPECT_EQ(metrics.data_size(), 4);
|
||||
auto data = metrics.data(0);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
|
||||
EXPECT_EQ("ReadEmail",
|
||||
data.dimensions_in_condition().value_tuple().
|
||||
dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
|
||||
EXPECT_EQ("ReadDoc",
|
||||
data.dimensions_in_condition().value_tuple().
|
||||
dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 50);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(2);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
|
||||
EXPECT_EQ("ReadEmail",
|
||||
data.dimensions_in_condition().value_tuple().
|
||||
dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(3);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
|
||||
EXPECT_EQ("ReadDoc",
|
||||
data.dimensions_in_condition().value_tuple().
|
||||
dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||
#endif
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
@@ -1,816 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "src/StatsLogProcessor.h"
|
||||
#include "src/stats_log_util.h"
|
||||
#include "tests/statsd_test_util.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
namespace {
|
||||
|
||||
StatsdConfig CreateCountMetric_NoLink_CombinationCondition_Config() {
|
||||
StatsdConfig config;
|
||||
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
||||
auto screenBrightnessChangeAtomMatcher = CreateScreenBrightnessChangedAtomMatcher();
|
||||
*config.add_atom_matcher() = screenBrightnessChangeAtomMatcher;
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
|
||||
|
||||
auto screenIsOffPredicate = CreateScreenIsOffPredicate();
|
||||
*config.add_predicate() = screenIsOffPredicate;
|
||||
|
||||
auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
|
||||
// The predicate is dimensioning by any attribution node and both by uid and tag.
|
||||
*holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
|
||||
CreateAttributionUidAndTagDimensions(android::util::WAKELOCK_STATE_CHANGED,
|
||||
{Position::FIRST});
|
||||
*config.add_predicate() = holdingWakelockPredicate;
|
||||
|
||||
auto combinationPredicate = config.add_predicate();
|
||||
combinationPredicate->set_id(987654);
|
||||
combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
|
||||
addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
|
||||
addPredicateToPredicateCombination(holdingWakelockPredicate, combinationPredicate);
|
||||
|
||||
auto metric = config.add_count_metric();
|
||||
metric->set_id(StringToId("ScreenBrightnessChangeMetric"));
|
||||
metric->set_what(screenBrightnessChangeAtomMatcher.id());
|
||||
metric->set_condition(combinationPredicate->id());
|
||||
*metric->mutable_dimensions_in_what() =
|
||||
CreateDimensions(android::util::SCREEN_BRIGHTNESS_CHANGED, {1 /* level */});
|
||||
*metric->mutable_dimensions_in_condition() = CreateAttributionUidDimensions(
|
||||
android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
|
||||
metric->set_bucket(FIVE_MINUTES);
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition) {
|
||||
ConfigKey cfgKey;
|
||||
auto config = CreateCountMetric_NoLink_CombinationCondition_Config();
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
int64_t bucketSizeNs =
|
||||
TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
|
||||
|
||||
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
||||
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
|
||||
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
|
||||
CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(222, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(333, "App2"),
|
||||
CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<std::unique_ptr<LogEvent>> events;
|
||||
events.push_back(
|
||||
CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 100));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + bucketSizeNs + 1));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 2 * bucketSizeNs - 10));
|
||||
|
||||
events.push_back(CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 200));
|
||||
events.push_back(
|
||||
CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1));
|
||||
|
||||
events.push_back(CreateAcquireWakelockEvent(attributions2, "wl2",
|
||||
bucketStartTimeNs + bucketSizeNs - 100));
|
||||
events.push_back(CreateReleaseWakelockEvent(attributions2, "wl2",
|
||||
bucketStartTimeNs + 2 * bucketSizeNs - 50));
|
||||
|
||||
events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 11));
|
||||
events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 101));
|
||||
events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 201));
|
||||
events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + 203));
|
||||
events.push_back(
|
||||
CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs - 99));
|
||||
events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs - 2));
|
||||
events.push_back(CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + bucketSizeNs - 1));
|
||||
events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs + 2));
|
||||
events.push_back(
|
||||
CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 11));
|
||||
events.push_back(
|
||||
CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 9));
|
||||
events.push_back(
|
||||
CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 1));
|
||||
|
||||
sortLogEventsByTimestamp(&events);
|
||||
|
||||
for (const auto& event : events) {
|
||||
processor->OnLogEvent(event.get());
|
||||
}
|
||||
|
||||
ConfigMetricsReportList reports;
|
||||
vector<uint8_t> buffer;
|
||||
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
|
||||
ADB_DUMP, FAST, &buffer);
|
||||
EXPECT_TRUE(buffer.size() > 0);
|
||||
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
|
||||
backfillDimensionPath(&reports);
|
||||
backfillStringInReport(&reports);
|
||||
backfillStartEndTimestamp(&reports);
|
||||
|
||||
EXPECT_EQ(reports.reports_size(), 1);
|
||||
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
|
||||
StatsLogReport::CountMetricDataWrapper countMetrics;
|
||||
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
|
||||
|
||||
EXPECT_EQ(countMetrics.data_size(), 7);
|
||||
auto data = countMetrics.data(0);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 123);
|
||||
EXPECT_FALSE(data.dimensions_in_condition().has_field());
|
||||
|
||||
data = countMetrics.data(1);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 123);
|
||||
ValidateAttributionUidDimension(data.dimensions_in_condition(),
|
||||
android::util::WAKELOCK_STATE_CHANGED, 111);
|
||||
|
||||
data = countMetrics.data(2);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 3);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 456);
|
||||
ValidateAttributionUidDimension(data.dimensions_in_condition(),
|
||||
android::util::WAKELOCK_STATE_CHANGED, 111);
|
||||
|
||||
data = countMetrics.data(3);
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).count(), 1);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 456);
|
||||
ValidateAttributionUidDimension(data.dimensions_in_condition(),
|
||||
android::util::WAKELOCK_STATE_CHANGED, 333);
|
||||
|
||||
data = countMetrics.data(4);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
|
||||
EXPECT_FALSE(data.dimensions_in_condition().has_field());
|
||||
|
||||
data = countMetrics.data(5);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
|
||||
ValidateAttributionUidDimension(data.dimensions_in_condition(),
|
||||
android::util::WAKELOCK_STATE_CHANGED, 111);
|
||||
|
||||
data = countMetrics.data(6);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
|
||||
ValidateAttributionUidDimension(data.dimensions_in_condition(),
|
||||
android::util::WAKELOCK_STATE_CHANGED, 333);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
StatsdConfig CreateCountMetric_Link_CombinationCondition() {
|
||||
StatsdConfig config;
|
||||
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
||||
auto appCrashMatcher = CreateProcessCrashAtomMatcher();
|
||||
*config.add_atom_matcher() = appCrashMatcher;
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncStartAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncEndAtomMatcher();
|
||||
|
||||
auto screenIsOffPredicate = CreateScreenIsOffPredicate();
|
||||
auto isSyncingPredicate = CreateIsSyncingPredicate();
|
||||
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
|
||||
{Position::FIRST});
|
||||
syncDimension->add_child()->set_field(2 /* name field*/);
|
||||
|
||||
*config.add_predicate() = screenIsOffPredicate;
|
||||
*config.add_predicate() = isSyncingPredicate;
|
||||
auto combinationPredicate = config.add_predicate();
|
||||
combinationPredicate->set_id(987654);
|
||||
combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
|
||||
addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
|
||||
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
|
||||
|
||||
auto metric = config.add_count_metric();
|
||||
metric->set_bucket(FIVE_MINUTES);
|
||||
metric->set_id(StringToId("AppCrashMetric"));
|
||||
metric->set_what(appCrashMatcher.id());
|
||||
metric->set_condition(combinationPredicate->id());
|
||||
*metric->mutable_dimensions_in_what() =
|
||||
CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1 /* uid */});
|
||||
*metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
|
||||
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
|
||||
// Links between crash atom and condition of app is in syncing.
|
||||
auto links = metric->add_links();
|
||||
links->set_condition(isSyncingPredicate.id());
|
||||
auto dimensionWhat = links->mutable_fields_in_what();
|
||||
dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
|
||||
dimensionWhat->add_child()->set_field(1); // uid field.
|
||||
*links->mutable_fields_in_condition() =
|
||||
CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition) {
|
||||
ConfigKey cfgKey;
|
||||
auto config = CreateCountMetric_Link_CombinationCondition();
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
int64_t bucketSizeNs =
|
||||
TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
|
||||
|
||||
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
||||
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
|
||||
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
||||
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
|
||||
CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(222, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(333, "App2"),
|
||||
CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<std::unique_ptr<LogEvent>> events;
|
||||
|
||||
events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 11));
|
||||
events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 101));
|
||||
events.push_back(CreateAppCrashEvent(222, bucketStartTimeNs + 101));
|
||||
|
||||
events.push_back(CreateAppCrashEvent(222, bucketStartTimeNs + 201));
|
||||
events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 211));
|
||||
events.push_back(CreateAppCrashEvent(333, bucketStartTimeNs + 211));
|
||||
|
||||
events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + 401));
|
||||
events.push_back(CreateAppCrashEvent(333, bucketStartTimeNs + 401));
|
||||
events.push_back(CreateAppCrashEvent(555, bucketStartTimeNs + 401));
|
||||
|
||||
events.push_back(CreateAppCrashEvent(111, bucketStartTimeNs + bucketSizeNs + 301));
|
||||
events.push_back(CreateAppCrashEvent(333, bucketStartTimeNs + bucketSizeNs + 301));
|
||||
|
||||
events.push_back(CreateAppCrashEvent(777, bucketStartTimeNs + bucketSizeNs + 701));
|
||||
|
||||
events.push_back(
|
||||
CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 100));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 202));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
|
||||
events.push_back(
|
||||
CreateSyncEndEvent(attributions1, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
|
||||
events.push_back(
|
||||
CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 400));
|
||||
events.push_back(
|
||||
CreateSyncEndEvent(attributions2, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 600));
|
||||
|
||||
sortLogEventsByTimestamp(&events);
|
||||
|
||||
for (const auto& event : events) {
|
||||
processor->OnLogEvent(event.get());
|
||||
}
|
||||
|
||||
ConfigMetricsReportList reports;
|
||||
vector<uint8_t> buffer;
|
||||
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
|
||||
ADB_DUMP, FAST, &buffer);
|
||||
EXPECT_TRUE(buffer.size() > 0);
|
||||
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
|
||||
backfillDimensionPath(&reports);
|
||||
backfillStringInReport(&reports);
|
||||
backfillStartEndTimestamp(&reports);
|
||||
|
||||
EXPECT_EQ(reports.reports_size(), 1);
|
||||
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
|
||||
StatsLogReport::CountMetricDataWrapper countMetrics;
|
||||
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
|
||||
|
||||
EXPECT_EQ(countMetrics.data_size(), 5);
|
||||
auto data = countMetrics.data(0);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
|
||||
EXPECT_FALSE(data.dimensions_in_condition().has_field());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = countMetrics.data(1);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = countMetrics.data(2);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 222);
|
||||
EXPECT_FALSE(data.dimensions_in_condition().has_field());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = countMetrics.data(3);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 333);
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).count(), 1);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = countMetrics.data(4);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 777);
|
||||
EXPECT_FALSE(data.dimensions_in_condition().has_field());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).count(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
StatsdConfig CreateDurationMetricConfig_NoLink_CombinationCondition(
|
||||
DurationMetric::AggregationType aggregationType) {
|
||||
StatsdConfig config;
|
||||
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
||||
*config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncStartAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncEndAtomMatcher();
|
||||
|
||||
auto inBatterySaverModePredicate = CreateBatterySaverModePredicate();
|
||||
|
||||
auto screenIsOffPredicate = CreateScreenIsOffPredicate();
|
||||
auto isSyncingPredicate = CreateIsSyncingPredicate();
|
||||
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
|
||||
{Position::FIRST});
|
||||
syncDimension->add_child()->set_field(2 /* name field */);
|
||||
|
||||
*config.add_predicate() = inBatterySaverModePredicate;
|
||||
*config.add_predicate() = screenIsOffPredicate;
|
||||
*config.add_predicate() = isSyncingPredicate;
|
||||
auto combinationPredicate = config.add_predicate();
|
||||
combinationPredicate->set_id(987654);
|
||||
combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
|
||||
addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
|
||||
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
|
||||
|
||||
auto metric = config.add_duration_metric();
|
||||
metric->set_bucket(FIVE_MINUTES);
|
||||
metric->set_id(StringToId("BatterySaverModeDurationMetric"));
|
||||
metric->set_what(inBatterySaverModePredicate.id());
|
||||
metric->set_condition(combinationPredicate->id());
|
||||
metric->set_aggregation_type(aggregationType);
|
||||
*metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
|
||||
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition) {
|
||||
for (auto aggregationType : { DurationMetric::MAX_SPARSE, DurationMetric::SUM}) {
|
||||
ConfigKey cfgKey;
|
||||
auto config = CreateDurationMetricConfig_NoLink_CombinationCondition(aggregationType);
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
int64_t bucketSizeNs =
|
||||
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
|
||||
|
||||
auto processor = CreateStatsLogProcessor(
|
||||
bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
||||
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
|
||||
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions1 = {
|
||||
CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(222, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions2 = {
|
||||
CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<std::unique_ptr<LogEvent>> events;
|
||||
|
||||
events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 1));
|
||||
events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 101));
|
||||
events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 110));
|
||||
|
||||
events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 201));
|
||||
events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 500));
|
||||
|
||||
events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 600));
|
||||
events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + bucketSizeNs + 850));
|
||||
|
||||
events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + bucketSizeNs + 870));
|
||||
events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + bucketSizeNs + 900));
|
||||
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 10));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 100));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 202));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + bucketSizeNs + 800));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 300));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
|
||||
events.push_back(
|
||||
CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 401));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
|
||||
sortLogEventsByTimestamp(&events);
|
||||
|
||||
for (const auto& event : events) {
|
||||
processor->OnLogEvent(event.get());
|
||||
}
|
||||
|
||||
ConfigMetricsReportList reports;
|
||||
vector<uint8_t> buffer;
|
||||
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
|
||||
ADB_DUMP, FAST, &buffer);
|
||||
EXPECT_TRUE(buffer.size() > 0);
|
||||
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
|
||||
backfillDimensionPath(&reports);
|
||||
backfillStringInReport(&reports);
|
||||
backfillStartEndTimestamp(&reports);
|
||||
|
||||
EXPECT_EQ(reports.reports_size(), 1);
|
||||
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
|
||||
StatsLogReport::DurationMetricDataWrapper metrics;
|
||||
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metrics);
|
||||
|
||||
EXPECT_EQ(metrics.data_size(), 3);
|
||||
auto data = metrics.data(0);
|
||||
EXPECT_FALSE(data.dimensions_in_what().has_field());
|
||||
EXPECT_FALSE(data.dimensions_in_condition().has_field());
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
} else {
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
|
||||
data = metrics.data(1);
|
||||
EXPECT_FALSE(data.dimensions_in_what().has_field());
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
|
||||
} else {
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 300);
|
||||
}
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(2);
|
||||
EXPECT_FALSE(data.dimensions_in_what().has_field());
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
|
||||
} else {
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs + 700 - 600);
|
||||
}
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
StatsdConfig CreateDurationMetricConfig_Link_CombinationCondition(
|
||||
DurationMetric::AggregationType aggregationType) {
|
||||
StatsdConfig config;
|
||||
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
||||
*config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncStartAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncEndAtomMatcher();
|
||||
|
||||
auto screenIsOffPredicate = CreateScreenIsOffPredicate();
|
||||
auto isSyncingPredicate = CreateIsSyncingPredicate();
|
||||
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
|
||||
{Position::FIRST});
|
||||
syncDimension->add_child()->set_field(2 /* name field */);
|
||||
|
||||
auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
|
||||
*isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
|
||||
CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */});
|
||||
|
||||
*config.add_predicate() = screenIsOffPredicate;
|
||||
*config.add_predicate() = isSyncingPredicate;
|
||||
*config.add_predicate() = isInBackgroundPredicate;
|
||||
auto combinationPredicate = config.add_predicate();
|
||||
combinationPredicate->set_id(987654);
|
||||
combinationPredicate->mutable_combination()->set_operation(LogicalOperation::OR);
|
||||
addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
|
||||
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
|
||||
|
||||
auto metric = config.add_duration_metric();
|
||||
metric->set_bucket(FIVE_MINUTES);
|
||||
metric->set_id(StringToId("AppInBackgroundMetric"));
|
||||
metric->set_what(isInBackgroundPredicate.id());
|
||||
metric->set_condition(combinationPredicate->id());
|
||||
metric->set_aggregation_type(aggregationType);
|
||||
*metric->mutable_dimensions_in_what() =
|
||||
CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */});
|
||||
*metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
|
||||
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
|
||||
// Links between crash atom and condition of app is in syncing.
|
||||
auto links = metric->add_links();
|
||||
links->set_condition(isSyncingPredicate.id());
|
||||
auto dimensionWhat = links->mutable_fields_in_what();
|
||||
dimensionWhat->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
|
||||
dimensionWhat->add_child()->set_field(1); // uid field.
|
||||
*links->mutable_fields_in_condition() =
|
||||
CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition) {
|
||||
for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
|
||||
ConfigKey cfgKey;
|
||||
auto config = CreateDurationMetricConfig_Link_CombinationCondition(aggregationType);
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
int64_t bucketSizeNs =
|
||||
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
|
||||
|
||||
auto processor = CreateStatsLogProcessor(
|
||||
bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
||||
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
|
||||
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions1 = {
|
||||
CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(222, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions2 = {
|
||||
CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<std::unique_ptr<LogEvent>> events;
|
||||
|
||||
events.push_back(CreateMoveToBackgroundEvent(111, bucketStartTimeNs + 101));
|
||||
events.push_back(CreateMoveToForegroundEvent(111, bucketStartTimeNs + 110));
|
||||
|
||||
events.push_back(CreateMoveToBackgroundEvent(111, bucketStartTimeNs + 201));
|
||||
events.push_back(CreateMoveToForegroundEvent(111, bucketStartTimeNs + bucketSizeNs + 100));
|
||||
|
||||
events.push_back(CreateMoveToBackgroundEvent(333, bucketStartTimeNs + 399));
|
||||
events.push_back(CreateMoveToForegroundEvent(333, bucketStartTimeNs + bucketSizeNs + 800));
|
||||
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 10));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + 100));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
|
||||
bucketStartTimeNs + 202));
|
||||
events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
|
||||
bucketStartTimeNs + bucketSizeNs + 801));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 300));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
|
||||
events.push_back(
|
||||
CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 401));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
|
||||
sortLogEventsByTimestamp(&events);
|
||||
|
||||
for (const auto& event : events) {
|
||||
processor->OnLogEvent(event.get());
|
||||
}
|
||||
|
||||
ConfigMetricsReportList reports;
|
||||
vector<uint8_t> buffer;
|
||||
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
|
||||
ADB_DUMP, FAST, &buffer);
|
||||
EXPECT_TRUE(buffer.size() > 0);
|
||||
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
|
||||
backfillDimensionPath(&reports);
|
||||
backfillStringInReport(&reports);
|
||||
backfillStartEndTimestamp(&reports);
|
||||
|
||||
EXPECT_EQ(reports.reports_size(), 1);
|
||||
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
|
||||
StatsLogReport::DurationMetricDataWrapper metrics;
|
||||
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metrics);
|
||||
|
||||
EXPECT_EQ(metrics.data_size(), 3);
|
||||
auto data = metrics.data(0);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
|
||||
EXPECT_FALSE(data.dimensions_in_condition().has_field());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 201);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
} else {
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs + 100 - 201);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
|
||||
data = metrics.data(2);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 333);
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 401);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
} else {
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs + 299);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||
#endif
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
@@ -1,814 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "src/StatsLogProcessor.h"
|
||||
#include "src/stats_log_util.h"
|
||||
#include "tests/statsd_test_util.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
namespace {
|
||||
|
||||
StatsdConfig CreateDurationMetricConfig_NoLink_SimpleCondition(
|
||||
DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
|
||||
StatsdConfig config;
|
||||
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
||||
*config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncStartAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncEndAtomMatcher();
|
||||
|
||||
auto scheduledJobPredicate = CreateScheduledJobPredicate();
|
||||
auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
dimensions->add_child()->set_field(2); // job name field.
|
||||
|
||||
auto isSyncingPredicate = CreateIsSyncingPredicate();
|
||||
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
|
||||
{Position::FIRST});
|
||||
if (addExtraDimensionInCondition) {
|
||||
syncDimension->add_child()->set_field(2 /* name field*/);
|
||||
}
|
||||
|
||||
*config.add_predicate() = scheduledJobPredicate;
|
||||
*config.add_predicate() = isSyncingPredicate;
|
||||
|
||||
auto metric = config.add_duration_metric();
|
||||
metric->set_bucket(FIVE_MINUTES);
|
||||
metric->set_id(StringToId("scheduledJob"));
|
||||
metric->set_what(scheduledJobPredicate.id());
|
||||
metric->set_condition(isSyncingPredicate.id());
|
||||
metric->set_aggregation_type(aggregationType);
|
||||
auto dimensionWhat = metric->mutable_dimensions_in_what();
|
||||
dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
dimensionWhat->add_child()->set_field(2); // job name field.
|
||||
*metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
|
||||
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition) {
|
||||
for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : {true, false}) {
|
||||
for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
|
||||
ConfigKey cfgKey;
|
||||
auto config = CreateDurationMetricConfig_NoLink_SimpleCondition(
|
||||
aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension);
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
int64_t bucketSizeNs =
|
||||
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
|
||||
|
||||
auto processor = CreateStatsLogProcessor(
|
||||
bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
||||
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
|
||||
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions1 = {
|
||||
CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(222, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions2 = {
|
||||
CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<std::unique_ptr<LogEvent>> events;
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 1));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 10));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 50));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 200));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 300));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
|
||||
bucketStartTimeNs + 400));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs - 1));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + 401));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
|
||||
sortLogEventsByTimestamp(&events);
|
||||
|
||||
for (const auto& event : events) {
|
||||
processor->OnLogEvent(event.get());
|
||||
}
|
||||
|
||||
ConfigMetricsReportList reports;
|
||||
vector<uint8_t> buffer;
|
||||
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
|
||||
true, ADB_DUMP, FAST, &buffer);
|
||||
EXPECT_TRUE(buffer.size() > 0);
|
||||
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
|
||||
backfillDimensionPath(&reports);
|
||||
backfillStringInReport(&reports);
|
||||
backfillStartEndTimestamp(&reports);
|
||||
|
||||
EXPECT_EQ(reports.reports_size(), 1);
|
||||
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
|
||||
StatsLogReport::DurationMetricDataWrapper metrics;
|
||||
sortMetricDataByDimensionsValue(
|
||||
reports.reports(0).metrics(0).duration_metrics(), &metrics);
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(metrics.data_size(), 4);
|
||||
auto data = metrics.data(0);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
|
||||
"job0"); // job name
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
|
||||
"job1"); // job name
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(2);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
|
||||
"job2"); // job name
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(3);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
|
||||
"job2"); // job name
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
} else {
|
||||
EXPECT_EQ(metrics.data_size(), 4);
|
||||
auto data = metrics.data(0);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
|
||||
"job0"); // job name
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
|
||||
"job1"); // job name
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(2);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
|
||||
"job2"); // job name
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 111, "App1");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 300);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(3);
|
||||
EXPECT_EQ(data.dimensions_in_what().field(),
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED);
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
|
||||
2); // job name field
|
||||
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
|
||||
"job2"); // job name
|
||||
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
|
||||
android::util::SYNC_STATE_CHANGED, 333, "App2");
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 );
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
StatsdConfig createDurationMetric_Link_SimpleConditionConfig(
|
||||
DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
|
||||
StatsdConfig config;
|
||||
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
||||
*config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncStartAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncEndAtomMatcher();
|
||||
|
||||
auto scheduledJobPredicate = CreateScheduledJobPredicate();
|
||||
auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*dimensions = CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
dimensions->add_child()->set_field(2); // job name field.
|
||||
|
||||
auto isSyncingPredicate = CreateIsSyncingPredicate();
|
||||
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*syncDimension = CreateAttributionUidDimensions(
|
||||
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
if (addExtraDimensionInCondition) {
|
||||
syncDimension->add_child()->set_field(2 /* name field*/);
|
||||
}
|
||||
|
||||
*config.add_predicate() = scheduledJobPredicate;
|
||||
*config.add_predicate() = isSyncingPredicate;
|
||||
|
||||
auto metric = config.add_duration_metric();
|
||||
metric->set_bucket(FIVE_MINUTES);
|
||||
metric->set_id(StringToId("scheduledJob"));
|
||||
metric->set_what(scheduledJobPredicate.id());
|
||||
metric->set_condition(isSyncingPredicate.id());
|
||||
metric->set_aggregation_type(aggregationType);
|
||||
*metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
|
||||
auto links = metric->add_links();
|
||||
links->set_condition(isSyncingPredicate.id());
|
||||
*links->mutable_fields_in_what() =
|
||||
CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
*links->mutable_fields_in_condition() =
|
||||
CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition) {
|
||||
for (bool isFullLink : {true, false}) {
|
||||
for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
|
||||
ConfigKey cfgKey;
|
||||
auto config = createDurationMetric_Link_SimpleConditionConfig(
|
||||
aggregationType, !isFullLink);
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
int64_t bucketSizeNs =
|
||||
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
|
||||
|
||||
auto processor = CreateStatsLogProcessor(
|
||||
bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
||||
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
|
||||
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions1 = {
|
||||
CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(222, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions2 = {
|
||||
CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions3 = {
|
||||
CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<std::unique_ptr<LogEvent>> events;
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
|
||||
events.push_back(
|
||||
CreateFinishScheduledJobEvent({CreateAttribution(333, "App2")}, "job2",
|
||||
bucketStartTimeNs + bucketSizeNs + 850));
|
||||
|
||||
events.push_back(
|
||||
CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
|
||||
bucketStartTimeNs + bucketSizeNs - 2));
|
||||
events.push_back(
|
||||
CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
|
||||
bucketStartTimeNs + bucketSizeNs + 900));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 50));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 110));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + 300));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
|
||||
bucketStartTimeNs + 400));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs - 1));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + 550));
|
||||
events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + 800));
|
||||
events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs - 1));
|
||||
events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
|
||||
sortLogEventsByTimestamp(&events);
|
||||
|
||||
for (const auto& event : events) {
|
||||
processor->OnLogEvent(event.get());
|
||||
}
|
||||
|
||||
ConfigMetricsReportList reports;
|
||||
vector<uint8_t> buffer;
|
||||
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
|
||||
true, ADB_DUMP, FAST, &buffer);
|
||||
EXPECT_TRUE(buffer.size() > 0);
|
||||
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
|
||||
backfillDimensionPath(&reports);
|
||||
backfillStringInReport(&reports);
|
||||
backfillStartEndTimestamp(&reports);
|
||||
|
||||
EXPECT_EQ(reports.reports_size(), 1);
|
||||
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
|
||||
StatsLogReport::DurationMetricDataWrapper metrics;
|
||||
sortMetricDataByDimensionsValue(
|
||||
reports.reports(0).metrics(0).duration_metrics(), &metrics);
|
||||
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(metrics.data_size(), 3);
|
||||
auto data = metrics.data(0);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(2);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
} else {
|
||||
EXPECT_EQ(metrics.data_size(), 3);
|
||||
auto data = metrics.data(0);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(2);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
StatsdConfig createDurationMetric_PartialLink_SimpleConditionConfig(
|
||||
DurationMetric::AggregationType aggregationType) {
|
||||
StatsdConfig config;
|
||||
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
||||
*config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncStartAtomMatcher();
|
||||
*config.add_atom_matcher() = CreateSyncEndAtomMatcher();
|
||||
|
||||
auto scheduledJobPredicate = CreateScheduledJobPredicate();
|
||||
auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*dimensions = CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
dimensions->add_child()->set_field(2); // job name field.
|
||||
|
||||
auto isSyncingPredicate = CreateIsSyncingPredicate();
|
||||
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
|
||||
*syncDimension = CreateAttributionUidDimensions(
|
||||
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
syncDimension->add_child()->set_field(2 /* name field*/);
|
||||
|
||||
*config.add_predicate() = scheduledJobPredicate;
|
||||
*config.add_predicate() = isSyncingPredicate;
|
||||
|
||||
auto metric = config.add_duration_metric();
|
||||
metric->set_bucket(FIVE_MINUTES);
|
||||
metric->set_id(StringToId("scheduledJob"));
|
||||
metric->set_what(scheduledJobPredicate.id());
|
||||
metric->set_condition(isSyncingPredicate.id());
|
||||
metric->set_aggregation_type(aggregationType);
|
||||
*metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
*metric->mutable_dimensions_in_condition() = *syncDimension;
|
||||
|
||||
auto links = metric->add_links();
|
||||
links->set_condition(isSyncingPredicate.id());
|
||||
*links->mutable_fields_in_what() =
|
||||
CreateAttributionUidDimensions(
|
||||
android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
|
||||
*links->mutable_fields_in_condition() =
|
||||
CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition) {
|
||||
for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
|
||||
ConfigKey cfgKey;
|
||||
auto config = createDurationMetric_PartialLink_SimpleConditionConfig(
|
||||
aggregationType);
|
||||
int64_t bucketStartTimeNs = 10000000000;
|
||||
int64_t bucketSizeNs =
|
||||
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
|
||||
|
||||
auto processor = CreateStatsLogProcessor(
|
||||
bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
||||
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
|
||||
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions1 = {
|
||||
CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(222, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions2 = {
|
||||
CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<AttributionNodeInternal> attributions3 = {
|
||||
CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
|
||||
CreateAttribution(555, "GMSCoreModule2")};
|
||||
|
||||
std::vector<std::unique_ptr<LogEvent>> events;
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
|
||||
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
|
||||
events.push_back(CreateStartScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
|
||||
events.push_back(CreateFinishScheduledJobEvent(
|
||||
{CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + bucketSizeNs + 850));
|
||||
|
||||
events.push_back(
|
||||
CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
|
||||
bucketStartTimeNs + bucketSizeNs - 2));
|
||||
events.push_back(
|
||||
CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
|
||||
bucketStartTimeNs + bucketSizeNs + 900));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 50));
|
||||
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
|
||||
bucketStartTimeNs + 110));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + 300));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
|
||||
bucketStartTimeNs + 400));
|
||||
events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs - 1));
|
||||
|
||||
events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + 550));
|
||||
events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + 800));
|
||||
events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs - 1));
|
||||
events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
|
||||
bucketStartTimeNs + bucketSizeNs + 700));
|
||||
|
||||
sortLogEventsByTimestamp(&events);
|
||||
|
||||
for (const auto& event : events) {
|
||||
processor->OnLogEvent(event.get());
|
||||
}
|
||||
|
||||
ConfigMetricsReportList reports;
|
||||
vector<uint8_t> buffer;
|
||||
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
|
||||
ADB_DUMP, FAST, &buffer);
|
||||
EXPECT_TRUE(buffer.size() > 0);
|
||||
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
|
||||
backfillDimensionPath(&reports);
|
||||
backfillStringInReport(&reports);
|
||||
backfillStartEndTimestamp(&reports);
|
||||
|
||||
EXPECT_EQ(reports.reports_size(), 1);
|
||||
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
|
||||
StatsLogReport::DurationMetricDataWrapper metrics;
|
||||
sortMetricDataByDimensionsValue(
|
||||
reports.reports(0).metrics(0).duration_metrics(), &metrics);
|
||||
|
||||
if (aggregationType == DurationMetric::SUM) {
|
||||
EXPECT_EQ(4, metrics.data_size());
|
||||
auto data = metrics.data(0);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
|
||||
EXPECT_EQ("ReadEmail",
|
||||
data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
|
||||
EXPECT_EQ("ReadDoc",
|
||||
data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 400 - 100);
|
||||
|
||||
data = metrics.data(2);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
|
||||
EXPECT_EQ("ReadEmail",
|
||||
data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(3);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
|
||||
EXPECT_EQ("ReadDoc",
|
||||
data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
} else {
|
||||
EXPECT_EQ(metrics.data_size(), 4);
|
||||
auto data = metrics.data(0);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
|
||||
EXPECT_EQ("ReadEmail",
|
||||
data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
|
||||
data = metrics.data(1);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
|
||||
EXPECT_EQ("ReadDoc",
|
||||
data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
|
||||
|
||||
data = metrics.data(2);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
|
||||
EXPECT_EQ("ReadEmail",
|
||||
data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 2);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300);
|
||||
EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
|
||||
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
|
||||
data = metrics.data(3);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
|
||||
ValidateAttributionUidDimension(
|
||||
data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
|
||||
EXPECT_EQ("ReadDoc",
|
||||
data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
|
||||
EXPECT_EQ(data.bucket_info_size(), 1);
|
||||
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701);
|
||||
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + bucketSizeNs);
|
||||
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
|
||||
bucketStartTimeNs + 2 * bucketSizeNs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||
#endif
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
@@ -187,9 +187,9 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
|
||||
{getMockedDimensionKey(conditionTagId, 2, "222")};
|
||||
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)).WillOnce(Return(ConditionState::kFalse));
|
||||
EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
|
||||
|
||||
EXPECT_CALL(*wizard, query(_, key2, _, _, _, _)).WillOnce(Return(ConditionState::kTrue));
|
||||
EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
|
||||
|
||||
CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
|
||||
bucketStartTimeNs, bucketStartTimeNs);
|
||||
|
||||
@@ -113,9 +113,9 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
|
||||
key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "222")};
|
||||
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)).WillOnce(Return(ConditionState::kFalse));
|
||||
EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
|
||||
|
||||
EXPECT_CALL(*wizard, query(_, key2, _, _, _, _)).WillOnce(Return(ConditionState::kTrue));
|
||||
EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
|
||||
|
||||
EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
|
||||
|
||||
|
||||
@@ -485,10 +485,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
|
||||
dim->set_field(tagId);
|
||||
dim->add_child()->set_field(1);
|
||||
|
||||
dim = metric.mutable_dimensions_in_condition();
|
||||
dim->set_field(conditionTag);
|
||||
dim->add_child()->set_field(1);
|
||||
|
||||
UidMap uidMap;
|
||||
SimpleAtomMatcher atomMatcher;
|
||||
atomMatcher.set_atom_id(tagId);
|
||||
@@ -496,18 +492,14 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
|
||||
new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
|
||||
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
EXPECT_CALL(*wizard, query(_, _, _, _, _, _))
|
||||
EXPECT_CALL(*wizard, query(_, _, _))
|
||||
.WillRepeatedly(
|
||||
Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
|
||||
const vector<Matcher>& dimensionFields, const bool isSubsetDim,
|
||||
const bool isPartialLink,
|
||||
std::unordered_set<HashableDimensionKey>* dimensionKeySet) {
|
||||
dimensionKeySet->clear();
|
||||
const bool isPartialLink) {
|
||||
int pos[] = {1, 0, 0};
|
||||
Field f(conditionTag, pos, 0);
|
||||
HashableDimensionKey key;
|
||||
key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
|
||||
dimensionKeySet->insert(key);
|
||||
|
||||
return ConditionState::kTrue;
|
||||
}));
|
||||
@@ -538,9 +530,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
|
||||
EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
|
||||
EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
|
||||
|
||||
EXPECT_EQ(1UL, key.getDimensionKeyInCondition().getValues().size());
|
||||
EXPECT_EQ(1000000, key.getDimensionKeyInCondition().getValues()[0].mValue.int_value);
|
||||
|
||||
EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
|
||||
|
||||
vector<shared_ptr<LogEvent>> allData;
|
||||
|
||||
@@ -52,7 +52,6 @@ TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
|
||||
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
|
||||
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
|
||||
|
||||
vector<Matcher> dimensionInCondition;
|
||||
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
@@ -63,7 +62,7 @@ TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
|
||||
int64_t bucketNum = 0;
|
||||
|
||||
int64_t metricId = 1;
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
|
||||
false, false, {});
|
||||
|
||||
@@ -88,7 +87,6 @@ TEST(MaxDurationTrackerTest, TestStopAll) {
|
||||
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
|
||||
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
|
||||
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
|
||||
@@ -99,7 +97,7 @@ TEST(MaxDurationTrackerTest, TestStopAll) {
|
||||
int64_t bucketNum = 0;
|
||||
|
||||
int64_t metricId = 1;
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
|
||||
false, false, {});
|
||||
|
||||
@@ -124,7 +122,6 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
|
||||
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
|
||||
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
|
||||
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
|
||||
@@ -135,7 +132,7 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
|
||||
int64_t bucketNum = 0;
|
||||
|
||||
int64_t metricId = 1;
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
|
||||
false, false, {});
|
||||
|
||||
@@ -165,7 +162,6 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
|
||||
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
|
||||
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
|
||||
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
|
||||
@@ -176,7 +172,7 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
|
||||
int64_t bucketNum = 0;
|
||||
|
||||
int64_t metricId = 1;
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1,
|
||||
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
|
||||
false, false, {});
|
||||
|
||||
@@ -202,7 +198,6 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
|
||||
TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
|
||||
const HashableDimensionKey conditionDimKey = key1;
|
||||
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
ConditionKey conditionKey1;
|
||||
@@ -223,7 +218,7 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
|
||||
int64_t eventStopTimeNs = conditionStops2 + 8 * NS_PER_SEC;
|
||||
|
||||
int64_t metricId = 1;
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
false, bucketStartTimeNs, 0, bucketStartTimeNs, bucketSizeNs, true,
|
||||
false, {});
|
||||
EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
|
||||
@@ -246,7 +241,6 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
|
||||
}
|
||||
|
||||
TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
ConditionKey conditionKey1;
|
||||
@@ -273,7 +267,7 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
|
||||
true, false, {anomalyTracker});
|
||||
|
||||
@@ -295,7 +289,6 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
|
||||
// This tests that we correctly compute the predicted time of an anomaly assuming that the current
|
||||
// state continues forward as-is.
|
||||
TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp) {
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
ConditionKey conditionKey1;
|
||||
@@ -333,7 +326,7 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
|
||||
true, false, {anomalyTracker});
|
||||
|
||||
@@ -381,7 +374,6 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp) {
|
||||
// Suppose A starts, then B starts, and then A stops. We still need to set an anomaly based on the
|
||||
// elapsed duration of B.
|
||||
TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop) {
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
ConditionKey conditionKey1;
|
||||
@@ -416,7 +408,7 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
|
||||
true, false, {anomalyTracker});
|
||||
|
||||
@@ -434,4 +426,4 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop) {
|
||||
} // namespace android
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -51,7 +51,6 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) {
|
||||
|
||||
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
|
||||
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
|
||||
@@ -62,7 +61,7 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) {
|
||||
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
|
||||
int64_t durationTimeNs = 2 * 1000;
|
||||
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, false, false, {});
|
||||
|
||||
@@ -84,7 +83,6 @@ TEST(OringDurationTrackerTest, TestDurationNested) {
|
||||
|
||||
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
|
||||
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
|
||||
@@ -94,7 +92,7 @@ TEST(OringDurationTrackerTest, TestDurationNested) {
|
||||
int64_t bucketNum = 0;
|
||||
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
|
||||
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, false, false, {});
|
||||
|
||||
@@ -117,7 +115,6 @@ TEST(OringDurationTrackerTest, TestStopAll) {
|
||||
{getMockedDimensionKey(TagId, 1, "maps")};
|
||||
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
|
||||
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
|
||||
@@ -127,7 +124,7 @@ TEST(OringDurationTrackerTest, TestStopAll) {
|
||||
int64_t bucketNum = 0;
|
||||
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
|
||||
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, false, false, {});
|
||||
|
||||
@@ -147,7 +144,6 @@ TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
|
||||
|
||||
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
|
||||
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
|
||||
@@ -158,7 +154,7 @@ TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
|
||||
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
|
||||
int64_t durationTimeNs = 2 * 1000;
|
||||
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, false, false, {});
|
||||
|
||||
@@ -186,13 +182,12 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) {
|
||||
|
||||
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
|
||||
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
ConditionKey key1;
|
||||
key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
|
||||
|
||||
EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)) // #4
|
||||
EXPECT_CALL(*wizard, query(_, key1, _)) // #4
|
||||
.WillOnce(Return(ConditionState::kFalse));
|
||||
|
||||
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
|
||||
@@ -203,7 +198,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) {
|
||||
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
|
||||
int64_t durationTimeNs = 2 * 1000;
|
||||
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, true, false, {});
|
||||
|
||||
@@ -224,13 +219,12 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
|
||||
|
||||
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
|
||||
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
ConditionKey key1;
|
||||
key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
|
||||
|
||||
EXPECT_CALL(*wizard, query(_, key1, _, _, _, _))
|
||||
EXPECT_CALL(*wizard, query(_, key1, _))
|
||||
.Times(2)
|
||||
.WillOnce(Return(ConditionState::kFalse))
|
||||
.WillOnce(Return(ConditionState::kTrue));
|
||||
@@ -243,7 +237,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
|
||||
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
|
||||
int64_t durationTimeNs = 2 * 1000;
|
||||
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, true, false, {});
|
||||
|
||||
@@ -266,13 +260,12 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
|
||||
|
||||
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
|
||||
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
|
||||
|
||||
ConditionKey key1;
|
||||
key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
|
||||
|
||||
EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)) // #4
|
||||
EXPECT_CALL(*wizard, query(_, key1, _)) // #4
|
||||
.WillOnce(Return(ConditionState::kFalse));
|
||||
|
||||
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
|
||||
@@ -282,7 +275,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
|
||||
int64_t bucketNum = 0;
|
||||
int64_t eventStartTimeNs = bucketStartTimeNs + 1;
|
||||
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, true, false, {});
|
||||
|
||||
@@ -306,7 +299,6 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
|
||||
|
||||
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
|
||||
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
Alert alert;
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(1);
|
||||
@@ -324,7 +316,7 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, true, false, {anomalyTracker});
|
||||
|
||||
@@ -371,7 +363,6 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
|
||||
}
|
||||
|
||||
TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp2) {
|
||||
vector<Matcher> dimensionInCondition;
|
||||
Alert alert;
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(1);
|
||||
@@ -387,7 +378,7 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp2) {
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
OringDurationTracker tracker(kConfigKey, metricId, DEFAULT_METRIC_DIMENSION_KEY, wizard, 1,
|
||||
dimensionInCondition,
|
||||
|
||||
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, true, false, {anomalyTracker});
|
||||
|
||||
@@ -415,7 +406,7 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp3) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int64_t thresholdNs = j * bucketSizeNs + 5 * NS_PER_SEC;
|
||||
for (int i = 0; i <= 7; ++i) {
|
||||
vector<Matcher> dimensionInCondition;
|
||||
|
||||
Alert alert;
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(1);
|
||||
@@ -432,7 +423,7 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp3) {
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
OringDurationTracker tracker(kConfigKey, metricId, DEFAULT_METRIC_DIMENSION_KEY,
|
||||
wizard, 1, dimensionInCondition,
|
||||
wizard, 1,
|
||||
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, true, false, {anomalyTracker});
|
||||
|
||||
@@ -472,7 +463,6 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
|
||||
|
||||
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
|
||||
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
Alert alert;
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(1);
|
||||
@@ -491,7 +481,7 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
true /*nesting*/, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
|
||||
bucketSizeNs, false, false, {anomalyTracker});
|
||||
|
||||
@@ -522,7 +512,6 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
|
||||
|
||||
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
|
||||
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
|
||||
vector<Matcher> dimensionInCondition;
|
||||
Alert alert;
|
||||
alert.set_id(101);
|
||||
alert.set_metric_id(1);
|
||||
@@ -541,7 +530,7 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
|
||||
sp<AlarmMonitor> alarmMonitor;
|
||||
sp<DurationAnomalyTracker> anomalyTracker =
|
||||
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
|
||||
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1,
|
||||
true /*nesting*/, bucketStartTimeNs, 0, bucketStartTimeNs,
|
||||
bucketSizeNs, false, false, {anomalyTracker});
|
||||
|
||||
@@ -589,4 +578,4 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
|
||||
} // namespace android
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -26,11 +26,9 @@ namespace statsd {
|
||||
|
||||
class MockConditionWizard : public ConditionWizard {
|
||||
public:
|
||||
MOCK_METHOD6(query,
|
||||
MOCK_METHOD3(query,
|
||||
ConditionState(const int conditionIndex, const ConditionKey& conditionParameters,
|
||||
const vector<Matcher>& dimensionFields,
|
||||
const bool isSubsetDim, const bool isPartialLink,
|
||||
std::unordered_set<HashableDimensionKey>* dimensionKeySet));
|
||||
const bool isPartialLink));
|
||||
};
|
||||
|
||||
class MockStatsPullerManager : public StatsPullerManager {
|
||||
@@ -55,4 +53,4 @@ void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher);
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
} // namespace android
|
||||
|
||||
Reference in New Issue
Block a user