diff options
22 files changed, 7293 insertions, 7175 deletions
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 3940aa8e1243..b68eeb8d6499 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -328,4 +328,3 @@ void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::v } // namespace statsd } // namespace os } // namespace android - diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp index 4b78e305f65c..7febb35355a3 100644 --- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp +++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp @@ -137,7 +137,9 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) { simplePredicate, trackerNameIndexMap); EXPECT_FALSE(conditionTracker.isSliced()); - LogEvent event(1 /*tagId*/, 0 /*timestamp*/); + // This event is not accessed in this test besides dimensions which is why this is okay. + // This is technically an invalid LogEvent because we do not call parseBuffer. + LogEvent event(/*uid=*/0, /*pid=*/0); vector<MatchingState> matcherState; matcherState.push_back(MatchingState::kNotMatched); @@ -222,7 +224,9 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) { trackerNameIndexMap); EXPECT_FALSE(conditionTracker.isSliced()); - LogEvent event(1 /*tagId*/, 0 /*timestamp*/); + // This event is not accessed in this test besides dimensions which is why this is okay. + // This is technically an invalid LogEvent because we do not call parseBuffer. + LogEvent event(/*uid=*/0, /*pid=*/0); // one matched start vector<MatchingState> matcherState; @@ -296,8 +300,8 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) { std::vector<int> uids = {111, 222, 333}; - LogEvent event(/*uid=*/-1, /*pid=*/-1); - makeWakeLockEvent(&event, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1); + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1); // one matched start vector<MatchingState> matcherState; @@ -308,7 +312,7 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) { vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated); vector<bool> changedCache(1, false); - conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache, + conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache, changedCache); if (position == Position::FIRST || position == Position::LAST) { @@ -333,7 +337,7 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) { EXPECT_EQ(ConditionState::kTrue, conditionCache[0]); // another wake lock acquired by this uid - LogEvent event2(/*uid=*/-1, /*pid=*/-1); + LogEvent event2(/*uid=*/0, /*pid=*/0); makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/1); matcherState.clear(); matcherState.push_back(MatchingState::kMatched); @@ -353,7 +357,7 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) { // wake lock 1 release - LogEvent event3(/*uid=*/-1, /*pid=*/-1); + LogEvent event3(/*uid=*/0, /*pid=*/0); makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/0); matcherState.clear(); matcherState.push_back(MatchingState::kNotMatched); @@ -372,7 +376,7 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) { EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); - LogEvent event4(/*uid=*/-1, /*pid=*/-1); + LogEvent event4(/*uid=*/0, /*pid=*/0); makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/0); matcherState.clear(); matcherState.push_back(MatchingState::kNotMatched); @@ -399,246 +403,235 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) { } -//TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) { -// std::vector<sp<ConditionTracker>> allConditions; -// -// SimplePredicate simplePredicate = getWakeLockHeldCondition( -// true /*nesting*/, true /*default to false*/, false /*slice output by uid*/, -// Position::ANY /* position */); -// string conditionName = "WL_HELD"; -// -// unordered_map<int64_t, int> trackerNameIndexMap; -// trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0; -// trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; -// trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; -// -// SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), -// 0 /*condition tracker index*/, simplePredicate, -// trackerNameIndexMap); -// -// EXPECT_FALSE(conditionTracker.isSliced()); -// -// std::vector<int> uid_list1 = {111, 1111, 11111}; -// string uid1_wl1 = "wl1_1"; -// std::vector<int> uid_list2 = {222, 2222, 22222}; -// string uid2_wl1 = "wl2_1"; -// -// LogEvent event(1 /*tagId*/, 0 /*timestamp*/); -// makeWakeLockEvent(&event, uid_list1, uid1_wl1, 1); -// -// // one matched start for uid1 -// vector<MatchingState> matcherState; -// matcherState.push_back(MatchingState::kMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// vector<sp<ConditionTracker>> allPredicates; -// vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated); -// vector<bool> changedCache(1, false); -// -// conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache, -// changedCache); -// -// EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size()); -// EXPECT_TRUE(changedCache[0]); -// -// // Now test query -// ConditionKey queryKey; -// conditionCache[0] = ConditionState::kNotEvaluated; -// -// conditionTracker.isConditionMet(queryKey, allPredicates, -// true, -// conditionCache); -// EXPECT_EQ(ConditionState::kTrue, conditionCache[0]); -// -// // another wake lock acquired by this uid -// LogEvent event2(1 /*tagId*/, 0 /*timestamp*/); -// makeWakeLockEvent(&event2, uid_list2, uid2_wl1, 1); -// matcherState.clear(); -// matcherState.push_back(MatchingState::kMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// conditionCache[0] = ConditionState::kNotEvaluated; -// changedCache[0] = false; -// conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache, -// changedCache); -// EXPECT_FALSE(changedCache[0]); -// -// // uid1 wake lock 1 release -// LogEvent event3(1 /*tagId*/, 0 /*timestamp*/); -// makeWakeLockEvent(&event3, uid_list1, uid1_wl1, 0); // now release it. -// matcherState.clear(); -// matcherState.push_back(MatchingState::kNotMatched); -// matcherState.push_back(MatchingState::kMatched); -// conditionCache[0] = ConditionState::kNotEvaluated; -// changedCache[0] = false; -// conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache, -// changedCache); -// // nothing changes, because uid2 is still holding wl. -// EXPECT_FALSE(changedCache[0]); -// -// LogEvent event4(1 /*tagId*/, 0 /*timestamp*/); -// makeWakeLockEvent(&event4, uid_list2, uid2_wl1, 0); // now release it. -// matcherState.clear(); -// matcherState.push_back(MatchingState::kNotMatched); -// matcherState.push_back(MatchingState::kMatched); -// conditionCache[0] = ConditionState::kNotEvaluated; -// changedCache[0] = false; -// conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache, -// changedCache); -// EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size()); -// EXPECT_TRUE(changedCache[0]); -// -// // query again -// conditionCache[0] = ConditionState::kNotEvaluated; -// conditionTracker.isConditionMet(queryKey, allPredicates, -// true, -// conditionCache); -// EXPECT_EQ(ConditionState::kFalse, conditionCache[0]); -//} -// -//TEST(SimpleConditionTrackerTest, TestStopAll) { -// std::vector<sp<ConditionTracker>> allConditions; -// for (Position position : -// { Position::FIRST, Position::LAST }) { -// SimplePredicate simplePredicate = getWakeLockHeldCondition( -// true /*nesting*/, true /*default to false*/, true /*output slice by uid*/, -// position); -// string conditionName = "WL_HELD_BY_UID3"; -// -// unordered_map<int64_t, int> trackerNameIndexMap; -// trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0; -// trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; -// trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; -// -// SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), -// 0 /*condition tracker index*/, simplePredicate, -// trackerNameIndexMap); -// -// std::vector<int> uid_list1 = {111, 1111, 11111}; -// std::vector<int> uid_list2 = {222, 2222, 22222}; -// -// LogEvent event(1 /*tagId*/, 0 /*timestamp*/); -// makeWakeLockEvent(&event, uid_list1, "wl1", 1); -// -// // one matched start -// vector<MatchingState> matcherState; -// matcherState.push_back(MatchingState::kMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// vector<sp<ConditionTracker>> allPredicates; -// vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated); -// vector<bool> changedCache(1, false); -// -// conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache, -// changedCache); -// if (position == Position::FIRST || -// position == Position::LAST) { -// EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size()); -// } else { -// EXPECT_EQ(uid_list1.size(), conditionTracker.mSlicedConditionState.size()); -// } -// EXPECT_TRUE(changedCache[0]); -// { -// if (position == Position::FIRST || -// position == Position::LAST) { -// EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size()); -// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); -// } else { -// EXPECT_EQ(uid_list1.size(), conditionTracker.getChangedToTrueDimensions(allConditions)->size()); -// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); -// } -// } -// -// // Now test query -// const auto queryKey = getWakeLockQueryKey(position, uid_list1, conditionName); -// conditionCache[0] = ConditionState::kNotEvaluated; -// -// conditionTracker.isConditionMet(queryKey, allPredicates, -// false, -// conditionCache); -// EXPECT_EQ(ConditionState::kTrue, conditionCache[0]); -// -// // another wake lock acquired by uid2 -// LogEvent event2(1 /*tagId*/, 0 /*timestamp*/); -// makeWakeLockEvent(&event2, uid_list2, "wl2", 1); -// matcherState.clear(); -// matcherState.push_back(MatchingState::kMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// conditionCache[0] = ConditionState::kNotEvaluated; -// changedCache[0] = false; -// conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache, -// changedCache); -// if (position == Position::FIRST || -// position == Position::LAST) { -// EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size()); -// } else { -// EXPECT_EQ(uid_list1.size() + uid_list2.size(), -// conditionTracker.mSlicedConditionState.size()); -// } -// EXPECT_TRUE(changedCache[0]); -// { -// if (position == Position::FIRST || -// position == Position::LAST) { -// EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size()); -// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); -// } else { -// EXPECT_EQ(uid_list2.size(), conditionTracker.getChangedToTrueDimensions(allConditions)->size()); -// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); -// } -// } -// -// -// // TEST QUERY -// const auto queryKey2 = getWakeLockQueryKey(position, uid_list2, conditionName); -// conditionCache[0] = ConditionState::kNotEvaluated; -// conditionTracker.isConditionMet(queryKey, allPredicates, -// false, -// conditionCache); -// -// EXPECT_EQ(ConditionState::kTrue, conditionCache[0]); -// -// -// // stop all event -// LogEvent event3(2 /*tagId*/, 0 /*timestamp*/); -// matcherState.clear(); -// matcherState.push_back(MatchingState::kNotMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// matcherState.push_back(MatchingState::kMatched); -// -// conditionCache[0] = ConditionState::kNotEvaluated; -// changedCache[0] = false; -// conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache, -// changedCache); -// EXPECT_TRUE(changedCache[0]); -// EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size()); -// { -// if (position == Position::FIRST || position == Position::LAST) { -// EXPECT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size()); -// EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); -// } else { -// EXPECT_EQ(uid_list1.size() + uid_list2.size(), -// conditionTracker.getChangedToFalseDimensions(allConditions)->size()); -// EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); -// } -// } -// -// // TEST QUERY -// const auto queryKey3 = getWakeLockQueryKey(position, uid_list1, conditionName); -// conditionCache[0] = ConditionState::kNotEvaluated; -// 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, -// false, -// conditionCache); -// EXPECT_EQ(ConditionState::kFalse, conditionCache[0]); -// } -//} +TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) { + std::vector<sp<ConditionTracker>> allConditions; + + SimplePredicate simplePredicate = + getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/, + false /*slice output by uid*/, Position::ANY /* position */); + string conditionName = "WL_HELD"; + + unordered_map<int64_t, int> trackerNameIndexMap; + trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0; + trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; + trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; + + SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), + 0 /*condition tracker index*/, simplePredicate, + trackerNameIndexMap); + + EXPECT_FALSE(conditionTracker.isSliced()); + + std::vector<int> uids1 = {111, 1111, 11111}; + string uid1_wl1 = "wl1_1"; + std::vector<int> uids2 = {222, 2222, 22222}; + string uid2_wl1 = "wl2_1"; + + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1, /*acquire=*/1); + + // one matched start for uid1 + vector<MatchingState> matcherState; + matcherState.push_back(MatchingState::kMatched); + matcherState.push_back(MatchingState::kNotMatched); + matcherState.push_back(MatchingState::kNotMatched); + vector<sp<ConditionTracker>> allPredicates; + vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated); + vector<bool> changedCache(1, false); + + conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache, + changedCache); + + EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size()); + EXPECT_TRUE(changedCache[0]); + + // Now test query + ConditionKey queryKey; + conditionCache[0] = ConditionState::kNotEvaluated; + + conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache); + EXPECT_EQ(ConditionState::kTrue, conditionCache[0]); + + // another wake lock acquired by this uid + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1, /*acquire=*/1); + + matcherState.clear(); + matcherState.push_back(MatchingState::kMatched); + matcherState.push_back(MatchingState::kNotMatched); + conditionCache[0] = ConditionState::kNotEvaluated; + changedCache[0] = false; + conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache, + changedCache); + EXPECT_FALSE(changedCache[0]); + + // uid1 wake lock 1 release + LogEvent event3(/*uid=*/0, /*pid=*/0); + makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1, + /*release=*/0); // now release it. + + matcherState.clear(); + matcherState.push_back(MatchingState::kNotMatched); + matcherState.push_back(MatchingState::kMatched); + conditionCache[0] = ConditionState::kNotEvaluated; + changedCache[0] = false; + conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache, + changedCache); + // nothing changes, because uid2 is still holding wl. + EXPECT_FALSE(changedCache[0]); + + LogEvent event4(/*uid=*/0, /*pid=*/0); + makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1, + /*acquire=*/0); // now release it. + matcherState.clear(); + matcherState.push_back(MatchingState::kNotMatched); + matcherState.push_back(MatchingState::kMatched); + conditionCache[0] = ConditionState::kNotEvaluated; + changedCache[0] = false; + conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache, + changedCache); + EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size()); + EXPECT_TRUE(changedCache[0]); + + // query again + conditionCache[0] = ConditionState::kNotEvaluated; + conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache); + EXPECT_EQ(ConditionState::kFalse, conditionCache[0]); +} + +TEST(SimpleConditionTrackerTest, TestStopAll) { + std::vector<sp<ConditionTracker>> allConditions; + for (Position position : {Position::FIRST, Position::LAST}) { + SimplePredicate simplePredicate = + getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/, + true /*output slice by uid*/, position); + string conditionName = "WL_HELD_BY_UID3"; + + unordered_map<int64_t, int> trackerNameIndexMap; + trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0; + trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; + trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; + + SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), + 0 /*condition tracker index*/, simplePredicate, + trackerNameIndexMap); + + std::vector<int> uids1 = {111, 1111, 11111}; + std::vector<int> uids2 = {222, 2222, 22222}; + + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, "wl1", /*acquire=*/1); + + // one matched start + vector<MatchingState> matcherState; + matcherState.push_back(MatchingState::kMatched); + matcherState.push_back(MatchingState::kNotMatched); + matcherState.push_back(MatchingState::kNotMatched); + vector<sp<ConditionTracker>> allPredicates; + vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated); + vector<bool> changedCache(1, false); + + conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache, + changedCache); + if (position == Position::FIRST || position == Position::LAST) { + EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size()); + } else { + EXPECT_EQ(uids1.size(), conditionTracker.mSlicedConditionState.size()); + } + EXPECT_TRUE(changedCache[0]); + { + if (position == Position::FIRST || position == Position::LAST) { + EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size()); + EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); + } else { + EXPECT_EQ(uids1.size(), + conditionTracker.getChangedToTrueDimensions(allConditions)->size()); + EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); + } + } + + // Now test query + const auto queryKey = getWakeLockQueryKey(position, uids1, conditionName); + conditionCache[0] = ConditionState::kNotEvaluated; + + conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache); + EXPECT_EQ(ConditionState::kTrue, conditionCache[0]); + + // another wake lock acquired by uid2 + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1); + + matcherState.clear(); + matcherState.push_back(MatchingState::kMatched); + matcherState.push_back(MatchingState::kNotMatched); + matcherState.push_back(MatchingState::kNotMatched); + conditionCache[0] = ConditionState::kNotEvaluated; + changedCache[0] = false; + conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache, + changedCache); + if (position == Position::FIRST || position == Position::LAST) { + EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size()); + } else { + EXPECT_EQ(uids1.size() + uids2.size(), conditionTracker.mSlicedConditionState.size()); + } + EXPECT_TRUE(changedCache[0]); + { + if (position == Position::FIRST || position == Position::LAST) { + EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size()); + EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); + } else { + EXPECT_EQ(uids2.size(), + conditionTracker.getChangedToTrueDimensions(allConditions)->size()); + EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); + } + } + + // TEST QUERY + const auto queryKey2 = getWakeLockQueryKey(position, uids2, conditionName); + conditionCache[0] = ConditionState::kNotEvaluated; + conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache); + + EXPECT_EQ(ConditionState::kTrue, conditionCache[0]); + + // stop all event + LogEvent event3(/*uid=*/0, /*pid=*/0); + makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1); + + matcherState.clear(); + matcherState.push_back(MatchingState::kNotMatched); + matcherState.push_back(MatchingState::kNotMatched); + matcherState.push_back(MatchingState::kMatched); + + conditionCache[0] = ConditionState::kNotEvaluated; + changedCache[0] = false; + conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache, + changedCache); + EXPECT_TRUE(changedCache[0]); + EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size()); + { + if (position == Position::FIRST || position == Position::LAST) { + EXPECT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size()); + EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); + } else { + EXPECT_EQ(uids1.size() + uids2.size(), + conditionTracker.getChangedToFalseDimensions(allConditions)->size()); + EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); + } + } + + // TEST QUERY + const auto queryKey3 = getWakeLockQueryKey(position, uids1, conditionName); + conditionCache[0] = ConditionState::kNotEvaluated; + conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache); + EXPECT_EQ(ConditionState::kFalse, conditionCache[0]); + + // TEST QUERY + const auto queryKey4 = getWakeLockQueryKey(position, uids2, conditionName); + conditionCache[0] = ConditionState::kNotEvaluated; + conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache); + EXPECT_EQ(ConditionState::kFalse, conditionCache[0]); + } +} } // namespace statsd } // namespace os diff --git a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp index 1eaaf08ab2b9..e0eebefd1621 100644 --- a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp @@ -53,185 +53,192 @@ StatsdConfig CreateStatsdConfig(int num_buckets, int threshold) { } // namespace -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) { -// const int num_buckets = 1; -// const int threshold = 3; -// auto config = CreateStatsdConfig(num_buckets, threshold); -// const uint64_t alert_id = config.alert(0).id(); -// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); -// -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); -// -// sp<AnomalyTracker> anomalyTracker = -// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; -// -// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")}; -// std::vector<AttributionNodeInternal> attributions2 = { -// CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")}; -// std::vector<AttributionNodeInternal> attributions3 = { -// CreateAttribution(111, "App1"), CreateAttribution(333, "App3")}; -// std::vector<AttributionNodeInternal> attributions4 = { -// CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")}; -// std::vector<AttributionNodeInternal> attributions5 = { -// CreateAttribution(222, "GMSCoreModule1") }; -// -// FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), -// Value((int32_t)111)); -// HashableDimensionKey whatKey1({fieldValue1}); -// MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY); -// -// FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), -// Value((int32_t)222)); -// HashableDimensionKey whatKey2({fieldValue2}); -// MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY); -// -// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + 2); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); -// -// event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 3); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); -// -// event = CreateAcquireWakelockEvent(attributions3, "wl1", bucketStartTimeNs + 4); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 4); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); -// -// // Fired alarm and refractory period end timestamp updated. -// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 5); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 100); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + bucketSizeNs + 1); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); -// -// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 2); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); -// -// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 3); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); -// -// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 4); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); -//} -// -//TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) { -// const int num_buckets = 3; -// const int threshold = 3; -// auto config = CreateStatsdConfig(num_buckets, threshold); -// const uint64_t alert_id = config.alert(0).id(); -// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); -// -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); -// -// sp<AnomalyTracker> anomalyTracker = -// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; -// -// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")}; -// std::vector<AttributionNodeInternal> attributions2 = { -// CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")}; -// std::vector<AttributionNodeInternal> attributions3 = { -// CreateAttribution(111, "App1"), CreateAttribution(333, "App3")}; -// std::vector<AttributionNodeInternal> attributions4 = { -// CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")}; -// std::vector<AttributionNodeInternal> attributions5 = { -// CreateAttribution(222, "GMSCoreModule1") }; -// -// FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), -// Value((int32_t)111)); -// HashableDimensionKey whatKey1({fieldValue1}); -// MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY); -// -// FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), -// Value((int32_t)222)); -// HashableDimensionKey whatKey2({fieldValue2}); -// MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY); -// -// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// // Fired alarm and refractory period end timestamp updated. -// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 4); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 2); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 1); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -// -// event = CreateAcquireWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 2); -// processor->OnLogEvent(event.get()); -// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); -//} +TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) { + const int num_buckets = 1; + const int threshold = 3; + auto config = CreateStatsdConfig(num_buckets, threshold); + const uint64_t alert_id = config.alert(0).id(); + const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); + + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + + sp<AnomalyTracker> anomalyTracker = + processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; + + std::vector<int> attributionUids1 = {111}; + std::vector<string> attributionTags1 = {"App1"}; + std::vector<int> attributionUids2 = {111, 222}; + std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"}; + std::vector<int> attributionUids3 = {111, 333}; + std::vector<string> attributionTags3 = {"App1", "App3"}; + std::vector<int> attributionUids4 = {222, 333}; + std::vector<string> attributionTags4 = {"GMSCoreModule1", "App3"}; + std::vector<int> attributionUids5 = {222}; + std::vector<string> attributionTags5 = {"GMSCoreModule1"}; + + FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), + Value((int32_t)111)); + HashableDimensionKey whatKey1({fieldValue1}); + MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY); + + FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), + Value((int32_t)222)); + HashableDimensionKey whatKey2({fieldValue2}); + MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY); + + auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids4, attributionTags4, + "wl2"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2, + "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids5, attributionTags5, + "wl2"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids3, attributionTags3, + "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids5, attributionTags5, + "wl2"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); + + // Fired alarm and refractory period end timestamp updated. + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 5, attributionUids1, attributionTags1, + "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 100, attributionUids1, attributionTags1, + "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids4, + attributionTags4, "wl2"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids5, + attributionTags5, "wl2"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 3, attributionUids5, + attributionTags5, "wl2"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 4, attributionUids5, + attributionTags5, "wl2"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); +} + +TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) { + const int num_buckets = 3; + const int threshold = 3; + auto config = CreateStatsdConfig(num_buckets, threshold); + const uint64_t alert_id = config.alert(0).id(); + const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); + + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + + sp<AnomalyTracker> anomalyTracker = + processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; + + std::vector<int> attributionUids1 = {111}; + std::vector<string> attributionTags1 = {"App1"}; + std::vector<int> attributionUids2 = {111, 222}; + std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"}; + + FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), + Value((int32_t)111)); + HashableDimensionKey whatKey1({fieldValue1}); + MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY); + + auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2, + "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Fired alarm and refractory period end timestamp updated. + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids1, attributionTags1, + "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 2, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(event.get()); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); +} #else GTEST_LOG_(INFO) << "This test does nothing.\n"; diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp index 03a209a0e41f..fe45b5507c25 100644 --- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp @@ -69,414 +69,432 @@ StatsdConfig CreateStatsdConfig(int num_buckets, return config; } -} // namespace - -std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"), - CreateAttribution(222, "GMSCoreModule1")}; +std::vector<int> attributionUids1 = {111, 222}; +std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1"}; -std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"), - CreateAttribution(222, "GMSCoreModule1")}; +std::vector<int> attributionUids2 = {111, 222}; +std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1"}; -std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1")}; +std::vector<int> attributionUids3 = {222}; +std::vector<string> attributionTags3 = {"GMSCoreModule1"}; -MetricDimensionKey dimensionKey( - HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED, - (int32_t)0x02010101), Value((int32_t)111))}), - DEFAULT_DIMENSION_KEY); +MetricDimensionKey dimensionKey1( + HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED, + (int32_t)0x02010101), + Value((int32_t)111))}), + DEFAULT_DIMENSION_KEY); MetricDimensionKey dimensionKey2( HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), Value((int32_t)222))}), DEFAULT_DIMENSION_KEY); -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { -// const int num_buckets = 1; -// const uint64_t threshold_ns = NS_PER_SEC; -// auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true); -// const uint64_t alert_id = config.alert(0).id(); -// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); -// -// int64_t bucketStartTimeNs = 10 * NS_PER_SEC; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); -// -// sp<AnomalyTracker> anomalyTracker = -// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; -// -// auto screen_on_event = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1); -// auto screen_off_event = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 10); -// processor->OnLogEvent(screen_on_event.get()); -// processor->OnLogEvent(screen_off_event.get()); -// -// // Acquire wakelock wl1. -// auto acquire_event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 11); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event. -// auto release_event = CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 101); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Acquire wakelock wl1 within bucket #0. -// acquire_event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 110); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Release wakelock wl1. One anomaly detected. -// release_event = CreateReleaseWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + NS_PER_SEC + 109); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Acquire wakelock wl1. -// acquire_event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + NS_PER_SEC + 112); -// processor->OnLogEvent(acquire_event.get()); -// // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the -// // end of the refractory period. -// const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey); -// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1, -// (uint32_t)alarmFiredTimestampSec0); -// -// // Anomaly alarm fired. -// auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( -// static_cast<uint32_t>(alarmFiredTimestampSec0)); -// EXPECT_EQ(1u, alarmSet.size()); -// processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Release wakelock wl1. -// release_event = CreateReleaseWakelockEvent( -// attributions1, "wl1", alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// // Within refractory period. No more anomaly detected. -// EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Acquire wakelock wl1. -// acquire_event = CreateAcquireWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11); -// processor->OnLogEvent(acquire_event.get()); -// const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey); -// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC, -// (uint64_t)alarmFiredTimestampSec1); -// -// // Release wakelock wl1. -// release_event = CreateReleaseWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(refractory_period_sec + -// (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( -// static_cast<uint32_t>(alarmFiredTimestampSec1)); -// EXPECT_EQ(0u, alarmSet.size()); -// -// // Acquire wakelock wl1 near the end of bucket #0. -// acquire_event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 2); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// -// // Release the event at early bucket #1. -// release_event = CreateReleaseWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// // Anomaly detected when stopping the alarm. The refractory period does not change. -// EXPECT_EQ(refractory_period_sec + -// (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Condition changes to false. -// screen_on_event = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 2 * bucketSizeNs + 20); -// processor->OnLogEvent(screen_on_event.get()); -// EXPECT_EQ(refractory_period_sec + -// (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// -// acquire_event = CreateAcquireWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 30); -// processor->OnLogEvent(acquire_event.get()); -// // The condition is false. Do not start the alarm. -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(refractory_period_sec + -// (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Condition turns true. -// screen_off_event = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC); -// processor->OnLogEvent(screen_off_event.get()); -// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// -// // Condition turns to false. -// screen_on_event = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1); -// processor->OnLogEvent(screen_on_event.get()); -// // Condition turns to false. Cancelled the alarm. -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// // Detected one anomaly. -// EXPECT_EQ(refractory_period_sec + -// (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Condition turns to true again. -// screen_off_event = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2); -// processor->OnLogEvent(screen_off_event.get()); -// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// -// release_event = CreateReleaseWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(refractory_period_sec + -// (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -//} -// -//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) { -// const int num_buckets = 3; -// const uint64_t threshold_ns = NS_PER_SEC; -// auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true); -// const uint64_t alert_id = config.alert(0).id(); -// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); -// -// int64_t bucketStartTimeNs = 10 * NS_PER_SEC; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); -// -// sp<AnomalyTracker> anomalyTracker = -// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; -// -// auto screen_off_event = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1); -// processor->OnLogEvent(screen_off_event.get()); -// -// // Acquire wakelock "wc1" in bucket #0. -// auto acquire_event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Release wakelock "wc1" in bucket #0. -// auto release_event = CreateReleaseWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Acquire wakelock "wc1" in bucket #1. -// acquire_event = CreateAcquireWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 1); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// release_event = CreateReleaseWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 100); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Acquire wakelock "wc2" in bucket #2. -// acquire_event = CreateAcquireWakelockEvent( -// attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2, -// anomalyTracker->getAlarmTimestampSec(dimensionKey2)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); -// -// // Release wakelock "wc2" in bucket #2. -// release_event = CreateReleaseWakelockEvent( -// attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); -// EXPECT_EQ(refractory_period_sec + -// (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); -// -// // Acquire wakelock "wc1" in bucket #2. -// acquire_event = CreateAcquireWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Release wakelock "wc1" in bucket #2. -// release_event = CreateReleaseWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(refractory_period_sec + -// (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// acquire_event = CreateAcquireWakelockEvent( -// attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4); -// processor->OnLogEvent(acquire_event.get()); -// acquire_event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, -// anomalyTracker->getAlarmTimestampSec(dimensionKey2)); -// -// release_event = CreateReleaseWakelockEvent( -// attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs + 2); -// processor->OnLogEvent(release_event.get()); -// release_event = CreateReleaseWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs + 6); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); -// // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered. -// EXPECT_EQ(refractory_period_sec + -// (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -//} -// -//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) { -// const int num_buckets = 2; -// const uint64_t threshold_ns = 3 * NS_PER_SEC; -// auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false); -// int64_t bucketStartTimeNs = 10 * NS_PER_SEC; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; -// -// const uint64_t alert_id = config.alert(0).id(); -// const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC; -// config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec); -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); -// -// sp<AnomalyTracker> anomalyTracker = -// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; -// -// auto screen_off_event = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1); -// processor->OnLogEvent(screen_off_event.get()); -// -// // Acquire wakelock "wc1" in bucket #0. -// auto acquire_event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 100); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Acquire the wakelock "wc1" again. -// acquire_event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1); -// processor->OnLogEvent(acquire_event.get()); -// // The alarm does not change. -// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // Anomaly alarm fired late. -// const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC; -// auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( -// static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC)); -// EXPECT_EQ(1u, alarmSet.size()); -// processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// acquire_event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs - 100); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// auto release_event = CreateReleaseWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 1); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// // Within the refractory period. No anomaly. -// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// // A new wakelock, but still within refractory period. -// acquire_event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// -// release_event = CreateReleaseWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC); -// // Still in the refractory period. No anomaly. -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, -// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey)); -// -// acquire_event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// -// release_event = CreateReleaseWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4); -// processor->OnLogEvent(release_event.get()); -// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey)); -// -// acquire_event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3); -// processor->OnLogEvent(acquire_event.get()); -// EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC, -// anomalyTracker->getAlarmTimestampSec(dimensionKey)); -//} +} // namespace + +TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { + const int num_buckets = 1; + const uint64_t threshold_ns = NS_PER_SEC; + auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true); + const uint64_t alert_id = config.alert(0).id(); + const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); + + int64_t bucketStartTimeNs = 10 * NS_PER_SEC; + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + + sp<AnomalyTracker> anomalyTracker = + processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; + + auto screen_on_event = CreateScreenStateChangedEvent( + bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON); + auto screen_off_event = CreateScreenStateChangedEvent( + bucketStartTimeNs + 10, android::view::DisplayStateEnum::DISPLAY_STATE_OFF); + processor->OnLogEvent(screen_on_event.get()); + processor->OnLogEvent(screen_off_event.get()); + + // Acquire wakelock wl1. + auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 11, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event. + auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 101, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Acquire wakelock wl1 within bucket #0. + acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 110, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Release wakelock wl1. One anomaly detected. + release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 109, + attributionUids2, attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Acquire wakelock wl1. + acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 112, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the + // end of the refractory period. + const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1, + (uint32_t)alarmFiredTimestampSec0); + + // Anomaly alarm fired. + auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( + static_cast<uint32_t>(alarmFiredTimestampSec0)); + EXPECT_EQ(1u, alarmSet.size()); + processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Release wakelock wl1. + release_event = + CreateReleaseWakelockEvent(alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + // Within refractory period. No more anomaly detected. + EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Acquire wakelock wl1. + acquire_event = + CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, + attributionUids2, attributionTags2, "wl1"); + processor->OnLogEvent(acquire_event.get()); + const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1); + EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC, + (uint64_t)alarmFiredTimestampSec1); + + // Release wakelock wl1. + release_event = + CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10, + attributionUids2, attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(refractory_period_sec + + (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( + static_cast<uint32_t>(alarmFiredTimestampSec1)); + EXPECT_EQ(0u, alarmSet.size()); + + // Acquire wakelock wl1 near the end of bucket #0. + acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + + // Release the event at early bucket #1. + release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + // Anomaly detected when stopping the alarm. The refractory period does not change. + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Condition changes to false. + screen_on_event = + CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 20, + android::view::DisplayStateEnum::DISPLAY_STATE_ON); + processor->OnLogEvent(screen_on_event.get()); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + + acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 30, + attributionUids2, attributionTags2, "wl1"); + processor->OnLogEvent(acquire_event.get()); + // The condition is false. Do not start the alarm. + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Condition turns true. + screen_off_event = + CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_OFF); + processor->OnLogEvent(screen_off_event.get()); + EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + + // Condition turns to false. + screen_on_event = + CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1, + android::view::DisplayStateEnum::DISPLAY_STATE_ON); + processor->OnLogEvent(screen_on_event.get()); + // Condition turns to false. Cancelled the alarm. + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + // Detected one anomaly. + EXPECT_EQ(refractory_period_sec + + (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Condition turns to true again. + screen_off_event = + CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2, + android::view::DisplayStateEnum::DISPLAY_STATE_OFF); + processor->OnLogEvent(screen_off_event.get()); + EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + + release_event = + CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC, + attributionUids2, attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(refractory_period_sec + + (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); +} + +TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) { + const int num_buckets = 3; + const uint64_t threshold_ns = NS_PER_SEC; + auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true); + const uint64_t alert_id = config.alert(0).id(); + const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); + + int64_t bucketStartTimeNs = 10 * NS_PER_SEC; + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + + sp<AnomalyTracker> anomalyTracker = + processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; + + auto screen_off_event = CreateScreenStateChangedEvent( + bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF); + processor->OnLogEvent(screen_off_event.get()); + + // Acquire wakelock "wc1" in bucket #0. + auto acquire_event = + CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Release wakelock "wc1" in bucket #0. + auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Acquire wakelock "wc1" in bucket #1. + acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, + attributionUids2, attributionTags2, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100, + attributionUids2, attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Acquire wakelock "wc2" in bucket #2. + acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1, + attributionUids3, attributionTags3, "wl2"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2, + anomalyTracker->getAlarmTimestampSec(dimensionKey2)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); + + // Release wakelock "wc2" in bucket #2. + release_event = + CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC, + attributionUids3, attributionTags3, "wl2"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); + EXPECT_EQ(refractory_period_sec + + (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); + + // Acquire wakelock "wc1" in bucket #2. + acquire_event = + CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC, + attributionUids2, attributionTags2, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Release wakelock "wc1" in bucket #2. + release_event = + CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC, + attributionUids2, attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(refractory_period_sec + + (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) / + NS_PER_SEC + + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + acquire_event = + CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4, + attributionUids3, attributionTags3, "wl2"); + processor->OnLogEvent(acquire_event.get()); + acquire_event = + CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, + anomalyTracker->getAlarmTimestampSec(dimensionKey2)); + + release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2, + attributionUids3, attributionTags3, "wl2"); + processor->OnLogEvent(release_event.get()); + release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); + // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered. + EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + + 1, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); +} + +TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) { + const int num_buckets = 2; + const uint64_t threshold_ns = 3 * NS_PER_SEC; + auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false); + int64_t bucketStartTimeNs = 10 * NS_PER_SEC; + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; + + const uint64_t alert_id = config.alert(0).id(); + const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC; + config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec); + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + + sp<AnomalyTracker> anomalyTracker = + processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; + + auto screen_off_event = CreateScreenStateChangedEvent( + bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF); + processor->OnLogEvent(screen_off_event.get()); + + // Acquire wakelock "wc1" in bucket #0. + auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Acquire the wakelock "wc1" again. + acquire_event = + CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + // The alarm does not change. + EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // Anomaly alarm fired late. + const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC; + auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( + static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC)); + EXPECT_EQ(1u, alarmSet.size()); + processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + // Within the refractory period. No anomaly. + EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + // A new wakelock, but still within refractory period. + acquire_event = + CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + + release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC, + attributionUids1, attributionTags1, "wl1"); + // Still in the refractory period. No anomaly. + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, + anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); + + acquire_event = + CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + + release_event = + CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get()); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); + + acquire_event = + CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3, + attributionUids1, attributionTags1, "wl1"); + processor->OnLogEvent(acquire_event.get()); + EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC, + anomalyTracker->getAlarmTimestampSec(dimensionKey1)); +} #else GTEST_LOG_(INFO) << "This test does nothing.\n"; diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp index 605117474014..9e743f7a3157 100644 --- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp @@ -53,367 +53,318 @@ StatsdConfig CreateStatsdConfig(const Position position) { return config; } +// GMS core node is in the middle. +std::vector<int> attributionUids1 = {111, 222, 333}; +std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1", "App3"}; + +// GMS core node is the last one. +std::vector<int> attributionUids2 = {111, 333, 222}; +std::vector<string> attributionTags2 = {"App1", "App3", "GMSCoreModule1"}; + +// GMS core node is the first one. +std::vector<int> attributionUids3 = {222, 333}; +std::vector<string> attributionTags3 = {"GMSCoreModule1", "App3"}; + +// Single GMS core node. +std::vector<int> attributionUids4 = {222}; +std::vector<string> attributionTags4 = {"GMSCoreModule1"}; + +// GMS core has another uid. +std::vector<int> attributionUids5 = {111, 444, 333}; +std::vector<string> attributionTags5 = {"App1", "GMSCoreModule2", "App3"}; + +// Multiple GMS core nodes. +std::vector<int> attributionUids6 = {444, 222}; +std::vector<string> attributionTags6 = {"GMSCoreModule2", "GMSCoreModule1"}; + +// No GMS core nodes +std::vector<int> attributionUids7 = {111, 333}; +std::vector<string> attributionTags7 = {"App1", "App3"}; + +std::vector<int> attributionUids8 = {111}; +std::vector<string> attributionTags8 = {"App1"}; + +// GMS core node with isolated uid. +const int isolatedUid = 666; +std::vector<int> attributionUids9 = {isolatedUid}; +std::vector<string> attributionTags9 = {"GMSCoreModule3"}; + +std::vector<int> attributionUids10 = {isolatedUid}; +std::vector<string> attributionTags10 = {"GMSCoreModule1"}; + } // namespace -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) { -// auto config = CreateStatsdConfig(Position::FIRST); -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// -// // Here it assumes that GMS core has two uids. -// processor->getUidMap()->updateMap( -// 1, {222, 444, 111, 333}, {1, 1, 2, 2}, -// {String16("v1"), String16("v1"), String16("v2"), String16("v2")}, -// {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"), -// String16("APP3")}, -// {String16(""), String16(""), String16(""), String16("")}); -// -// // GMS core node is in the middle. -// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"), -// CreateAttribution(222, "GMSCoreModule1"), -// CreateAttribution(333, "App3")}; -// -// // GMS core node is the last one. -// std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"), -// CreateAttribution(333, "App3"), -// CreateAttribution(222, "GMSCoreModule1")}; -// -// // GMS core node is the first one. -// std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"), -// CreateAttribution(333, "App3")}; -// -// // Single GMS core node. -// std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")}; -// -// // GMS core has another uid. -// std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"), -// CreateAttribution(444, "GMSCoreModule2"), -// CreateAttribution(333, "App3")}; -// -// // Multiple GMS core nodes. -// std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"), -// CreateAttribution(222, "GMSCoreModule1")}; -// -// // No GMS core nodes. -// std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"), -// CreateAttribution(333, "App3")}; -// std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")}; -// -// // GMS core node with isolated uid. -// const int isolatedUid = 666; -// std::vector<AttributionNodeInternal> attributions9 = { -// CreateAttribution(isolatedUid, "GMSCoreModule3")}; -// -// std::vector<std::unique_ptr<LogEvent>> events; -// // Events 1~4 are in the 1st bucket. -// events.push_back(CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 2)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + 200)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions4, "wl1", bucketStartTimeNs + bucketSizeNs)); -// -// // Events 5~8 are in the 3rd bucket. -// events.push_back(CreateAcquireWakelockEvent( -// attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100)); -// events.push_back(CreateIsolatedUidChangedEvent( -// isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1)); -// events.push_back(CreateIsolatedUidChangedEvent( -// isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10)); -// -// sortLogEventsByTimestamp(&events); -// -// for (const auto& event : events) { -// processor->OnLogEvent(event.get()); -// } -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * 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(), 4); -// -// auto data = countMetrics.data(0); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 111, -// "App1"); -// 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 + 2 * bucketSizeNs); -// EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs); -// -// data = countMetrics.data(1); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222, -// "GMSCoreModule1"); -// 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(2); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222, -// "GMSCoreModule3"); -// 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 + 3 * bucketSizeNs); -// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs); -// -// data = countMetrics.data(3); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 444, -// "GMSCoreModule2"); -// 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 + 2 * bucketSizeNs); -// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs); -//} -// -//TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) { -// auto config = CreateStatsdConfig(Position::ALL); -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// -// // Here it assumes that GMS core has two uids. -// processor->getUidMap()->updateMap( -// 1, {222, 444, 111, 333}, {1, 1, 2, 2}, -// {String16("v1"), String16("v1"), String16("v2"), String16("v2")}, -// {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"), -// String16("APP3")}, -// {String16(""), String16(""), String16(""), String16("")}); -// -// // GMS core node is in the middle. -// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"), -// CreateAttribution(222, "GMSCoreModule1"), -// CreateAttribution(333, "App3")}; -// -// // GMS core node is the last one. -// std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"), -// CreateAttribution(333, "App3"), -// CreateAttribution(222, "GMSCoreModule1")}; -// -// // GMS core node is the first one. -// std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"), -// CreateAttribution(333, "App3")}; -// -// // Single GMS core node. -// std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")}; -// -// // GMS core has another uid. -// std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"), -// CreateAttribution(444, "GMSCoreModule2"), -// CreateAttribution(333, "App3")}; -// -// // Multiple GMS core nodes. -// std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"), -// CreateAttribution(222, "GMSCoreModule1")}; -// -// // No GMS core nodes. -// std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"), -// CreateAttribution(333, "App3")}; -// std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")}; -// -// // GMS core node with isolated uid. -// const int isolatedUid = 666; -// std::vector<AttributionNodeInternal> attributions9 = { -// CreateAttribution(isolatedUid, "GMSCoreModule1")}; -// -// std::vector<std::unique_ptr<LogEvent>> events; -// // Events 1~4 are in the 1st bucket. -// events.push_back(CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 2)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions2, "wl1", bucketStartTimeNs + 200)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions4, "wl1", bucketStartTimeNs + bucketSizeNs)); -// -// // Events 5~8 are in the 3rd bucket. -// events.push_back(CreateAcquireWakelockEvent( -// attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1)); -// events.push_back(CreateAcquireWakelockEvent( -// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100)); -// events.push_back(CreateIsolatedUidChangedEvent( -// isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1)); -// events.push_back(CreateIsolatedUidChangedEvent( -// isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10)); -// -// sortLogEventsByTimestamp(&events); -// -// for (const auto& event : events) { -// processor->OnLogEvent(event.get()); -// } -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * 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(), 6); -// -// auto data = countMetrics.data(0); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); -// EXPECT_EQ(2, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, data.bucket_info(1).count()); -// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, -// data.bucket_info(1).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, -// data.bucket_info(1).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(1); -// ValidateUidDimension( -// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); -// ValidateUidDimension( -// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); -// 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(2); -// ValidateUidDimension( -// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2"); -// ValidateUidDimension( -// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); -// EXPECT_EQ(data.bucket_info_size(), 1); -// EXPECT_EQ(data.bucket_info(0).count(), 1); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(3); -// ValidateUidDimension( -// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); -// ValidateUidDimension( -// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); -// ValidateUidDimension( -// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); -// EXPECT_EQ(data.bucket_info_size(), 1); -// EXPECT_EQ(data.bucket_info(0).count(), 1); -// EXPECT_EQ(bucketStartTimeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(4); -// ValidateUidDimension( -// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); -// ValidateUidDimension( -// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); -// ValidateUidDimension( -// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1"); -// EXPECT_EQ(data.bucket_info_size(), 1); -// EXPECT_EQ(data.bucket_info(0).count(), 1); -// EXPECT_EQ(bucketStartTimeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(5); -// ValidateUidDimension( -// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); -// ValidateUidDimension( -// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2"); -// ValidateUidDimension( -// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333); -// ValidateAttributionUidAndTagDimension( -// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); -// EXPECT_EQ(data.bucket_info_size(), 1); -// EXPECT_EQ(data.bucket_info(0).count(), 1); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -//} +TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) { + auto config = CreateStatsdConfig(Position::FIRST); + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + + // Here it assumes that GMS core has two uids. + processor->getUidMap()->updateMap( + 1, {222, 444, 111, 333}, {1, 1, 2, 2}, + {String16("v1"), String16("v1"), String16("v2"), String16("v2")}, + {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"), + String16("APP3")}, + {String16(""), String16(""), String16(""), String16("")}); + + std::vector<std::unique_ptr<LogEvent>> events; + // Events 1~4 are in the 1st bucket. + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1, + attributionTags1, "wl1")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 200, attributionUids2, + attributionTags2, "wl1")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, + attributionUids3, attributionTags3, "wl1")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs, attributionUids4, + attributionTags4, "wl1")); + + // Events 5~8 are in the 3rd bucket. + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1, + attributionUids5, attributionTags5, "wl2")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, + attributionUids6, attributionTags6, "wl2")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - 2, + attributionUids7, attributionTags7, "wl2")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs, + attributionUids8, attributionTags8, "wl2")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1, + attributionUids9, attributionTags9, "wl2")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 100, + attributionUids9, attributionTags9, "wl2")); + events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs - 1, 222, + isolatedUid, true /*is_create*/)); + events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs + 10, 222, + isolatedUid, false /*is_create*/)); + + sortLogEventsByTimestamp(&events); + + for (const auto& event : events) { + processor->OnLogEvent(event.get()); + } + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * 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(), 4); + + auto data = countMetrics.data(0); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); + 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 + 2 * bucketSizeNs); + EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs); + + data = countMetrics.data(1); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, 222, + "GMSCoreModule1"); + 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(2); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, 222, + "GMSCoreModule3"); + 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 + 3 * bucketSizeNs); + EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs); + + data = countMetrics.data(3); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, 444, + "GMSCoreModule2"); + 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 + 2 * bucketSizeNs); + EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs); +} + +TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) { + auto config = CreateStatsdConfig(Position::ALL); + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + + // Here it assumes that GMS core has two uids. + processor->getUidMap()->updateMap( + 1, {222, 444, 111, 333}, {1, 1, 2, 2}, + {String16("v1"), String16("v1"), String16("v2"), String16("v2")}, + {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"), + String16("APP3")}, + {String16(""), String16(""), String16(""), String16("")}); + + std::vector<std::unique_ptr<LogEvent>> events; + // Events 1~4 are in the 1st bucket. + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1, + attributionTags1, "wl1")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 200, attributionUids2, + attributionTags2, "wl1")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, + attributionUids3, attributionTags3, "wl1")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs, attributionUids4, + attributionTags4, "wl1")); + + // Events 5~8 are in the 3rd bucket. + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1, + attributionUids5, attributionTags5, "wl2")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, + attributionUids6, attributionTags6, "wl2")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - 2, + attributionUids7, attributionTags7, "wl2")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs, + attributionUids8, attributionTags8, "wl2")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1, + attributionUids10, attributionTags10, "wl2")); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 100, + attributionUids10, attributionTags10, "wl2")); + events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs - 1, 222, + isolatedUid, true /*is_create*/)); + events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs + 10, 222, + isolatedUid, false /*is_create*/)); + + sortLogEventsByTimestamp(&events); + + for (const auto& event : events) { + processor->OnLogEvent(event.get()); + } + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * 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(), 6); + + auto data = countMetrics.data(0); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, 222, + "GMSCoreModule1"); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(1, data.bucket_info(1).count()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, + data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); + + data = countMetrics.data(1); + ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0, + android::util::WAKELOCK_STATE_CHANGED, 222, + "GMSCoreModule1"); + ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1, + android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); + 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(2); + ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0, + android::util::WAKELOCK_STATE_CHANGED, 444, + "GMSCoreModule2"); + ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1, + android::util::WAKELOCK_STATE_CHANGED, 222, + "GMSCoreModule1"); + EXPECT_EQ(data.bucket_info_size(), 1); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(3); + ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0, + android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); + ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1, + android::util::WAKELOCK_STATE_CHANGED, 222, + "GMSCoreModule1"); + ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2, + android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); + EXPECT_EQ(data.bucket_info_size(), 1); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(4); + ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0, + android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); + ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1, + android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); + ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2, + android::util::WAKELOCK_STATE_CHANGED, 222, + "GMSCoreModule1"); + EXPECT_EQ(data.bucket_info_size(), 1); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(5); + ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0, + android::util::WAKELOCK_STATE_CHANGED, 111, "App1"); + ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1, + android::util::WAKELOCK_STATE_CHANGED, 444, + "GMSCoreModule2"); + ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333); + ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2, + android::util::WAKELOCK_STATE_CHANGED, 333, "App3"); + EXPECT_EQ(data.bucket_info_size(), 1); + EXPECT_EQ(data.bucket_info(0).count(), 1); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); +} #else GTEST_LOG_(INFO) << "This test does nothing.\n"; diff --git a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp index f8edee50a3fd..102bb1ea243d 100644 --- a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp @@ -56,54 +56,54 @@ StatsdConfig CreateStatsdConfig(int num_buckets, int threshold) { } // namespace -// TODO(b/149590301): Update this test to use new socket schema. -//TEST(ConfigTtlE2eTest, TestCountMetric) { -// const int num_buckets = 1; -// const int threshold = 3; -// auto config = CreateStatsdConfig(num_buckets, threshold); -// const uint64_t alert_id = config.alert(0).id(); -// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); -// -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// 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")}; -// -// FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), -// Value((int32_t)111)); -// HashableDimensionKey whatKey1({fieldValue1}); -// MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY); -// -// FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), -// Value((int32_t)222)); -// HashableDimensionKey whatKey2({fieldValue2}); -// MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY); -// -// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2); -// processor->OnLogEvent(event.get()); -// -// event = CreateAcquireWakelockEvent(attributions1, "wl2", bucketStartTimeNs + bucketSizeNs + 2); -// processor->OnLogEvent(event.get()); -// -// event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 25 * bucketSizeNs + 2); -// processor->OnLogEvent(event.get()); -// -// EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC), -// processor->mMetricsManagers.begin()->second->getTtlEndNs()); -// -// // Clear the data stored on disk as a result of the ttl. -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true, -// ADB_DUMP, FAST, &buffer); -//} - +TEST(ConfigTtlE2eTest, TestCountMetric) { + const int num_buckets = 1; + const int threshold = 3; + auto config = CreateStatsdConfig(num_buckets, threshold); + const uint64_t alert_id = config.alert(0).id(); + const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); + + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + + std::vector<int> attributionUids1 = {111}; + std::vector<string> attributionTags1 = {"App1"}; + + FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), + Value((int32_t)111)); + HashableDimensionKey whatKey1({fieldValue1}); + MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY); + + FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101), + Value((int32_t)222)); + HashableDimensionKey whatKey2({fieldValue2}); + MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY); + + auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(event.get()); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids1, + attributionTags1, "wl2"); + processor->OnLogEvent(event.get()); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + 25 * bucketSizeNs + 2, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(event.get()); + + EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC), + processor->mMetricsManagers.begin()->second->getTtlEndNs()); + + // Clear the data stored on disk as a result of the ttl. + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true, + ADB_DUMP, FAST, &buffer); +} #else GTEST_LOG_(INFO) << "This test does nothing.\n"; diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp index a1f74a631f56..2cd7854420a9 100644 --- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp @@ -27,773 +27,775 @@ namespace statsd { #ifdef __ANDROID__ -// TODO(b/149590301): Update these tests to use new socket schema. -///** -// * Test a count metric that has one slice_by_state with no primary fields. -// * -// * Once the CountMetricProducer is initialized, it has one atom id in -// * mSlicedStateAtoms and no entries in mStateGroupMap. -// -// * One StateTracker tracks the state atom, and it has one listener which is the -// * CountMetricProducer that was initialized. -// */ -//TEST(CountMetricE2eTest, TestSlicedState) { -// // Initialize config. -// StatsdConfig config; -// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. -// -// auto syncStartMatcher = CreateSyncStartAtomMatcher(); -// *config.add_atom_matcher() = syncStartMatcher; -// -// auto state = CreateScreenState(); -// *config.add_state() = state; -// -// // Create count metric that slices by screen state. -// int64_t metricId = 123456; -// auto countMetric = config.add_count_metric(); -// countMetric->set_id(metricId); -// countMetric->set_what(syncStartMatcher.id()); -// countMetric->set_bucket(TimeUnit::FIVE_MINUTES); -// countMetric->add_slice_by_state(state.id()); -// -// // Initialize StatsLogProcessor. -// const uint64_t bucketStartTimeNs = 10000000000; // 0:10 -// const uint64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// -// // Check that CountMetricProducer was initialized correctly. -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1); -// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID); -// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0); -// -// // Check that StateTrackers were initialized correctly. -// EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); -// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); -// -// /* -// bucket #1 bucket #2 -// | 1 2 3 4 5 6 7 8 9 10 (minutes) -// |-----------------------------|-----------------------------|-- -// x x x x x x (syncStartEvents) -// | | (ScreenIsOnEvent) -// | | (ScreenIsOffEvent) -// | (ScreenUnknownEvent) -// */ -// // Initialize log events - first bucket. -// int appUid = 123; -// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")}; -// std::vector<std::unique_ptr<LogEvent>> events; -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 50 * NS_PER_SEC)); // 1:00 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 75 * NS_PER_SEC)); // 1:25 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20 -// -// // Initialize log events - second bucket. -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 350 * NS_PER_SEC)); // 6:00 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 400 * NS_PER_SEC)); // 6:50 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 450 * NS_PER_SEC)); // 7:40 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 475 * NS_PER_SEC)); // 8:05 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, -// bucketStartTimeNs + 500 * NS_PER_SEC)); // 8:30 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 520 * NS_PER_SEC)); // 8:50 -// -// // Send log events to StatsLogProcessor. -// for (auto& event : events) { -// processor->OnLogEvent(event.get()); -// } -// -// // Check dump report. -// vector<uint8_t> buffer; -// ConfigMetricsReportList reports; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, -// FAST, &buffer); -// EXPECT_GT(buffer.size(), 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStringInReport(&reports); -// backfillStartEndTimestamp(&reports); -// -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); -// EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); -// -// // For each CountMetricData, check StateValue info is correct and buckets -// // have correct counts. -// auto data = reports.reports(0).metrics(0).count_metrics().data(0); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_value()); -// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value()); -// EXPECT_EQ(2, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(1, data.bucket_info(1).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(1); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_value()); -// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, data.slice_by_state(0).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(2); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_value()); -// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value()); -// EXPECT_EQ(2, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(2, data.bucket_info(1).count()); -//} -// -///** -// * Test a count metric that has one slice_by_state with a mapping and no -// * primary fields. -// * -// * Once the CountMetricProducer is initialized, it has one atom id in -// * mSlicedStateAtoms and has one entry per state value in mStateGroupMap. -// * -// * One StateTracker tracks the state atom, and it has one listener which is the -// * CountMetricProducer that was initialized. -// */ -//TEST(CountMetricE2eTest, TestSlicedStateWithMap) { -// // Initialize config. -// StatsdConfig config; -// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. -// -// auto syncStartMatcher = CreateSyncStartAtomMatcher(); -// *config.add_atom_matcher() = syncStartMatcher; -// -// auto state = CreateScreenStateWithOnOffMap(); -// *config.add_state() = state; -// -// // Create count metric that slices by screen state with on/off map. -// int64_t metricId = 123456; -// auto countMetric = config.add_count_metric(); -// countMetric->set_id(metricId); -// countMetric->set_what(syncStartMatcher.id()); -// countMetric->set_bucket(TimeUnit::FIVE_MINUTES); -// countMetric->add_slice_by_state(state.id()); -// -// // Initialize StatsLogProcessor. -// const uint64_t bucketStartTimeNs = 10000000000; // 0:10 -// const uint64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// -// // Check that StateTrackers were initialized correctly. -// EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); -// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); -// -// // Check that CountMetricProducer was initialized correctly. -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1); -// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID); -// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1); -// -// StateMap map = state.map(); -// for (auto group : map.group()) { -// for (auto value : group.value()) { -// EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value], -// group.group_id()); -// } -// } -// -// /* -// bucket #1 bucket #2 -// | 1 2 3 4 5 6 7 8 9 10 (minutes) -// |-----------------------------|-----------------------------|-- -// x x x x x x x x x (syncStartEvents) -// -----------------------------------------------------------SCREEN_OFF events -// | (ScreenStateUnknownEvent = 0) -// | | (ScreenStateOffEvent = 1) -// | (ScreenStateDozeEvent = 3) -// | (ScreenStateDozeSuspendEvent = 4) -// -----------------------------------------------------------SCREEN_ON events -// | | (ScreenStateOnEvent = 2) -// | (ScreenStateVrEvent = 5) -// | (ScreenStateOnSuspendEvent = 6) -// */ -// // Initialize log events - first bucket. -// int appUid = 123; -// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")}; -// -// std::vector<std::unique_ptr<LogEvent>> events; -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, -// bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_VR, -// bucketStartTimeNs + 180 * NS_PER_SEC)); // 3:10 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE, -// bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55 -// -// // Initialize log events - second bucket. -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND, -// bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40 -// events.push_back(CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND, -// bucketStartTimeNs + 430 * NS_PER_SEC)); // 7:20 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10 -// events.push_back(CreateSyncStartEvent(attributions1, "sync_name", -// bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40 -// -// // Send log events to StatsLogProcessor. -// for (auto& event : events) { -// processor->OnLogEvent(event.get()); -// } -// -// // Check dump report. -// vector<uint8_t> buffer; -// ConfigMetricsReportList reports; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, -// FAST, &buffer); -// EXPECT_GT(buffer.size(), 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStringInReport(&reports); -// backfillStartEndTimestamp(&reports); -// -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); -// EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); -// -// // For each CountMetricData, check StateValue info is correct and buckets -// // have correct counts. -// auto data = reports.reports(0).metrics(0).count_metrics().data(0); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_value()); -// EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(1); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_group_id()); -// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); -// EXPECT_EQ(2, data.bucket_info_size()); -// EXPECT_EQ(4, data.bucket_info(0).count()); -// EXPECT_EQ(2, data.bucket_info(1).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(2); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_group_id()); -// EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); -// EXPECT_EQ(2, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(1, data.bucket_info(1).count()); -//} -// -///** -// * Test a count metric that has one slice_by_state with a primary field. -// -// * Once the CountMetricProducer is initialized, it should have one -// * MetricStateLink stored. State querying using a non-empty primary key -// * should also work as intended. -// */ -//TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) { -// // Initialize config. -// StatsdConfig config; -// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. -// -// auto appCrashMatcher = -// CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED); -// *config.add_atom_matcher() = appCrashMatcher; -// -// auto state = CreateUidProcessState(); -// *config.add_state() = state; -// -// // Create count metric that slices by uid process state. -// int64_t metricId = 123456; -// auto countMetric = config.add_count_metric(); -// countMetric->set_id(metricId); -// countMetric->set_what(appCrashMatcher.id()); -// countMetric->set_bucket(TimeUnit::FIVE_MINUTES); -// countMetric->add_slice_by_state(state.id()); -// MetricStateLink* stateLink = countMetric->add_state_link(); -// stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID); -// auto fieldsInWhat = stateLink->mutable_fields_in_what(); -// *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */}); -// auto fieldsInState = stateLink->mutable_fields_in_state(); -// *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */}); -// -// // Initialize StatsLogProcessor. -// const uint64_t bucketStartTimeNs = 10000000000; // 0:10 -// const uint64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// -// // Check that StateTrackers were initialized correctly. -// EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); -// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID)); -// -// // Check that CountMetricProducer was initialized correctly. -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1); -// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID); -// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0); -// EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1); -// -// /* -// NOTE: "1" or "2" represents the uid associated with the state/app crash event -// bucket #1 bucket #2 -// | 1 2 3 4 5 6 7 8 9 10 -// |-----------------------------|-----------------------------|-- -// 1 1 1 1 1 2 1 1 2 (AppCrashEvents) -// -----------------------------------------------------------PROCESS STATE events -// 1 2 (ProcessStateTopEvent = 1002) -// 1 1 (ProcessStateForegroundServiceEvent = 1003) -// 2 (ProcessStateImportantBackgroundEvent = 1006) -// 1 1 1 (ProcessStateImportantForegroundEvent = 1005) -// -// Based on the diagram above, an AppCrashEvent querying for process state value would return: -// - StateTracker::kStateUnknown -// - Important foreground -// - Top -// - Important foreground -// - Foreground service -// - Top (both the app crash and state still have matching uid = 2) -// -// - Foreground service -// - Foreground service -// - Important background -// */ -// // Initialize log events - first bucket. -// std::vector<std::unique_ptr<LogEvent>> events; -// events.push_back( -// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30 -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, -// bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40 -// events.push_back( -// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10 -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP, -// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40 -// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, -// bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10 -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, -// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40 -// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, -// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30 -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, -// bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40 -// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, -// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20 -// events.push_back(CreateUidProcessStateChangedEvent( -// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP, -// bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50 -// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */, -// bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55 -// -// // Initialize log events - second bucket. -// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, -// bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10 -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, -// bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40 -// events.push_back(CreateUidProcessStateChangedEvent( -// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, -// bucketStartTimeNs + 430 * NS_PER_SEC)); // 7:20 -// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, -// bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30 -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, -// bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10 -// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */, -// bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40 -// -// // Send log events to StatsLogProcessor. -// for (auto& event : events) { -// processor->OnLogEvent(event.get()); -// } -// -// // Check dump report. -// vector<uint8_t> buffer; -// ConfigMetricsReportList reports; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, -// FAST, &buffer); -// EXPECT_GT(buffer.size(), 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStringInReport(&reports); -// backfillStartEndTimestamp(&reports); -// -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); -// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); -// -// // For each CountMetricData, check StateValue info is correct and buckets -// // have correct counts. -// auto data = reports.reports(0).metrics(0).count_metrics().data(0); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_value()); -// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(1); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_value()); -// EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(2); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_value()); -// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(2, data.bucket_info(0).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(3); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_value()); -// EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(2, data.bucket_info(0).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(4); -// EXPECT_EQ(1, data.slice_by_state_size()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_value()); -// EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value()); -// EXPECT_EQ(2, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(2, data.bucket_info(1).count()); -//} -// -//TEST(CountMetricE2eTest, TestMultipleSlicedStates) { -// // Initialize config. -// StatsdConfig config; -// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. -// -// auto appCrashMatcher = -// CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED); -// *config.add_atom_matcher() = appCrashMatcher; -// -// auto state1 = CreateScreenStateWithOnOffMap(); -// *config.add_state() = state1; -// auto state2 = CreateUidProcessState(); -// *config.add_state() = state2; -// -// // Create count metric that slices by screen state with on/off map and -// // slices by uid process state. -// int64_t metricId = 123456; -// auto countMetric = config.add_count_metric(); -// countMetric->set_id(metricId); -// countMetric->set_what(appCrashMatcher.id()); -// countMetric->set_bucket(TimeUnit::FIVE_MINUTES); -// countMetric->add_slice_by_state(state1.id()); -// countMetric->add_slice_by_state(state2.id()); -// MetricStateLink* stateLink = countMetric->add_state_link(); -// stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID); -// auto fieldsInWhat = stateLink->mutable_fields_in_what(); -// *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */}); -// auto fieldsInState = stateLink->mutable_fields_in_state(); -// *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */}); -// -// // Initialize StatsLogProcessor. -// const uint64_t bucketStartTimeNs = 10000000000; // 0:10 -// const uint64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// -// // Check that StateTrackers were properly initialized. -// EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount()); -// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); -// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID)); -// -// // Check that CountMetricProducer was initialized correctly. -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2); -// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID); -// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID); -// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1); -// EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1); -// -// StateMap map = state1.map(); -// for (auto group : map.group()) { -// for (auto value : group.value()) { -// EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value], -// group.group_id()); -// } -// } -// -// /* -// bucket #1 bucket #2 -// | 1 2 3 4 5 6 7 8 9 10 (minutes) -// |-----------------------------|-----------------------------|-- -// 1 1 1 1 1 2 1 1 2 (AppCrashEvents) -// -----------------------------------------------------------SCREEN_OFF events -// | (ScreenStateUnknownEvent = 0) -// | | (ScreenStateOffEvent = 1) -// | (ScreenStateDozeEvent = 3) -// -----------------------------------------------------------SCREEN_ON events -// | | (ScreenStateOnEvent = 2) -// | (ScreenStateOnSuspendEvent = 6) -// -----------------------------------------------------------PROCESS STATE events -// 1 2 (ProcessStateTopEvent = 1002) -// 1 (ProcessStateForegroundServiceEvent = 1003) -// 2 (ProcessStateImportantBackgroundEvent = 1006) -// 1 1 1 (ProcessStateImportantForegroundEvent = 1005) -// -// Based on the diagram above, Screen State / Process State pairs for each -// AppCrashEvent are: -// - StateTracker::kStateUnknown / important foreground -// - off / important foreground -// - off / Top -// - on / important foreground -// - off / important foreground -// - off / top -// -// - off / important foreground -// - off / foreground service -// - on / important background -// -// */ -// // Initialize log events - first bucket. -// std::vector<std::unique_ptr<LogEvent>> events; -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, -// bucketStartTimeNs + 5 * NS_PER_SEC)); // 0:15 -// events.push_back( -// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, -// bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40 -// events.push_back( -// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10 -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP, -// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40 -// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, -// bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10 -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, -// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 160 * NS_PER_SEC)); // 2:50 -// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, -// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE, -// bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40 -// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, -// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20 -// events.push_back(CreateUidProcessStateChangedEvent( -// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP, -// bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50 -// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */, -// bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55 -// -// // Initialize log events - second bucket. -// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, -// bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10 -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, -// bucketStartTimeNs + 380 * NS_PER_SEC)); // 6:30 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND, -// bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40 -// events.push_back(CreateUidProcessStateChangedEvent( -// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, -// bucketStartTimeNs + 420 * NS_PER_SEC)); // 7:10 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30 -// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */, -// bucketStartTimeNs + 450 * NS_PER_SEC)); // 7:40 -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 520 * NS_PER_SEC)); // 8:50 -// events.push_back(CreateUidProcessStateChangedEvent( -// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, -// bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10 -// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */, -// bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40 -// -// // Send log events to StatsLogProcessor. -// for (auto& event : events) { -// processor->OnLogEvent(event.get()); -// } -// -// // Check dump report. -// vector<uint8_t> buffer; -// ConfigMetricsReportList reports; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, -// FAST, &buffer); -// EXPECT_GT(buffer.size(), 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStringInReport(&reports); -// backfillStartEndTimestamp(&reports); -// -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); -// EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size()); -// -// // For each CountMetricData, check StateValue info is correct and buckets -// // have correct counts. -// auto data = reports.reports(0).metrics(0).count_metrics().data(0); -// EXPECT_EQ(2, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_group_id()); -// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); -// EXPECT_TRUE(data.slice_by_state(1).has_value()); -// EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(1); -// EXPECT_EQ(2, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_value()); -// EXPECT_EQ(-1, data.slice_by_state(0).value()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); -// EXPECT_TRUE(data.slice_by_state(1).has_value()); -// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(2); -// EXPECT_EQ(2, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_group_id()); -// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); -// EXPECT_TRUE(data.slice_by_state(1).has_value()); -// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); -// EXPECT_EQ(2, data.bucket_info_size()); -// EXPECT_EQ(2, data.bucket_info(0).count()); -// EXPECT_EQ(1, data.bucket_info(1).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(3); -// EXPECT_EQ(2, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_group_id()); -// EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); -// EXPECT_TRUE(data.slice_by_state(1).has_value()); -// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(4); -// EXPECT_EQ(2, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_group_id()); -// EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); -// EXPECT_TRUE(data.slice_by_state(1).has_value()); -// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// -// data = reports.reports(0).metrics(0).count_metrics().data(5); -// EXPECT_EQ(2, data.slice_by_state_size()); -// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); -// EXPECT_TRUE(data.slice_by_state(0).has_group_id()); -// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); -// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); -// EXPECT_TRUE(data.slice_by_state(1).has_value()); -// EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(2, data.bucket_info(0).count()); -//} +/** +* Test a count metric that has one slice_by_state with no primary fields. +* +* Once the CountMetricProducer is initialized, it has one atom id in +* mSlicedStateAtoms and no entries in mStateGroupMap. + +* One StateTracker tracks the state atom, and it has one listener which is the +* CountMetricProducer that was initialized. +*/ +TEST(CountMetricE2eTest, TestSlicedState) { + // Initialize config. + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + + auto syncStartMatcher = CreateSyncStartAtomMatcher(); + *config.add_atom_matcher() = syncStartMatcher; + + auto state = CreateScreenState(); + *config.add_state() = state; + + // Create count metric that slices by screen state. + int64_t metricId = 123456; + auto countMetric = config.add_count_metric(); + countMetric->set_id(metricId); + countMetric->set_what(syncStartMatcher.id()); + countMetric->set_bucket(TimeUnit::FIVE_MINUTES); + countMetric->add_slice_by_state(state.id()); + + // Initialize StatsLogProcessor. + const uint64_t bucketStartTimeNs = 10000000000; // 0:10 + const uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + + // Check that CountMetricProducer was initialized correctly. + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1); + EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID); + EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0); + + // Check that StateTrackers were initialized correctly. + EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); + + /* + bucket #1 bucket #2 + | 1 2 3 4 5 6 7 8 9 10 (minutes) + |-----------------------------|-----------------------------|-- + x x x x x x (syncStartEvents) + | | (ScreenIsOnEvent) + | | (ScreenIsOffEvent) + | (ScreenUnknownEvent) + */ + // Initialize log events - first bucket. + std::vector<int> attributionUids1 = {123}; + std::vector<string> attributionTags1 = {"App1"}; + + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 50 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 1:00 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 75 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 1:25 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 150 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 2:40 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 200 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 3:30 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 4:20 + + // Initialize log events - second bucket. + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 350 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 6:00 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 6:50 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 450 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 7:40 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 475 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 8:05 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 500 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN)); // 8:30 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 520 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 8:50 + + // Send log events to StatsLogProcessor. + for (auto& event : events) { + processor->OnLogEvent(event.get()); + } + + // Check dump report. + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); + EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); + + // For each CountMetricData, check StateValue info is correct and buckets + // have correct counts. + auto data = reports.reports(0).metrics(0).count_metrics().data(0); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(1); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, + data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(2); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); +} + +/** + * Test a count metric that has one slice_by_state with a mapping and no + * primary fields. + * + * Once the CountMetricProducer is initialized, it has one atom id in + * mSlicedStateAtoms and has one entry per state value in mStateGroupMap. + * + * One StateTracker tracks the state atom, and it has one listener which is the + * CountMetricProducer that was initialized. + */ +TEST(CountMetricE2eTest, TestSlicedStateWithMap) { + // Initialize config. + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + + auto syncStartMatcher = CreateSyncStartAtomMatcher(); + *config.add_atom_matcher() = syncStartMatcher; + + auto state = CreateScreenStateWithOnOffMap(); + *config.add_state() = state; + + // Create count metric that slices by screen state with on/off map. + int64_t metricId = 123456; + auto countMetric = config.add_count_metric(); + countMetric->set_id(metricId); + countMetric->set_what(syncStartMatcher.id()); + countMetric->set_bucket(TimeUnit::FIVE_MINUTES); + countMetric->add_slice_by_state(state.id()); + + // Initialize StatsLogProcessor. + const uint64_t bucketStartTimeNs = 10000000000; // 0:10 + const uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + + // Check that StateTrackers were initialized correctly. + EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); + + // Check that CountMetricProducer was initialized correctly. + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1); + EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID); + EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1); + + StateMap map = state.map(); + for (auto group : map.group()) { + for (auto value : group.value()) { + EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value], + group.group_id()); + } + } + + /* + bucket #1 bucket #2 + | 1 2 3 4 5 6 7 8 9 10 (minutes) + |-----------------------------|-----------------------------|-- + x x x x x x x x x (syncStartEvents) + -----------------------------------------------------------SCREEN_OFF events + | (ScreenStateUnknownEvent = 0) + | | (ScreenStateOffEvent = 1) + | (ScreenStateDozeEvent = 3) + | (ScreenStateDozeSuspendEvent = + 4) + -----------------------------------------------------------SCREEN_ON events + | | (ScreenStateOnEvent = 2) + | (ScreenStateVrEvent = 5) + | (ScreenStateOnSuspendEvent = 6) + */ + // Initialize log events - first bucket. + std::vector<int> attributionUids1 = {123}; + std::vector<string> attributionTags1 = {"App1"}; + + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 20 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 0:30 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 30 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN)); // 0:40 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 1:10 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 90 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:40 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 120 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 2:10 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 150 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:40 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 180 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_VR)); // 3:10 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 3:30 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 210 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 3:40 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 4:20 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 280 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 4:50 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 285 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 4:55 + + // Initialize log events - second bucket. + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 360 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 6:10 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 390 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND)); // 6:40 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 430 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND)); // 7:20 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 440 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 7:30 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 540 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 9:10 + events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 570 * NS_PER_SEC, attributionUids1, + attributionTags1, "sync_name")); // 9:40 + + // Send log events to StatsLogProcessor. + for (auto& event : events) { + processor->OnLogEvent(event.get()); + } + + // Check dump report. + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); + EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); + + // For each CountMetricData, check StateValue info is correct and buckets + // have correct counts. + auto data = reports.reports(0).metrics(0).count_metrics().data(0); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(1); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(4, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(2); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); +} + +/** +* Test a count metric that has one slice_by_state with a primary field. + +* Once the CountMetricProducer is initialized, it should have one +* MetricStateLink stored. State querying using a non-empty primary key +* should also work as intended. +*/ +TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) { + // Initialize config. + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + + auto appCrashMatcher = + CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED); + *config.add_atom_matcher() = appCrashMatcher; + + auto state = CreateUidProcessState(); + *config.add_state() = state; + + // Create count metric that slices by uid process state. + int64_t metricId = 123456; + auto countMetric = config.add_count_metric(); + countMetric->set_id(metricId); + countMetric->set_what(appCrashMatcher.id()); + countMetric->set_bucket(TimeUnit::FIVE_MINUTES); + countMetric->add_slice_by_state(state.id()); + MetricStateLink* stateLink = countMetric->add_state_link(); + stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID); + auto fieldsInWhat = stateLink->mutable_fields_in_what(); + *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /*uid*/}); + auto fieldsInState = stateLink->mutable_fields_in_state(); + *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/}); + + // Initialize StatsLogProcessor. + const uint64_t bucketStartTimeNs = 10000000000; // 0:10 + const uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + + // Check that StateTrackers were initialized correctly. + EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID)); + + // Check that CountMetricProducer was initialized correctly. + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1); + EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID); + EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0); + EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1); + + /* + NOTE: "1" or "2" represents the uid associated with the state/app crash event + bucket #1 bucket #2 + | 1 2 3 4 5 6 7 8 9 10 + |------------------------|-------------------------|-- + 1 1 1 1 1 2 1 1 2 (AppCrashEvents) + -----------------------------------------------------PROCESS STATE events + 1 2 (TopEvent = 1002) + 1 1 (ForegroundServiceEvent = 1003) + 2 (ImportantBackgroundEvent = 1006) + 1 1 1 (ImportantForegroundEvent = 1005) + + Based on the diagram above, an AppCrashEvent querying for process state value would return: + - StateTracker::kStateUnknown + - Important foreground + - Top + - Important foreground + - Foreground service + - Top (both the app crash and state still have matching uid = 2) + + - Foreground service + - Foreground service + - Important background + */ + // Initialize log events - first bucket. + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/)); // 0:30 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:40 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/)); // 1:10 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 1:40 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/)); // 2:10 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 2:40 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/)); // 3:30 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 210 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 3:40 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/)); // 4:20 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 4:50 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/)); // 4:55 + + // Initialize log events - second bucket. + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/)); // 6:10 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 390 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 6:40 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 430 * NS_PER_SEC, 2 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND)); // 7:20 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 440 * NS_PER_SEC, 1 /*uid*/)); // 7:30 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 9:10 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/)); // 9:40 + + // Send log events to StatsLogProcessor. + for (auto& event : events) { + processor->OnLogEvent(event.get()); + } + + // Check dump report. + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); + EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); + + // For each CountMetricData, check StateValue info is correct and buckets + // have correct counts. + auto data = reports.reports(0).metrics(0).count_metrics().data(0); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(1); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(2); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(3); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(4); + EXPECT_EQ(1, data.slice_by_state_size()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); +} + +TEST(CountMetricE2eTest, TestMultipleSlicedStates) { + // Initialize config. + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + + auto appCrashMatcher = + CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED); + *config.add_atom_matcher() = appCrashMatcher; + + auto state1 = CreateScreenStateWithOnOffMap(); + *config.add_state() = state1; + auto state2 = CreateUidProcessState(); + *config.add_state() = state2; + + // Create count metric that slices by screen state with on/off map and + // slices by uid process state. + int64_t metricId = 123456; + auto countMetric = config.add_count_metric(); + countMetric->set_id(metricId); + countMetric->set_what(appCrashMatcher.id()); + countMetric->set_bucket(TimeUnit::FIVE_MINUTES); + countMetric->add_slice_by_state(state1.id()); + countMetric->add_slice_by_state(state2.id()); + MetricStateLink* stateLink = countMetric->add_state_link(); + stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID); + auto fieldsInWhat = stateLink->mutable_fields_in_what(); + *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /*uid*/}); + auto fieldsInState = stateLink->mutable_fields_in_state(); + *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/}); + + // Initialize StatsLogProcessor. + const uint64_t bucketStartTimeNs = 10000000000; // 0:10 + const uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + + // Check that StateTrackers were properly initialized. + EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount()); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID)); + + // Check that CountMetricProducer was initialized correctly. + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2); + EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID); + EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID); + EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1); + EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1); + + StateMap map = state1.map(); + for (auto group : map.group()) { + for (auto value : group.value()) { + EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value], + group.group_id()); + } + } + + /* + bucket #1 bucket #2 + | 1 2 3 4 5 6 7 8 9 10 (minutes) + |------------------------|------------------------|-- + 1 1 1 1 1 2 1 1 2 (AppCrashEvents) + ---------------------------------------------------SCREEN_OFF events + | (ScreenUnknownEvent = 0) + | | (ScreenOffEvent = 1) + | (ScreenDozeEvent = 3) + ---------------------------------------------------SCREEN_ON events + | | (ScreenOnEvent = 2) + | (ScreenOnSuspendEvent = 6) + ---------------------------------------------------PROCESS STATE events + 1 2 (TopEvent = 1002) + 1 (ForegroundServiceEvent = 1003) + 2 (ImportantBackgroundEvent = 1006) + 1 1 1 (ImportantForegroundEvent = 1005) + + Based on the diagram above, Screen State / Process State pairs for each + AppCrashEvent are: + - StateTracker::kStateUnknown / important foreground + - off / important foreground + - off / Top + - on / important foreground + - off / important foreground + - off / top + + - off / important foreground + - off / foreground service + - on / important background + + */ + // Initialize log events - first bucket. + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 5 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:15 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/)); // 0:30 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 30 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN)); // 0:40 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/)); // 1:10 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 1:40 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 90 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:40 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/)); // 2:10 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 2:40 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 160 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:50 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/)); // 3:30 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 210 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 3:40 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/)); // 4:20 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 4:50 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/)); // 4:55 + + // Initialize log events - second bucket. + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/)); // 6:10 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 380 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 6:30 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 390 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND)); // 6:40 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 420 * NS_PER_SEC, 2 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND)); // 7:10 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 440 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 7:30 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 450 * NS_PER_SEC, 1 /*uid*/)); // 7:40 + events.push_back(CreateScreenStateChangedEvent( + bucketStartTimeNs + 520 * NS_PER_SEC, + android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 8:50 + events.push_back(CreateUidProcessStateChangedEvent( + bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/, + android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 9:10 + events.push_back( + CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/)); // 9:40 + + // Send log events to StatsLogProcessor. + for (auto& event : events) { + processor->OnLogEvent(event.get()); + } + + // Check dump report. + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); + EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size()); + + // For each CountMetricData, check StateValue info is correct and buckets + // have correct counts. + auto data = reports.reports(0).metrics(0).count_metrics().data(0); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(1); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(-1, data.slice_by_state(0).value()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(2); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); + EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(3); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(4); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + + data = reports.reports(0).metrics(0).count_metrics().data(5); + EXPECT_EQ(2, data.slice_by_state_size()); + EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); + EXPECT_TRUE(data.slice_by_state(1).has_value()); + EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); +} } // namespace statsd } // namespace os diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp index 8eb5f69dcf40..b586b06e0175 100644 --- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp @@ -26,688 +26,688 @@ namespace statsd { #ifdef __ANDROID__ -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST(DurationMetricE2eTest, TestOneBucket) { -// StatsdConfig config; -// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. -// -// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); -// auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); -// *config.add_atom_matcher() = screenOnMatcher; -// *config.add_atom_matcher() = screenOffMatcher; -// -// auto durationPredicate = CreateScreenIsOnPredicate(); -// *config.add_predicate() = durationPredicate; -// -// int64_t metricId = 123456; -// auto durationMetric = config.add_duration_metric(); -// durationMetric->set_id(metricId); -// durationMetric->set_what(durationPredicate.id()); -// durationMetric->set_bucket(FIVE_MINUTES); -// durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM); -// -// -// const int64_t baseTimeNs = 0; // 0:00 -// const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01 -// const int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL; -// -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// -// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey); -// -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// -// std::unique_ptr<LogEvent> event; -// -// // Screen is off at start of bucket. -// event = CreateScreenStateChangedEvent( -// android::view::DISPLAY_STATE_OFF, configAddedTimeNs); // 0:01 -// processor->OnLogEvent(event.get()); -// -// // Turn screen on. -// const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11 -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs); -// processor->OnLogEvent(event.get()); -// -// // Turn off screen 30 seconds after turning on. -// const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41 -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs); -// processor->OnLogEvent(event.get()); -// -// event = CreateScreenBrightnessChangedEvent(64, durationEndNs + 1 * NS_PER_SEC); // 0:42 -// processor->OnLogEvent(event.get()); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true, -// ADB_DUMP, FAST, &buffer); // 5:01 -// EXPECT_TRUE(buffer.size() > 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStartEndTimestamp(&reports); -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); -// EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); -// -// const StatsLogReport::DurationMetricDataWrapper& durationMetrics = -// reports.reports(0).metrics(0).duration_metrics(); -// EXPECT_EQ(1, durationMetrics.data_size()); -// -// auto data = durationMetrics.data(0); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos()); -// EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -//} -// -//TEST(DurationMetricE2eTest, TestTwoBuckets) { -// StatsdConfig config; -// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. -// -// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); -// auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); -// *config.add_atom_matcher() = screenOnMatcher; -// *config.add_atom_matcher() = screenOffMatcher; -// -// auto durationPredicate = CreateScreenIsOnPredicate(); -// *config.add_predicate() = durationPredicate; -// -// int64_t metricId = 123456; -// auto durationMetric = config.add_duration_metric(); -// durationMetric->set_id(metricId); -// durationMetric->set_what(durationPredicate.id()); -// durationMetric->set_bucket(FIVE_MINUTES); -// durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM); -// -// -// const int64_t baseTimeNs = 0; // 0:00 -// const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01 -// const int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL; -// -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// -// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey); -// -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// -// std::unique_ptr<LogEvent> event; -// -// // Screen is off at start of bucket. -// event = CreateScreenStateChangedEvent( -// android::view::DISPLAY_STATE_OFF, configAddedTimeNs); // 0:01 -// processor->OnLogEvent(event.get()); -// -// // Turn screen on. -// const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11 -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs); -// processor->OnLogEvent(event.get()); -// -// // Turn off screen 30 seconds after turning on. -// const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41 -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs); -// processor->OnLogEvent(event.get()); -// -// event = CreateScreenBrightnessChangedEvent(64, durationEndNs + 1 * NS_PER_SEC); // 0:42 -// processor->OnLogEvent(event.get()); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, false, true, -// ADB_DUMP, FAST, &buffer); // 10:01 -// EXPECT_TRUE(buffer.size() > 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStartEndTimestamp(&reports); -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); -// EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); -// -// const StatsLogReport::DurationMetricDataWrapper& durationMetrics = -// reports.reports(0).metrics(0).duration_metrics(); -// EXPECT_EQ(1, durationMetrics.data_size()); -// -// auto data = durationMetrics.data(0); -// EXPECT_EQ(1, data.bucket_info_size()); -// -// auto bucketInfo = data.bucket_info(0); -// EXPECT_EQ(0, bucketInfo.bucket_num()); -// EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos()); -// EXPECT_EQ(configAddedTimeNs, bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); -//} -// -//TEST(DurationMetricE2eTest, TestWithActivation) { -// StatsdConfig config; -// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. -// -// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); -// auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); -// auto crashMatcher = CreateProcessCrashAtomMatcher(); -// *config.add_atom_matcher() = screenOnMatcher; -// *config.add_atom_matcher() = screenOffMatcher; -// *config.add_atom_matcher() = crashMatcher; -// -// auto durationPredicate = CreateScreenIsOnPredicate(); -// *config.add_predicate() = durationPredicate; -// -// int64_t metricId = 123456; -// auto durationMetric = config.add_duration_metric(); -// durationMetric->set_id(metricId); -// durationMetric->set_what(durationPredicate.id()); -// durationMetric->set_bucket(FIVE_MINUTES); -// durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM); -// -// auto metric_activation1 = config.add_metric_activation(); -// metric_activation1->set_metric_id(metricId); -// auto event_activation1 = metric_activation1->add_event_activation(); -// event_activation1->set_atom_matcher_id(crashMatcher.id()); -// event_activation1->set_ttl_seconds(30); // 30 secs. -// -// const int64_t bucketStartTimeNs = 10000000000; -// const int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL; -// -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// -// sp<UidMap> m = new UidMap(); -// sp<StatsPullerManager> pullerManager = new StatsPullerManager(); -// sp<AlarmMonitor> anomalyAlarmMonitor; -// sp<AlarmMonitor> subscriberAlarmMonitor; -// vector<int64_t> activeConfigsBroadcast; -// -// int broadcastCount = 0; -// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, -// bucketStartTimeNs, [](const ConfigKey& key) { return true; }, -// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, -// const vector<int64_t>& activeConfigs) { -// broadcastCount++; -// EXPECT_EQ(broadcastUid, uid); -// activeConfigsBroadcast.clear(); -// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), -// activeConfigs.begin(), activeConfigs.end()); -// return true; -// }); -// -// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); // 0:00 -// -// EXPECT_EQ(processor.mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// auto& eventActivationMap = metricProducer->mEventActivationMap; -// -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap.size(), 1u); -// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); -// -// std::unique_ptr<LogEvent> event; -// -// // Turn screen off. -// event = CreateScreenStateChangedEvent( -// android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 2 * NS_PER_SEC); // 0:02 -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC); -// -// // Turn screen on. -// const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:05 -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs); -// processor.OnLogEvent(event.get(), durationStartNs); -// -// // Activate metric. -// const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:10 -// const int64_t activationEndNs = -// activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 0:40 -// event = CreateAppCrashEvent(111, activationStartNs); -// processor.OnLogEvent(event.get(), activationStartNs); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 1); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); -// -// // Expire activation. -// const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC; -// event = CreateScreenBrightnessChangedEvent(64, expirationNs); // 0:47 -// processor.OnLogEvent(event.get(), expirationNs); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 2); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap.size(), 1u); -// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); -// -// // Turn off screen 10 seconds after activation expiration. -// const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC; // 0:50 -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs); -// processor.OnLogEvent(event.get(),durationEndNs); -// -// // Turn screen on. -// const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC; // 0:55 -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, duration2StartNs); -// processor.OnLogEvent(event.get(), duration2StartNs); -// -// // Turn off screen. -// const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC; // 1:05 -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, duration2EndNs); -// processor.OnLogEvent(event.get(), duration2EndNs); -// -// // Activate metric. -// const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC; // 1:10 -// const int64_t activation2EndNs = -// activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 1:40 -// event = CreateAppCrashEvent(211, activation2StartNs); -// processor.OnLogEvent(event.get(), activation2StartNs); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 3); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor.onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true, -// ADB_DUMP, FAST, &buffer); // 5:01 -// EXPECT_TRUE(buffer.size() > 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStartEndTimestamp(&reports); -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); -// EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); -// -// const StatsLogReport::DurationMetricDataWrapper& durationMetrics = -// reports.reports(0).metrics(0).duration_metrics(); -// EXPECT_EQ(1, durationMetrics.data_size()); -// -// auto data = durationMetrics.data(0); -// EXPECT_EQ(1, data.bucket_info_size()); -// -// auto bucketInfo = data.bucket_info(0); -// EXPECT_EQ(0, bucketInfo.bucket_num()); -// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(expirationNs, bucketInfo.end_bucket_elapsed_nanos()); -// EXPECT_EQ(expirationNs - durationStartNs, bucketInfo.duration_nanos()); -//} -// -//TEST(DurationMetricE2eTest, TestWithCondition) { -// StatsdConfig config; -// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. -// *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher(); -// *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher(); -// *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); -// *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); -// -// auto holdingWakelockPredicate = CreateHoldingWakelockPredicate(); -// *config.add_predicate() = holdingWakelockPredicate; -// -// auto isInBackgroundPredicate = CreateIsInBackgroundPredicate(); -// *config.add_predicate() = isInBackgroundPredicate; -// -// auto durationMetric = config.add_duration_metric(); -// durationMetric->set_id(StringToId("WakelockDuration")); -// durationMetric->set_what(holdingWakelockPredicate.id()); -// durationMetric->set_condition(isInBackgroundPredicate.id()); -// durationMetric->set_aggregation_type(DurationMetric::SUM); -// durationMetric->set_bucket(FIVE_MINUTES); -// -// ConfigKey cfgKey; -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// auto& eventActivationMap = metricProducer->mEventActivationMap; -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_TRUE(eventActivationMap.empty()); -// -// int appUid = 123; -// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")}; -// -// auto event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10 -// processor->OnLogEvent(event.get()); -// -// event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22 -// processor->OnLogEvent(event.get()); -// -// event = CreateMoveToForegroundEvent( -// appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15 -// processor->OnLogEvent(event.get()); -// -// event = CreateReleaseWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 4 * 60 * NS_PER_SEC); // 4:00 -// processor->OnLogEvent(event.get()); -// -// vector<uint8_t> buffer; -// ConfigMetricsReportList reports; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, -// ADB_DUMP, FAST, &buffer); -// EXPECT_GT(buffer.size(), 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStringInReport(&reports); -// backfillStartEndTimestamp(&reports); -// -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); -// -// auto data = reports.reports(0).metrics(0).duration_metrics().data(0); -// -// // Validate bucket info. -// EXPECT_EQ(1, data.bucket_info_size()); -// -// auto bucketInfo = data.bucket_info(0); -// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); -// EXPECT_EQ((2 * 60 + 53) * NS_PER_SEC, bucketInfo.duration_nanos()); -//} -// -//TEST(DurationMetricE2eTest, TestWithSlicedCondition) { -// StatsdConfig config; -// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. -// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); -// *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher(); -// *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher(); -// *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); -// *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); -// -// auto holdingWakelockPredicate = CreateHoldingWakelockPredicate(); -// // The predicate is dimensioning by first attribution node by uid. -// FieldMatcher dimensions = CreateAttributionUidDimensions( -// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); -// *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions; -// *config.add_predicate() = holdingWakelockPredicate; -// -// auto isInBackgroundPredicate = CreateIsInBackgroundPredicate(); -// *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() = -// CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST}); -// *config.add_predicate() = isInBackgroundPredicate; -// -// auto durationMetric = config.add_duration_metric(); -// durationMetric->set_id(StringToId("WakelockDuration")); -// durationMetric->set_what(holdingWakelockPredicate.id()); -// durationMetric->set_condition(isInBackgroundPredicate.id()); -// durationMetric->set_aggregation_type(DurationMetric::SUM); -// // The metric is dimensioning by first attribution node and only by uid. -// *durationMetric->mutable_dimensions_in_what() = -// CreateAttributionUidDimensions( -// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); -// durationMetric->set_bucket(FIVE_MINUTES); -// -// // Links between wakelock state atom and condition of app is in background. -// auto links = durationMetric->add_links(); -// links->set_condition(isInBackgroundPredicate.id()); -// auto dimensionWhat = links->mutable_fields_in_what(); -// dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED); -// dimensionWhat->add_child()->set_field(1); // uid field. -// *links->mutable_fields_in_condition() = CreateAttributionUidDimensions( -// android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, { Position::FIRST }); -// -// ConfigKey cfgKey; -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// auto& eventActivationMap = metricProducer->mEventActivationMap; -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_TRUE(eventActivationMap.empty()); -// -// int appUid = 123; -// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")}; -// -// auto event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10 -// processor->OnLogEvent(event.get()); -// -// event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22 -// processor->OnLogEvent(event.get()); -// -// event = CreateReleaseWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 60 * NS_PER_SEC); // 1:00 -// processor->OnLogEvent(event.get()); -// -// -// event = CreateMoveToForegroundEvent( -// appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15 -// processor->OnLogEvent(event.get()); -// -// vector<uint8_t> buffer; -// ConfigMetricsReportList reports; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, -// ADB_DUMP, FAST, &buffer); -// EXPECT_GT(buffer.size(), 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStringInReport(&reports); -// backfillStartEndTimestamp(&reports); -// -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); -// -// auto data = reports.reports(0).metrics(0).duration_metrics().data(0); -// // Validate dimension value. -// ValidateAttributionUidDimension(data.dimensions_in_what(), -// android::util::WAKELOCK_STATE_CHANGED, appUid); -// // Validate bucket info. -// EXPECT_EQ(1, data.bucket_info_size()); -// -// auto bucketInfo = data.bucket_info(0); -// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); -// EXPECT_EQ(38 * NS_PER_SEC, bucketInfo.duration_nanos()); -//} -// -//TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) { -// StatsdConfig config; -// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. -// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); -// *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher(); -// *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher(); -// *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); -// *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); -// *config.add_atom_matcher() = screenOnMatcher; -// -// auto holdingWakelockPredicate = CreateHoldingWakelockPredicate(); -// // The predicate is dimensioning by first attribution node by uid. -// FieldMatcher dimensions = CreateAttributionUidDimensions( -// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); -// *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions; -// *config.add_predicate() = holdingWakelockPredicate; -// -// auto isInBackgroundPredicate = CreateIsInBackgroundPredicate(); -// *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() = -// CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST}); -// *config.add_predicate() = isInBackgroundPredicate; -// -// auto durationMetric = config.add_duration_metric(); -// durationMetric->set_id(StringToId("WakelockDuration")); -// durationMetric->set_what(holdingWakelockPredicate.id()); -// durationMetric->set_condition(isInBackgroundPredicate.id()); -// durationMetric->set_aggregation_type(DurationMetric::SUM); -// // The metric is dimensioning by first attribution node and only by uid. -// *durationMetric->mutable_dimensions_in_what() = -// CreateAttributionUidDimensions( -// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); -// durationMetric->set_bucket(FIVE_MINUTES); -// -// // Links between wakelock state atom and condition of app is in background. -// auto links = durationMetric->add_links(); -// links->set_condition(isInBackgroundPredicate.id()); -// auto dimensionWhat = links->mutable_fields_in_what(); -// dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED); -// dimensionWhat->add_child()->set_field(1); // uid field. -// *links->mutable_fields_in_condition() = CreateAttributionUidDimensions( -// android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, { Position::FIRST }); -// -// auto metric_activation1 = config.add_metric_activation(); -// metric_activation1->set_metric_id(durationMetric->id()); -// auto event_activation1 = metric_activation1->add_event_activation(); -// event_activation1->set_atom_matcher_id(screenOnMatcher.id()); -// event_activation1->set_ttl_seconds(60 * 2); // 2 minutes. -// -// ConfigKey cfgKey; -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// auto& eventActivationMap = metricProducer->mEventActivationMap; -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap.size(), 1u); -// EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end()); -// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[4]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); -// -// int appUid = 123; -// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")}; -// -// auto event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10 -// processor->OnLogEvent(event.get()); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[4]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); -// -// event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22 -// processor->OnLogEvent(event.get()); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[4]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); -// -// const int64_t durationStartNs = bucketStartTimeNs + 30 * NS_PER_SEC; // 0:30 -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs); -// processor->OnLogEvent(event.get()); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs); -// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); -// -// const int64_t durationEndNs = -// durationStartNs + (event_activation1->ttl_seconds() + 30) * NS_PER_SEC; // 3:00 -// event = CreateAppCrashEvent(333, durationEndNs); -// processor->OnLogEvent(event.get()); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs); -// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); -// -// event = CreateMoveToForegroundEvent( -// appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15 -// processor->OnLogEvent(event.get()); -// -// event = CreateReleaseWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + (4 * 60 + 17) * NS_PER_SEC); // 4:17 -// processor->OnLogEvent(event.get()); -// -// event = CreateMoveToBackgroundEvent( -// appUid, bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC); // 4:20 -// processor->OnLogEvent(event.get()); -// -// event = CreateAcquireWakelockEvent( -// attributions1, "wl1", bucketStartTimeNs + (4 * 60 + 25) * NS_PER_SEC); // 4:25 -// processor->OnLogEvent(event.get()); -// -// const int64_t duration2StartNs = bucketStartTimeNs + (4 * 60 + 30) * NS_PER_SEC; // 4:30 -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, duration2StartNs); -// processor->OnLogEvent(event.get()); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[4]->start_ns, duration2StartNs); -// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); -// -// vector<uint8_t> buffer; -// ConfigMetricsReportList reports; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, -// ADB_DUMP, FAST, &buffer); -// EXPECT_GT(buffer.size(), 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStringInReport(&reports); -// backfillStartEndTimestamp(&reports); -// -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); -// -// auto data = reports.reports(0).metrics(0).duration_metrics().data(0); -// // Validate dimension value. -// ValidateAttributionUidDimension(data.dimensions_in_what(), -// android::util::WAKELOCK_STATE_CHANGED, appUid); -// // Validate bucket info. -// EXPECT_EQ(2, data.bucket_info_size()); -// -// auto bucketInfo = data.bucket_info(0); -// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(durationEndNs, bucketInfo.end_bucket_elapsed_nanos()); -// EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos()); -// -// bucketInfo = data.bucket_info(1); -// EXPECT_EQ(durationEndNs, bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - duration2StartNs, bucketInfo.duration_nanos()); -//} +TEST(DurationMetricE2eTest, TestOneBucket) { + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + + auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = screenOnMatcher; + *config.add_atom_matcher() = screenOffMatcher; + + auto durationPredicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = durationPredicate; + + int64_t metricId = 123456; + auto durationMetric = config.add_duration_metric(); + durationMetric->set_id(metricId); + durationMetric->set_what(durationPredicate.id()); + durationMetric->set_bucket(FIVE_MINUTES); + durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM); + + const int64_t baseTimeNs = 0; // 0:00 + const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01 + const int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL; + + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey); + + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + + std::unique_ptr<LogEvent> event; + + // Screen is off at start of bucket. + event = CreateScreenStateChangedEvent(configAddedTimeNs, + android::view::DISPLAY_STATE_OFF); // 0:01 + processor->OnLogEvent(event.get()); + + // Turn screen on. + const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11 + event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(event.get()); + + // Turn off screen 30 seconds after turning on. + const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41 + event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(event.get()); + + event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64); // 0:42 + processor->OnLogEvent(event.get()); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true, + ADB_DUMP, FAST, &buffer); // 5:01 + EXPECT_TRUE(buffer.size() > 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStartEndTimestamp(&reports); + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); + + const StatsLogReport::DurationMetricDataWrapper& durationMetrics = + reports.reports(0).metrics(0).duration_metrics(); + EXPECT_EQ(1, durationMetrics.data_size()); + + auto data = durationMetrics.data(0); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos()); + EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); +} + +TEST(DurationMetricE2eTest, TestTwoBuckets) { + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + + auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); + *config.add_atom_matcher() = screenOnMatcher; + *config.add_atom_matcher() = screenOffMatcher; + + auto durationPredicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = durationPredicate; + + int64_t metricId = 123456; + auto durationMetric = config.add_duration_metric(); + durationMetric->set_id(metricId); + durationMetric->set_what(durationPredicate.id()); + durationMetric->set_bucket(FIVE_MINUTES); + durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM); + + const int64_t baseTimeNs = 0; // 0:00 + const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01 + const int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL; + + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey); + + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + + std::unique_ptr<LogEvent> event; + + // Screen is off at start of bucket. + event = CreateScreenStateChangedEvent(configAddedTimeNs, + android::view::DISPLAY_STATE_OFF); // 0:01 + processor->OnLogEvent(event.get()); + + // Turn screen on. + const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11 + event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(event.get()); + + // Turn off screen 30 seconds after turning on. + const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41 + event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(event.get()); + + event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64); // 0:42 + processor->OnLogEvent(event.get()); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, false, + true, ADB_DUMP, FAST, &buffer); // 10:01 + EXPECT_TRUE(buffer.size() > 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStartEndTimestamp(&reports); + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); + + const StatsLogReport::DurationMetricDataWrapper& durationMetrics = + reports.reports(0).metrics(0).duration_metrics(); + EXPECT_EQ(1, durationMetrics.data_size()); + + auto data = durationMetrics.data(0); + EXPECT_EQ(1, data.bucket_info_size()); + + auto bucketInfo = data.bucket_info(0); + EXPECT_EQ(0, bucketInfo.bucket_num()); + EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos()); + EXPECT_EQ(configAddedTimeNs, bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); +} + +TEST(DurationMetricE2eTest, TestWithActivation) { + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + + auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher(); + auto crashMatcher = CreateProcessCrashAtomMatcher(); + *config.add_atom_matcher() = screenOnMatcher; + *config.add_atom_matcher() = screenOffMatcher; + *config.add_atom_matcher() = crashMatcher; + + auto durationPredicate = CreateScreenIsOnPredicate(); + *config.add_predicate() = durationPredicate; + + int64_t metricId = 123456; + auto durationMetric = config.add_duration_metric(); + durationMetric->set_id(metricId); + durationMetric->set_what(durationPredicate.id()); + durationMetric->set_bucket(FIVE_MINUTES); + durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM); + + auto metric_activation1 = config.add_metric_activation(); + metric_activation1->set_metric_id(metricId); + auto event_activation1 = metric_activation1->add_event_activation(); + event_activation1->set_atom_matcher_id(crashMatcher.id()); + event_activation1->set_ttl_seconds(30); // 30 secs. + + const int64_t bucketStartTimeNs = 10000000000; + const int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL; + + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + + sp<UidMap> m = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> subscriberAlarmMonitor; + vector<int64_t> activeConfigsBroadcast; + + int broadcastCount = 0; + StatsLogProcessor processor( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs, + [](const ConfigKey& key) { return true; }, + [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, + const vector<int64_t>& activeConfigs) { + broadcastCount++; + EXPECT_EQ(broadcastUid, uid); + activeConfigsBroadcast.clear(); + activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), + activeConfigs.end()); + return true; + }); + + processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); // 0:00 + + EXPECT_EQ(processor.mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + auto& eventActivationMap = metricProducer->mEventActivationMap; + + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap.size(), 1u); + EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); + + std::unique_ptr<LogEvent> event; + + // Turn screen off. + event = CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * NS_PER_SEC, + android::view::DISPLAY_STATE_OFF); // 0:02 + processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC); + + // Turn screen on. + const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:05 + event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), durationStartNs); + + // Activate metric. + const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:10 + const int64_t activationEndNs = + activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 0:40 + event = CreateAppCrashEvent(activationStartNs, 111); + processor.OnLogEvent(event.get(), activationStartNs); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 1); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); + + // Expire activation. + const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC; + event = CreateScreenBrightnessChangedEvent(expirationNs, 64); // 0:47 + processor.OnLogEvent(event.get(), expirationNs); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 2); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap.size(), 1u); + EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); + + // Turn off screen 10 seconds after activation expiration. + const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC; // 0:50 + event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF); + processor.OnLogEvent(event.get(), durationEndNs); + + // Turn screen on. + const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC; // 0:55 + event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), duration2StartNs); + + // Turn off screen. + const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC; // 1:05 + event = CreateScreenStateChangedEvent(duration2EndNs, android::view::DISPLAY_STATE_OFF); + processor.OnLogEvent(event.get(), duration2EndNs); + + // Activate metric. + const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC; // 1:10 + const int64_t activation2EndNs = + activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 1:40 + event = CreateAppCrashEvent(activation2StartNs, 211); + processor.OnLogEvent(event.get(), activation2StartNs); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 3); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor.onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true, + ADB_DUMP, FAST, &buffer); // 5:01 + EXPECT_TRUE(buffer.size() > 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStartEndTimestamp(&reports); + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); + EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); + + const StatsLogReport::DurationMetricDataWrapper& durationMetrics = + reports.reports(0).metrics(0).duration_metrics(); + EXPECT_EQ(1, durationMetrics.data_size()); + + auto data = durationMetrics.data(0); + EXPECT_EQ(1, data.bucket_info_size()); + + auto bucketInfo = data.bucket_info(0); + EXPECT_EQ(0, bucketInfo.bucket_num()); + EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(expirationNs, bucketInfo.end_bucket_elapsed_nanos()); + EXPECT_EQ(expirationNs - durationStartNs, bucketInfo.duration_nanos()); +} + +TEST(DurationMetricE2eTest, TestWithCondition) { + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher(); + *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher(); + *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); + *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); + + auto holdingWakelockPredicate = CreateHoldingWakelockPredicate(); + *config.add_predicate() = holdingWakelockPredicate; + + auto isInBackgroundPredicate = CreateIsInBackgroundPredicate(); + *config.add_predicate() = isInBackgroundPredicate; + + auto durationMetric = config.add_duration_metric(); + durationMetric->set_id(StringToId("WakelockDuration")); + durationMetric->set_what(holdingWakelockPredicate.id()); + durationMetric->set_condition(isInBackgroundPredicate.id()); + durationMetric->set_aggregation_type(DurationMetric::SUM); + durationMetric->set_bucket(FIVE_MINUTES); + + ConfigKey cfgKey; + uint64_t bucketStartTimeNs = 10000000000; + uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + auto& eventActivationMap = metricProducer->mEventActivationMap; + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_TRUE(eventActivationMap.empty()); + + int appUid = 123; + vector<int> attributionUids1 = {appUid}; + vector<string> attributionTags1 = {"App1"}; + + auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1, + attributionTags1, + "wl1"); // 0:10 + processor->OnLogEvent(event.get()); + + event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22 + processor->OnLogEvent(event.get()); + + event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC, + appUid); // 3:15 + processor->OnLogEvent(event.get()); + + event = CreateReleaseWakelockEvent(bucketStartTimeNs + 4 * 60 * NS_PER_SEC, attributionUids1, + attributionTags1, + "wl1"); // 4:00 + processor->OnLogEvent(event.get()); + + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); + + auto data = reports.reports(0).metrics(0).duration_metrics().data(0); + + // Validate bucket info. + EXPECT_EQ(1, data.bucket_info_size()); + + auto bucketInfo = data.bucket_info(0); + EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); + EXPECT_EQ((2 * 60 + 53) * NS_PER_SEC, bucketInfo.duration_nanos()); +} + +TEST(DurationMetricE2eTest, TestWithSlicedCondition) { + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher(); + *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher(); + *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); + *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); + + auto holdingWakelockPredicate = CreateHoldingWakelockPredicate(); + // The predicate is dimensioning by first attribution node by uid. + FieldMatcher dimensions = CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED, + {Position::FIRST}); + *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions; + *config.add_predicate() = holdingWakelockPredicate; + + auto isInBackgroundPredicate = CreateIsInBackgroundPredicate(); + *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() = + CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST}); + *config.add_predicate() = isInBackgroundPredicate; + + auto durationMetric = config.add_duration_metric(); + durationMetric->set_id(StringToId("WakelockDuration")); + durationMetric->set_what(holdingWakelockPredicate.id()); + durationMetric->set_condition(isInBackgroundPredicate.id()); + durationMetric->set_aggregation_type(DurationMetric::SUM); + // The metric is dimensioning by first attribution node and only by uid. + *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions( + android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); + durationMetric->set_bucket(FIVE_MINUTES); + + // Links between wakelock state atom and condition of app is in background. + auto links = durationMetric->add_links(); + links->set_condition(isInBackgroundPredicate.id()); + auto dimensionWhat = links->mutable_fields_in_what(); + dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED); + dimensionWhat->add_child()->set_field(1); // uid field. + *links->mutable_fields_in_condition() = CreateAttributionUidDimensions( + android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST}); + + ConfigKey cfgKey; + uint64_t bucketStartTimeNs = 10000000000; + uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + auto& eventActivationMap = metricProducer->mEventActivationMap; + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_TRUE(eventActivationMap.empty()); + + int appUid = 123; + std::vector<int> attributionUids1 = {appUid}; + std::vector<string> attributionTags1 = {"App1"}; + + auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1, + attributionTags1, "wl1"); // 0:10 + processor->OnLogEvent(event.get()); + + event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22 + processor->OnLogEvent(event.get()); + + event = CreateReleaseWakelockEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1, + attributionTags1, "wl1"); // 1:00 + processor->OnLogEvent(event.get()); + + event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC, + appUid); // 3:15 + processor->OnLogEvent(event.get()); + + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); + + auto data = reports.reports(0).metrics(0).duration_metrics().data(0); + // Validate dimension value. + ValidateAttributionUidDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, appUid); + // Validate bucket info. + EXPECT_EQ(1, data.bucket_info_size()); + + auto bucketInfo = data.bucket_info(0); + EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); + EXPECT_EQ(38 * NS_PER_SEC, bucketInfo.duration_nanos()); +} + +TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) { + StatsdConfig config; + config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher(); + *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher(); + *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); + *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); + *config.add_atom_matcher() = screenOnMatcher; + + auto holdingWakelockPredicate = CreateHoldingWakelockPredicate(); + // The predicate is dimensioning by first attribution node by uid. + FieldMatcher dimensions = CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED, + {Position::FIRST}); + *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions; + *config.add_predicate() = holdingWakelockPredicate; + + auto isInBackgroundPredicate = CreateIsInBackgroundPredicate(); + *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() = + CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST}); + *config.add_predicate() = isInBackgroundPredicate; + + auto durationMetric = config.add_duration_metric(); + durationMetric->set_id(StringToId("WakelockDuration")); + durationMetric->set_what(holdingWakelockPredicate.id()); + durationMetric->set_condition(isInBackgroundPredicate.id()); + durationMetric->set_aggregation_type(DurationMetric::SUM); + // The metric is dimensioning by first attribution node and only by uid. + *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions( + android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST}); + durationMetric->set_bucket(FIVE_MINUTES); + + // Links between wakelock state atom and condition of app is in background. + auto links = durationMetric->add_links(); + links->set_condition(isInBackgroundPredicate.id()); + auto dimensionWhat = links->mutable_fields_in_what(); + dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED); + dimensionWhat->add_child()->set_field(1); // uid field. + *links->mutable_fields_in_condition() = CreateAttributionUidDimensions( + android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST}); + + auto metric_activation1 = config.add_metric_activation(); + metric_activation1->set_metric_id(durationMetric->id()); + auto event_activation1 = metric_activation1->add_event_activation(); + event_activation1->set_atom_matcher_id(screenOnMatcher.id()); + event_activation1->set_ttl_seconds(60 * 2); // 2 minutes. + + ConfigKey cfgKey; + uint64_t bucketStartTimeNs = 10000000000; + uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + auto& eventActivationMap = metricProducer->mEventActivationMap; + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap.size(), 1u); + EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end()); + EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[4]->start_ns, 0); + EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); + + int appUid = 123; + std::vector<int> attributionUids1 = {appUid}; + std::vector<string> attributionTags1 = {"App1"}; + + auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1, + attributionTags1, "wl1"); // 0:10 + processor->OnLogEvent(event.get()); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[4]->start_ns, 0); + EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); + + event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22 + processor->OnLogEvent(event.get()); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[4]->start_ns, 0); + EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); + + const int64_t durationStartNs = bucketStartTimeNs + 30 * NS_PER_SEC; // 0:30 + event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(event.get()); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs); + EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); + + const int64_t durationEndNs = + durationStartNs + (event_activation1->ttl_seconds() + 30) * NS_PER_SEC; // 3:00 + event = CreateAppCrashEvent(durationEndNs, 333); + processor->OnLogEvent(event.get()); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs); + EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); + + event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC, + appUid); // 3:15 + processor->OnLogEvent(event.get()); + + event = CreateReleaseWakelockEvent(bucketStartTimeNs + (4 * 60 + 17) * NS_PER_SEC, + attributionUids1, attributionTags1, "wl1"); // 4:17 + processor->OnLogEvent(event.get()); + + event = CreateMoveToBackgroundEvent(bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC, + appUid); // 4:20 + processor->OnLogEvent(event.get()); + + event = CreateAcquireWakelockEvent(bucketStartTimeNs + (4 * 60 + 25) * NS_PER_SEC, + attributionUids1, attributionTags1, "wl1"); // 4:25 + processor->OnLogEvent(event.get()); + + const int64_t duration2StartNs = bucketStartTimeNs + (4 * 60 + 30) * NS_PER_SEC; // 4:30 + event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(event.get()); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[4]->start_ns, duration2StartNs); + EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC); + + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP, + FAST, &buffer); + EXPECT_GT(buffer.size(), 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStringInReport(&reports); + backfillStartEndTimestamp(&reports); + + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); + + auto data = reports.reports(0).metrics(0).duration_metrics().data(0); + // Validate dimension value. + ValidateAttributionUidDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, appUid); + // Validate bucket info. + EXPECT_EQ(2, data.bucket_info_size()); + + auto bucketInfo = data.bucket_info(0); + EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(durationEndNs, bucketInfo.end_bucket_elapsed_nanos()); + EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos()); + + bucketInfo = data.bucket_info(1); + EXPECT_EQ(durationEndNs, bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - duration2StartNs, bucketInfo.duration_nanos()); +} #else GTEST_LOG_(INFO) << "This test does nothing.\n"; diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp index 7f651d4ba529..594c1e6bf6e7 100644 --- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp @@ -65,482 +65,465 @@ StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType sampling_type, } // namespaces -// TODO(b/149590301): Update this test to use new socket schema. -//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) { -// auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE); -// int64_t baseTimeNs = getElapsedRealtimeNs(); -// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, -// SharedRefBase::make<FakeSubsystemSleepCallback>(), -// ATOM_TAG); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// processor->mPullerManager->ForceClearPullerCache(); -// -// int startBucketNum = processor->mMetricsManagers.begin()->second-> -// mAllMetricProducers[0]->getCurrentBucketNum(); -// EXPECT_GT(startBucketNum, (int64_t)0); -// -// // When creating the config, the gauge metric producer should register the alarm at the -// // end of the current bucket. -// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); -// EXPECT_EQ(bucketSizeNs, -// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); -// int64_t& nextPullTimeNs = -// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs); -// -// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 55); -// processor->OnLogEvent(screenOffEvent.get()); -// -// // Pulling alarm arrives on time and reset the sequential pulling alarm. -// processor->informPullAlarmFired(nextPullTimeNs + 1); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs); -// -// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// configAddedTimeNs + bucketSizeNs + 10); -// processor->OnLogEvent(screenOnEvent.get()); -// -// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + bucketSizeNs + 100); -// processor->OnLogEvent(screenOffEvent.get()); -// -// processor->informPullAlarmFired(nextPullTimeNs + 1); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, -// nextPullTimeNs); -// -// processor->informPullAlarmFired(nextPullTimeNs + 1); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs); -// -// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// configAddedTimeNs + 3 * bucketSizeNs + 2); -// processor->OnLogEvent(screenOnEvent.get()); -// -// processor->informPullAlarmFired(nextPullTimeNs + 3); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs); -// -// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 5 * bucketSizeNs + 1); -// processor->OnLogEvent(screenOffEvent.get()); -// -// processor->informPullAlarmFired(nextPullTimeNs + 2); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, nextPullTimeNs); -// -// processor->informPullAlarmFired(nextPullTimeNs + 2); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, 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(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); -// EXPECT_GT((int)gaugeMetrics.data_size(), 1); -// -// auto data = gaugeMetrics.data(0); -// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* subsystem name field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); -// EXPECT_EQ(6, data.bucket_info_size()); -// -// EXPECT_EQ(1, data.bucket_info(0).atom_size()); -// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0); -// -// EXPECT_EQ(1, data.bucket_info(1).atom_size()); -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, -// data.bucket_info(1).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0); -// -// EXPECT_EQ(1, data.bucket_info(2).atom_size()); -// EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, -// data.bucket_info(2).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0); -// -// EXPECT_EQ(1, data.bucket_info(3).atom_size()); -// EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1, -// data.bucket_info(3).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(3).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(3).atom(0).subsystem_sleep_state().time_millis(), 0); -// -// EXPECT_EQ(1, data.bucket_info(4).atom_size()); -// EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, -// data.bucket_info(4).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(4).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(4).atom(0).subsystem_sleep_state().time_millis(), 0); -// -// EXPECT_EQ(1, data.bucket_info(5).atom_size()); -// EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2, -// data.bucket_info(5).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(5).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(5).atom(0).subsystem_sleep_state().time_millis(), 0); -//} -// -//TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) { -// auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE); -// int64_t baseTimeNs = getElapsedRealtimeNs(); -// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, -// SharedRefBase::make<FakeSubsystemSleepCallback>(), -// ATOM_TAG); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// processor->mPullerManager->ForceClearPullerCache(); -// -// int startBucketNum = processor->mMetricsManagers.begin()->second-> -// mAllMetricProducers[0]->getCurrentBucketNum(); -// EXPECT_GT(startBucketNum, (int64_t)0); -// -// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 55); -// processor->OnLogEvent(screenOffEvent.get()); -// -// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// configAddedTimeNs + bucketSizeNs + 10); -// processor->OnLogEvent(screenOnEvent.get()); -// -// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + bucketSizeNs + 100); -// processor->OnLogEvent(screenOffEvent.get()); -// -// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// configAddedTimeNs + 3 * bucketSizeNs + 2); -// processor->OnLogEvent(screenOnEvent.get()); -// -// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 5 * bucketSizeNs + 1); -// processor->OnLogEvent(screenOffEvent.get()); -// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// configAddedTimeNs + 5 * bucketSizeNs + 3); -// processor->OnLogEvent(screenOnEvent.get()); -// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 5 * bucketSizeNs + 10); -// processor->OnLogEvent(screenOffEvent.get()); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, 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(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); -// EXPECT_GT((int)gaugeMetrics.data_size(), 1); -// -// auto data = gaugeMetrics.data(0); -// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* subsystem name field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); -// EXPECT_EQ(3, data.bucket_info_size()); -// -// EXPECT_EQ(1, data.bucket_info(0).atom_size()); -// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0); -// -// EXPECT_EQ(1, data.bucket_info(1).atom_size()); -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100, -// data.bucket_info(1).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0); -// -// EXPECT_EQ(2, data.bucket_info(2).atom_size()); -// EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, -// data.bucket_info(2).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10, -// data.bucket_info(2).elapsed_timestamp_nanos(1)); -// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0); -// EXPECT_TRUE(data.bucket_info(2).atom(1).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(2).atom(1).subsystem_sleep_state().time_millis(), 0); -//} -// -// -//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) { -// auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE); -// int64_t baseTimeNs = getElapsedRealtimeNs(); -// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, -// SharedRefBase::make<FakeSubsystemSleepCallback>(), -// ATOM_TAG); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// processor->mPullerManager->ForceClearPullerCache(); -// -// int startBucketNum = processor->mMetricsManagers.begin()->second-> -// mAllMetricProducers[0]->getCurrentBucketNum(); -// EXPECT_GT(startBucketNum, (int64_t)0); -// -// // When creating the config, the gauge metric producer should register the alarm at the -// // end of the current bucket. -// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); -// EXPECT_EQ(bucketSizeNs, -// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); -// int64_t& nextPullTimeNs = -// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs); -// -// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 55); -// processor->OnLogEvent(screenOffEvent.get()); -// -// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// configAddedTimeNs + bucketSizeNs + 10); -// processor->OnLogEvent(screenOnEvent.get()); -// -// // Pulling alarm arrives one bucket size late. -// processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs); -// -// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 3 * bucketSizeNs + 11); -// processor->OnLogEvent(screenOffEvent.get()); -// -// // Pulling alarm arrives more than one bucket size late. -// processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs + 12); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, 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(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); -// EXPECT_GT((int)gaugeMetrics.data_size(), 1); -// -// auto data = gaugeMetrics.data(0); -// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* subsystem name field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); -// EXPECT_EQ(3, data.bucket_info_size()); -// -// EXPECT_EQ(1, data.bucket_info(0).atom_size()); -// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0); -// -// EXPECT_EQ(1, data.bucket_info(1).atom_size()); -// EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11, -// data.bucket_info(1).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0); -// -// EXPECT_EQ(1, data.bucket_info(2).atom_size()); -// EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12, -// data.bucket_info(2).elapsed_timestamp_nanos(0)); -// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos()); -// EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0); -//} -// -//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) { -// auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false); -// -// int64_t baseTimeNs = getElapsedRealtimeNs(); -// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; -// -// auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher(); -// *config.add_atom_matcher() = batterySaverStartMatcher; -// const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets. -// auto metric_activation = config.add_metric_activation(); -// metric_activation->set_metric_id(metricId); -// metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY); -// auto event_activation = metric_activation->add_event_activation(); -// event_activation->set_atom_matcher_id(batterySaverStartMatcher.id()); -// event_activation->set_ttl_seconds(ttlNs / 1000000000); -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, -// SharedRefBase::make<FakeSubsystemSleepCallback>(), -// ATOM_TAG); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// processor->mPullerManager->ForceClearPullerCache(); -// -// int startBucketNum = processor->mMetricsManagers.begin()->second-> -// mAllMetricProducers[0]->getCurrentBucketNum(); -// EXPECT_GT(startBucketNum, (int64_t)0); -// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); -// -// // When creating the config, the gauge metric producer should register the alarm at the -// // end of the current bucket. -// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); -// EXPECT_EQ(bucketSizeNs, -// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); -// int64_t& nextPullTimeNs = -// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs); -// -// // Pulling alarm arrives on time and reset the sequential pulling alarm. -// // Event should not be kept. -// processor->informPullAlarmFired(nextPullTimeNs + 1); // 15 mins + 1 ns. -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs); -// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); -// -// // Activate the metric. A pull occurs upon activation. -// const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis. -// auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs); -// processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms. -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); -// -// // This event should be kept. 2 total. -// processor->informPullAlarmFired(nextPullTimeNs + 1); // 20 mins + 1 ns. -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, -// nextPullTimeNs); -// -// // This event should be kept. 3 total. -// processor->informPullAlarmFired(nextPullTimeNs + 2); // 25 mins + 2 ns. -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs); -// -// // Create random event to deactivate metric. -// auto deactivationEvent = CreateScreenBrightnessChangedEvent(50, activationNs + ttlNs + 1); -// processor->OnLogEvent(deactivationEvent.get()); -// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); -// -// // Event should not be kept. 3 total. -// processor->informPullAlarmFired(nextPullTimeNs + 3); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs); -// -// processor->informPullAlarmFired(nextPullTimeNs + 2); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, 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(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); -// EXPECT_GT((int)gaugeMetrics.data_size(), 0); -// -// auto data = gaugeMetrics.data(0); -// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* subsystem name field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); -// EXPECT_EQ(3, data.bucket_info_size()); -// -// auto bucketInfo = data.bucket_info(0); -// EXPECT_EQ(1, bucketInfo.atom_size()); -// EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size()); -// EXPECT_EQ(activationNs, bucketInfo.elapsed_timestamp_nanos(0)); -// EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); -// EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0); -// -// bucketInfo = data.bucket_info(1); -// EXPECT_EQ(1, bucketInfo.atom_size()); -// EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, bucketInfo.elapsed_timestamp_nanos(0)); -// EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); -// EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0); -// -// bucketInfo = data.bucket_info(2); -// EXPECT_EQ(1, bucketInfo.atom_size()); -// EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size()); -// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, bucketInfo.elapsed_timestamp_nanos(0)); -// EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size()); -// EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)), -// bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)), -// bucketInfo.end_bucket_elapsed_nanos()); -// EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty()); -// EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0); -//} +TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) { + auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE); + int64_t baseTimeNs = getElapsedRealtimeNs(); + int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = + CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + processor->mPullerManager->ForceClearPullerCache(); + + int startBucketNum = processor->mMetricsManagers.begin() + ->second->mAllMetricProducers[0] + ->getCurrentBucketNum(); + EXPECT_GT(startBucketNum, (int64_t)0); + + // When creating the config, the gauge metric producer should register the alarm at the + // end of the current bucket. + EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); + EXPECT_EQ(bucketSizeNs, + processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); + int64_t& nextPullTimeNs = + processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs); + + auto screenOffEvent = + CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + // Pulling alarm arrives on time and reset the sequential pulling alarm. + processor->informPullAlarmFired(nextPullTimeNs + 1); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs); + + auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10, + android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(screenOnEvent.get()); + + screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 100, + android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + processor->informPullAlarmFired(nextPullTimeNs + 1); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs); + + processor->informPullAlarmFired(nextPullTimeNs + 1); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs); + + screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 2, + android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(screenOnEvent.get()); + + processor->informPullAlarmFired(nextPullTimeNs + 3); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs); + + screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 1, + android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + processor->informPullAlarmFired(nextPullTimeNs + 2); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, nextPullTimeNs); + + processor->informPullAlarmFired(nextPullTimeNs + 2); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, 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(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); + EXPECT_GT((int)gaugeMetrics.data_size(), 1); + + auto data = gaugeMetrics.data(0); + EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* subsystem name field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); + EXPECT_EQ(6, data.bucket_info_size()); + + EXPECT_EQ(1, data.bucket_info(0).atom_size()); + EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); + EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); + EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0); + + EXPECT_EQ(1, data.bucket_info(1).atom_size()); + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0); + + EXPECT_EQ(1, data.bucket_info(2).atom_size()); + EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0); + + EXPECT_EQ(1, data.bucket_info(3).atom_size()); + EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1, data.bucket_info(3).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(3).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(3).atom(0).subsystem_sleep_state().time_millis(), 0); + + EXPECT_EQ(1, data.bucket_info(4).atom_size()); + EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(4).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(4).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(4).atom(0).subsystem_sleep_state().time_millis(), 0); + + EXPECT_EQ(1, data.bucket_info(5).atom_size()); + EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2, data.bucket_info(5).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(5).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(5).atom(0).subsystem_sleep_state().time_millis(), 0); +} + +TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) { + auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE); + int64_t baseTimeNs = getElapsedRealtimeNs(); + int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = + CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + processor->mPullerManager->ForceClearPullerCache(); + + int startBucketNum = processor->mMetricsManagers.begin() + ->second->mAllMetricProducers[0] + ->getCurrentBucketNum(); + EXPECT_GT(startBucketNum, (int64_t)0); + + auto screenOffEvent = + CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10, + android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(screenOnEvent.get()); + + screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 100, + android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 2, + android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(screenOnEvent.get()); + + screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 1, + android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 3, + android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(screenOnEvent.get()); + screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 10, + android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, 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(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); + EXPECT_GT((int)gaugeMetrics.data_size(), 1); + + auto data = gaugeMetrics.data(0); + EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* subsystem name field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); + EXPECT_EQ(3, data.bucket_info_size()); + + EXPECT_EQ(1, data.bucket_info(0).atom_size()); + EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); + EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); + EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0); + + EXPECT_EQ(1, data.bucket_info(1).atom_size()); + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100, data.bucket_info(1).elapsed_timestamp_nanos(0)); + EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0); + + EXPECT_EQ(2, data.bucket_info(2).atom_size()); + EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10, data.bucket_info(2).elapsed_timestamp_nanos(1)); + EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0); + EXPECT_TRUE(data.bucket_info(2).atom(1).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(2).atom(1).subsystem_sleep_state().time_millis(), 0); +} + +TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) { + auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE); + int64_t baseTimeNs = getElapsedRealtimeNs(); + int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = + CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + processor->mPullerManager->ForceClearPullerCache(); + + int startBucketNum = processor->mMetricsManagers.begin() + ->second->mAllMetricProducers[0] + ->getCurrentBucketNum(); + EXPECT_GT(startBucketNum, (int64_t)0); + + // When creating the config, the gauge metric producer should register the alarm at the + // end of the current bucket. + EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); + EXPECT_EQ(bucketSizeNs, + processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); + int64_t& nextPullTimeNs = + processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs); + + auto screenOffEvent = + CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10, + android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(screenOnEvent.get()); + + // Pulling alarm arrives one bucket size late. + processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs); + + screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 11, + android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + // Pulling alarm arrives more than one bucket size late. + processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs + 12); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, 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(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); + EXPECT_GT((int)gaugeMetrics.data_size(), 1); + + auto data = gaugeMetrics.data(0); + EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* subsystem name field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); + EXPECT_EQ(3, data.bucket_info_size()); + + EXPECT_EQ(1, data.bucket_info(0).atom_size()); + EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); + EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0); + + EXPECT_EQ(1, data.bucket_info(1).atom_size()); + EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11, + data.bucket_info(1).elapsed_timestamp_nanos(0)); + EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0); + + EXPECT_EQ(1, data.bucket_info(2).atom_size()); + EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12, data.bucket_info(2).elapsed_timestamp_nanos(0)); + EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos()); + EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0); +} + +TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) { + auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false); + + int64_t baseTimeNs = getElapsedRealtimeNs(); + int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; + + auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher(); + *config.add_atom_matcher() = batterySaverStartMatcher; + const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets. + auto metric_activation = config.add_metric_activation(); + metric_activation->set_metric_id(metricId); + metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY); + auto event_activation = metric_activation->add_event_activation(); + event_activation->set_atom_matcher_id(batterySaverStartMatcher.id()); + event_activation->set_ttl_seconds(ttlNs / 1000000000); + + ConfigKey cfgKey; + auto processor = + CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + processor->mPullerManager->ForceClearPullerCache(); + + int startBucketNum = processor->mMetricsManagers.begin() + ->second->mAllMetricProducers[0] + ->getCurrentBucketNum(); + EXPECT_GT(startBucketNum, (int64_t)0); + EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); + + // When creating the config, the gauge metric producer should register the alarm at the + // end of the current bucket. + EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); + EXPECT_EQ(bucketSizeNs, + processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); + int64_t& nextPullTimeNs = + processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs); + + // Pulling alarm arrives on time and reset the sequential pulling alarm. + // Event should not be kept. + processor->informPullAlarmFired(nextPullTimeNs + 1); // 15 mins + 1 ns. + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs); + EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); + + // Activate the metric. A pull occurs upon activation. + const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis. + auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs); + processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms. + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); + + // This event should be kept. 2 total. + processor->informPullAlarmFired(nextPullTimeNs + 1); // 20 mins + 1 ns. + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs); + + // This event should be kept. 3 total. + processor->informPullAlarmFired(nextPullTimeNs + 2); // 25 mins + 2 ns. + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs); + + // Create random event to deactivate metric. + auto deactivationEvent = CreateScreenBrightnessChangedEvent(activationNs + ttlNs + 1, 50); + processor->OnLogEvent(deactivationEvent.get()); + EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); + + // Event should not be kept. 3 total. + processor->informPullAlarmFired(nextPullTimeNs + 3); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs); + + processor->informPullAlarmFired(nextPullTimeNs + 2); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, 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(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); + EXPECT_GT((int)gaugeMetrics.data_size(), 0); + + auto data = gaugeMetrics.data(0); + EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* subsystem name field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); + EXPECT_EQ(3, data.bucket_info_size()); + + auto bucketInfo = data.bucket_info(0); + EXPECT_EQ(1, bucketInfo.atom_size()); + EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size()); + EXPECT_EQ(activationNs, bucketInfo.elapsed_timestamp_nanos(0)); + EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); + EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0); + + bucketInfo = data.bucket_info(1); + EXPECT_EQ(1, bucketInfo.atom_size()); + EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, bucketInfo.elapsed_timestamp_nanos(0)); + EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); + EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0); + + bucketInfo = data.bucket_info(2); + EXPECT_EQ(1, bucketInfo.atom_size()); + EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size()); + EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, bucketInfo.elapsed_timestamp_nanos(0)); + EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size()); + EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)), + bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)), + bucketInfo.end_bucket_elapsed_nanos()); + EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty()); + EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0); +} TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition) { auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false); diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp index ef6e753b802d..6e3d93a5547f 100644 --- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp @@ -14,12 +14,13 @@ #include <gtest/gtest.h> +#include <vector> + #include "src/StatsLogProcessor.h" #include "src/stats_log_util.h" +#include "stats_event.h" #include "tests/statsd_test_util.h" -#include <vector> - namespace android { namespace os { namespace statsd { @@ -68,221 +69,227 @@ StatsdConfig CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sa return config; } -// TODO(b/149590301): Update this helper to use new socket schema. -//std::unique_ptr<LogEvent> CreateAppStartOccurredEvent( -// const int uid, const string& pkg_name, AppStartOccurred::TransitionType type, -// const string& activity_name, const string& calling_pkg_name, const bool is_instant_app, -// int64_t activity_start_msec, uint64_t timestampNs) { -// auto logEvent = std::make_unique<LogEvent>( -// android::util::APP_START_OCCURRED, timestampNs); -// logEvent->write(uid); -// logEvent->write(pkg_name); -// logEvent->write(type); -// logEvent->write(activity_name); -// logEvent->write(calling_pkg_name); -// logEvent->write(is_instant_app); -// logEvent->write(activity_start_msec); -// logEvent->init(); -// return logEvent; -//} +std::unique_ptr<LogEvent> CreateAppStartOccurredEvent( + uint64_t timestampNs, const int uid, const string& pkg_name, + AppStartOccurred::TransitionType type, const string& activity_name, + const string& calling_pkg_name, const bool is_instant_app, int64_t activity_start_msec) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::APP_START_OCCURRED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, uid); + AStatsEvent_writeString(statsEvent, pkg_name.c_str()); + AStatsEvent_writeInt32(statsEvent, type); + AStatsEvent_writeString(statsEvent, activity_name.c_str()); + AStatsEvent_writeString(statsEvent, calling_pkg_name.c_str()); + AStatsEvent_writeInt32(statsEvent, is_instant_app); + AStatsEvent_writeInt32(statsEvent, activity_start_msec); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} } // namespace -// TODO(b/149590301): Update this test to use new socket schema. -//TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { -// for (const auto& sampling_type : -// { GaugeMetric::FIRST_N_SAMPLES, GaugeMetric:: RANDOM_ONE_SAMPLE }) { -// auto config = CreateStatsdConfigForPushedEvent(sampling_type); -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor( -// bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// -// int appUid1 = 123; -// int appUid2 = 456; -// std::vector<std::unique_ptr<LogEvent>> events; -// events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + 15)); -// events.push_back(CreateMoveToForegroundEvent( -// appUid1, bucketStartTimeNs + bucketSizeNs + 250)); -// events.push_back(CreateMoveToBackgroundEvent( -// appUid1, bucketStartTimeNs + bucketSizeNs + 350)); -// events.push_back(CreateMoveToForegroundEvent( -// appUid1, bucketStartTimeNs + 2 * bucketSizeNs + 100)); -// -// -// events.push_back(CreateAppStartOccurredEvent( -// appUid1, "app1", AppStartOccurred::WARM, "activity_name1", "calling_pkg_name1", -// true /*is_instant_app*/, 101 /*activity_start_msec*/, bucketStartTimeNs + 10)); -// events.push_back(CreateAppStartOccurredEvent( -// appUid1, "app1", AppStartOccurred::HOT, "activity_name2", "calling_pkg_name2", -// true /*is_instant_app*/, 102 /*activity_start_msec*/, bucketStartTimeNs + 20)); -// events.push_back(CreateAppStartOccurredEvent( -// appUid1, "app1", AppStartOccurred::COLD, "activity_name3", "calling_pkg_name3", -// true /*is_instant_app*/, 103 /*activity_start_msec*/, bucketStartTimeNs + 30)); -// events.push_back(CreateAppStartOccurredEvent( -// appUid1, "app1", AppStartOccurred::WARM, "activity_name4", "calling_pkg_name4", -// true /*is_instant_app*/, 104 /*activity_start_msec*/, -// bucketStartTimeNs + bucketSizeNs + 30)); -// events.push_back(CreateAppStartOccurredEvent( -// appUid1, "app1", AppStartOccurred::COLD, "activity_name5", "calling_pkg_name5", -// true /*is_instant_app*/, 105 /*activity_start_msec*/, -// bucketStartTimeNs + 2 * bucketSizeNs)); -// events.push_back(CreateAppStartOccurredEvent( -// appUid1, "app1", AppStartOccurred::HOT, "activity_name6", "calling_pkg_name6", -// false /*is_instant_app*/, 106 /*activity_start_msec*/, -// bucketStartTimeNs + 2 * bucketSizeNs + 10)); -// -// events.push_back(CreateMoveToBackgroundEvent( -// appUid2, bucketStartTimeNs + bucketSizeNs + 10)); -// events.push_back(CreateAppStartOccurredEvent( -// appUid2, "app2", AppStartOccurred::COLD, "activity_name7", "calling_pkg_name7", -// true /*is_instant_app*/, 201 /*activity_start_msec*/, -// bucketStartTimeNs + 2 * bucketSizeNs + 10)); -// -// sortLogEventsByTimestamp(&events); -// -// for (const auto& event : events) { -// processor->OnLogEvent(event.get()); -// } -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, 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(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics); -// EXPECT_EQ(2, gaugeMetrics.data_size()); -// -// auto data = gaugeMetrics.data(0); -// EXPECT_EQ(android::util::APP_START_OCCURRED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(3, data.bucket_info_size()); -// if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) { -// EXPECT_EQ(2, data.bucket_info(0).atom_size()); -// EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// EXPECT_EQ(AppStartOccurred::HOT, -// data.bucket_info(0).atom(0).app_start_occurred().type()); -// EXPECT_EQ("activity_name2", -// data.bucket_info(0).atom(0).app_start_occurred().activity_name()); -// EXPECT_EQ(102L, -// data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis()); -// EXPECT_EQ(AppStartOccurred::COLD, -// data.bucket_info(0).atom(1).app_start_occurred().type()); -// EXPECT_EQ("activity_name3", -// data.bucket_info(0).atom(1).app_start_occurred().activity_name()); -// EXPECT_EQ(103L, -// data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis()); -// -// EXPECT_EQ(1, data.bucket_info(1).atom_size()); -// EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, -// data.bucket_info(1).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(1).end_bucket_elapsed_nanos()); -// EXPECT_EQ(AppStartOccurred::WARM, -// data.bucket_info(1).atom(0).app_start_occurred().type()); -// EXPECT_EQ("activity_name4", -// data.bucket_info(1).atom(0).app_start_occurred().activity_name()); -// EXPECT_EQ(104L, -// data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis()); -// -// EXPECT_EQ(2, data.bucket_info(2).atom_size()); -// EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(2).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, -// data.bucket_info(2).end_bucket_elapsed_nanos()); -// EXPECT_EQ(AppStartOccurred::COLD, -// data.bucket_info(2).atom(0).app_start_occurred().type()); -// EXPECT_EQ("activity_name5", -// data.bucket_info(2).atom(0).app_start_occurred().activity_name()); -// EXPECT_EQ(105L, -// data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis()); -// EXPECT_EQ(AppStartOccurred::HOT, -// data.bucket_info(2).atom(1).app_start_occurred().type()); -// EXPECT_EQ("activity_name6", -// data.bucket_info(2).atom(1).app_start_occurred().activity_name()); -// EXPECT_EQ(106L, -// data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis()); -// } else { -// EXPECT_EQ(1, data.bucket_info(0).atom_size()); -// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// EXPECT_EQ(AppStartOccurred::HOT, -// data.bucket_info(0).atom(0).app_start_occurred().type()); -// EXPECT_EQ("activity_name2", -// data.bucket_info(0).atom(0).app_start_occurred().activity_name()); -// EXPECT_EQ(102L, -// data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis()); -// -// EXPECT_EQ(1, data.bucket_info(1).atom_size()); -// EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, -// data.bucket_info(1).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(1).end_bucket_elapsed_nanos()); -// EXPECT_EQ(AppStartOccurred::WARM, -// data.bucket_info(1).atom(0).app_start_occurred().type()); -// EXPECT_EQ("activity_name4", -// data.bucket_info(1).atom(0).app_start_occurred().activity_name()); -// EXPECT_EQ(104L, -// data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis()); -// -// EXPECT_EQ(1, data.bucket_info(2).atom_size()); -// EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(2).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, -// data.bucket_info(2).end_bucket_elapsed_nanos()); -// EXPECT_EQ(AppStartOccurred::COLD, -// data.bucket_info(2).atom(0).app_start_occurred().type()); -// EXPECT_EQ("activity_name5", -// data.bucket_info(2).atom(0).app_start_occurred().activity_name()); -// EXPECT_EQ(105L, -// data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis()); -// } -// -// data = gaugeMetrics.data(1); -// -// EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_OCCURRED); -// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).atom_size()); -// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type()); -// EXPECT_EQ("activity_name7", -// data.bucket_info(0).atom(0).app_start_occurred().activity_name()); -// EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis()); -// } -//} +TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { + for (const auto& sampling_type : + {GaugeMetric::FIRST_N_SAMPLES, GaugeMetric::RANDOM_ONE_SAMPLE}) { + auto config = CreateStatsdConfigForPushedEvent(sampling_type); + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = + CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + + int appUid1 = 123; + int appUid2 = 456; + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back(CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid1)); + events.push_back( + CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid1)); + events.push_back( + CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid1)); + events.push_back( + CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, appUid1)); + + events.push_back(CreateAppStartOccurredEvent( + bucketStartTimeNs + 10, appUid1, "app1", AppStartOccurred::WARM, "activity_name1", + "calling_pkg_name1", true /*is_instant_app*/, 101 /*activity_start_msec*/)); + events.push_back(CreateAppStartOccurredEvent( + bucketStartTimeNs + 20, appUid1, "app1", AppStartOccurred::HOT, "activity_name2", + "calling_pkg_name2", true /*is_instant_app*/, 102 /*activity_start_msec*/)); + events.push_back(CreateAppStartOccurredEvent( + bucketStartTimeNs + 30, appUid1, "app1", AppStartOccurred::COLD, "activity_name3", + "calling_pkg_name3", true /*is_instant_app*/, 103 /*activity_start_msec*/)); + events.push_back(CreateAppStartOccurredEvent( + bucketStartTimeNs + bucketSizeNs + 30, appUid1, "app1", AppStartOccurred::WARM, + "activity_name4", "calling_pkg_name4", true /*is_instant_app*/, + 104 /*activity_start_msec*/)); + events.push_back(CreateAppStartOccurredEvent( + bucketStartTimeNs + 2 * bucketSizeNs, appUid1, "app1", AppStartOccurred::COLD, + "activity_name5", "calling_pkg_name5", true /*is_instant_app*/, + 105 /*activity_start_msec*/)); + events.push_back(CreateAppStartOccurredEvent( + bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid1, "app1", AppStartOccurred::HOT, + "activity_name6", "calling_pkg_name6", false /*is_instant_app*/, + 106 /*activity_start_msec*/)); + + events.push_back( + CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 10, appUid2)); + events.push_back(CreateAppStartOccurredEvent( + bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid2, "app2", AppStartOccurred::COLD, + "activity_name7", "calling_pkg_name7", true /*is_instant_app*/, + 201 /*activity_start_msec*/)); + + sortLogEventsByTimestamp(&events); + + for (const auto& event : events) { + processor->OnLogEvent(event.get()); + } + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, 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(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + StatsLogReport::GaugeMetricDataWrapper gaugeMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), + &gaugeMetrics); + EXPECT_EQ(2, gaugeMetrics.data_size()); + + auto data = gaugeMetrics.data(0); + EXPECT_EQ(android::util::APP_START_OCCURRED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(3, data.bucket_info_size()); + if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) { + EXPECT_EQ(2, data.bucket_info(0).atom_size()); + EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size()); + EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, + data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(AppStartOccurred::HOT, + data.bucket_info(0).atom(0).app_start_occurred().type()); + EXPECT_EQ("activity_name2", + data.bucket_info(0).atom(0).app_start_occurred().activity_name()); + EXPECT_EQ(102L, + data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis()); + EXPECT_EQ(AppStartOccurred::COLD, + data.bucket_info(0).atom(1).app_start_occurred().type()); + EXPECT_EQ("activity_name3", + data.bucket_info(0).atom(1).app_start_occurred().activity_name()); + EXPECT_EQ(103L, + data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis()); + + EXPECT_EQ(1, data.bucket_info(1).atom_size()); + EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, + data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(1).end_bucket_elapsed_nanos()); + EXPECT_EQ(AppStartOccurred::WARM, + data.bucket_info(1).atom(0).app_start_occurred().type()); + EXPECT_EQ("activity_name4", + data.bucket_info(1).atom(0).app_start_occurred().activity_name()); + EXPECT_EQ(104L, + data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis()); + + EXPECT_EQ(2, data.bucket_info(2).atom_size()); + EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(2).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, + data.bucket_info(2).end_bucket_elapsed_nanos()); + EXPECT_EQ(AppStartOccurred::COLD, + data.bucket_info(2).atom(0).app_start_occurred().type()); + EXPECT_EQ("activity_name5", + data.bucket_info(2).atom(0).app_start_occurred().activity_name()); + EXPECT_EQ(105L, + data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis()); + EXPECT_EQ(AppStartOccurred::HOT, + data.bucket_info(2).atom(1).app_start_occurred().type()); + EXPECT_EQ("activity_name6", + data.bucket_info(2).atom(1).app_start_occurred().activity_name()); + EXPECT_EQ(106L, + data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis()); + } else { + EXPECT_EQ(1, data.bucket_info(0).atom_size()); + EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, + data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(AppStartOccurred::HOT, + data.bucket_info(0).atom(0).app_start_occurred().type()); + EXPECT_EQ("activity_name2", + data.bucket_info(0).atom(0).app_start_occurred().activity_name()); + EXPECT_EQ(102L, + data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis()); + + EXPECT_EQ(1, data.bucket_info(1).atom_size()); + EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, + data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(1).end_bucket_elapsed_nanos()); + EXPECT_EQ(AppStartOccurred::WARM, + data.bucket_info(1).atom(0).app_start_occurred().type()); + EXPECT_EQ("activity_name4", + data.bucket_info(1).atom(0).app_start_occurred().activity_name()); + EXPECT_EQ(104L, + data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis()); + + EXPECT_EQ(1, data.bucket_info(2).atom_size()); + EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(2).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, + data.bucket_info(2).end_bucket_elapsed_nanos()); + EXPECT_EQ(AppStartOccurred::COLD, + data.bucket_info(2).atom(0).app_start_occurred().type()); + EXPECT_EQ("activity_name5", + data.bucket_info(2).atom(0).app_start_occurred().activity_name()); + EXPECT_EQ(105L, + data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis()); + } + + data = gaugeMetrics.data(1); + + EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_OCCURRED); + EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).atom_size()); + EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, + data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type()); + EXPECT_EQ("activity_name7", + data.bucket_info(0).atom(0).app_start_occurred().activity_name()); + EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis()); + } +} #else GTEST_LOG_(INFO) << "This test does nothing.\n"; diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp index f3f7df775899..1dd90e2b9070 100644 --- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp @@ -233,1609 +233,1602 @@ StatsdConfig CreateStatsdConfigWithTwoMetricsTwoDeactivations() { } // namespace -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST(MetricActivationE2eTest, TestCountMetric) { -// auto config = CreateStatsdConfig(); -// -// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; -// -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// -// sp<UidMap> m = new UidMap(); -// sp<StatsPullerManager> pullerManager = new StatsPullerManager(); -// sp<AlarmMonitor> anomalyAlarmMonitor; -// sp<AlarmMonitor> subscriberAlarmMonitor; -// vector<int64_t> activeConfigsBroadcast; -// -// long timeBase1 = 1; -// int broadcastCount = 0; -// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, -// bucketStartTimeNs, [](const ConfigKey& key) { return true; }, -// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, -// const vector<int64_t>& activeConfigs) { -// broadcastCount++; -// EXPECT_EQ(broadcastUid, uid); -// activeConfigsBroadcast.clear(); -// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), -// activeConfigs.begin(), activeConfigs.end()); -// return true; -// }); -// -// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); -// -// EXPECT_EQ(processor.mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// auto& eventActivationMap = metricProducer->mEventActivationMap; -// -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is -// // triggered by screen on event (tracker index 2). -// EXPECT_EQ(eventActivationMap.size(), 2u); -// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); -// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// -// std::unique_ptr<LogEvent> event; -// -// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 0); -// -// // Activated by battery save mode. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 1); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// -// // First processed event. -// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); -// -// // Activated by screen on event. -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// bucketStartTimeNs + 20); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// -// // 2nd processed event. -// // The activation by screen_on event expires, but the one by battery save mode is still active. -// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// // No new broadcast since the config should still be active. -// EXPECT_EQ(broadcastCount, 1); -// -// // 3rd processed event. -// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); -// -// // All activations expired. -// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// // New broadcast since the config is no longer active. -// EXPECT_EQ(broadcastCount, 2); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// -// // Re-activate metric via screen on. -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 3); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// -// // 4th processed event. -// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, -// ADB_DUMP, FAST, &buffer); -// EXPECT_TRUE(buffer.size() > 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStartEndTimestamp(&reports); -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size()); -// -// StatsLogReport::CountMetricDataWrapper countMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).count_metrics(), &countMetrics); -// EXPECT_EQ(4, countMetrics.data_size()); -// -// auto data = countMetrics.data(0); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(1); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(2); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// // Partial bucket as metric is deactivated. -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(3); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -//} -// -//TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { -// auto config = CreateStatsdConfigWithOneDeactivation(); -// -// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; -// -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// -// sp<UidMap> m = new UidMap(); -// sp<StatsPullerManager> pullerManager = new StatsPullerManager(); -// sp<AlarmMonitor> anomalyAlarmMonitor; -// sp<AlarmMonitor> subscriberAlarmMonitor; -// vector<int64_t> activeConfigsBroadcast; -// -// long timeBase1 = 1; -// int broadcastCount = 0; -// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, -// bucketStartTimeNs, [](const ConfigKey& key) { return true; }, -// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, -// const vector<int64_t>& activeConfigs) { -// broadcastCount++; -// EXPECT_EQ(broadcastUid, uid); -// activeConfigsBroadcast.clear(); -// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), -// activeConfigs.begin(), activeConfigs.end()); -// return true; -// }); -// -// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); -// -// EXPECT_EQ(processor.mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// auto& eventActivationMap = metricProducer->mEventActivationMap; -// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap; -// -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is -// // triggered by screen on event (tracker index 2). -// EXPECT_EQ(eventActivationMap.size(), 2u); -// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); -// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap.size(), 1u); -// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); -// EXPECT_EQ(eventDeactivationMap[3].size(), 1u); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// -// std::unique_ptr<LogEvent> event; -// -// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 0); -// -// // Activated by battery save mode. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 1); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// -// // First processed event. -// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); -// -// // Activated by screen on event. -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// bucketStartTimeNs + 20); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// -// // 2nd processed event. -// // The activation by screen_on event expires, but the one by battery save mode is still active. -// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); -// processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// // No new broadcast since the config should still be active. -// EXPECT_EQ(broadcastCount, 1); -// -// // 3rd processed event. -// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); -// -// // All activations expired. -// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// // New broadcast since the config is no longer active. -// EXPECT_EQ(broadcastCount, 2); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// -// // Re-activate metric via screen on. -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 3); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// -// // 4th processed event. -// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); -// -// // Re-enable battery saver mode activation. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 3); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// -// // 5th processed event. -// event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); -// -// // Cancel battery saver mode activation. -// event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 3); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// -// // Screen-on activation expired. -// event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// // New broadcast since the config is no longer active. -// EXPECT_EQ(broadcastCount, 4); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// -// event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); -// -// // Re-enable battery saver mode activation. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 5); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// -// // Cancel battery saver mode activation. -// event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 6); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, -// ADB_DUMP, FAST, &buffer); -// EXPECT_TRUE(buffer.size() > 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStartEndTimestamp(&reports); -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); -// -// StatsLogReport::CountMetricDataWrapper countMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).count_metrics(), &countMetrics); -// EXPECT_EQ(5, countMetrics.data_size()); -// -// auto data = countMetrics.data(0); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(1); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(2); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// // Partial bucket as metric is deactivated. -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(3); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(4); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -//} -// -//TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { -// auto config = CreateStatsdConfigWithTwoDeactivations(); -// -// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; -// -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// -// sp<UidMap> m = new UidMap(); -// sp<StatsPullerManager> pullerManager = new StatsPullerManager(); -// sp<AlarmMonitor> anomalyAlarmMonitor; -// sp<AlarmMonitor> subscriberAlarmMonitor; -// vector<int64_t> activeConfigsBroadcast; -// -// long timeBase1 = 1; -// int broadcastCount = 0; -// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, -// bucketStartTimeNs, [](const ConfigKey& key) { return true; }, -// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, -// const vector<int64_t>& activeConfigs) { -// broadcastCount++; -// EXPECT_EQ(broadcastUid, uid); -// activeConfigsBroadcast.clear(); -// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), -// activeConfigs.begin(), activeConfigs.end()); -// return true; -// }); -// -// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); -// -// EXPECT_EQ(processor.mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// auto& eventActivationMap = metricProducer->mEventActivationMap; -// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap; -// -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is -// // triggered by screen on event (tracker index 2). -// EXPECT_EQ(eventActivationMap.size(), 2u); -// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); -// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap.size(), 2u); -// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); -// EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end()); -// EXPECT_EQ(eventDeactivationMap[3].size(), 1u); -// EXPECT_EQ(eventDeactivationMap[4].size(), 1u); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// std::unique_ptr<LogEvent> event; -// -// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 0); -// -// // Activated by battery save mode. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 1); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// // First processed event. -// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); -// -// // Activated by screen on event. -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// bucketStartTimeNs + 20); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// // 2nd processed event. -// // The activation by screen_on event expires, but the one by battery save mode is still active. -// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// // No new broadcast since the config should still be active. -// EXPECT_EQ(broadcastCount, 1); -// -// // 3rd processed event. -// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); -// -// // All activations expired. -// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// // New broadcast since the config is no longer active. -// EXPECT_EQ(broadcastCount, 2); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// // Re-activate metric via screen on. -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 3); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// // 4th processed event. -// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); -// -// // Re-enable battery saver mode activation. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 3); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// // 5th processed event. -// event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); -// -// // Cancel battery saver mode and screen on activation. -// event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// // New broadcast since the config is no longer active. -// EXPECT_EQ(broadcastCount, 4); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// // Screen-on activation expired. -// event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 4); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); -// -// // Re-enable battery saver mode activation. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 5); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// // Cancel battery saver mode and screen on activation. -// event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 6); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, -// ADB_DUMP, FAST, &buffer); -// EXPECT_TRUE(buffer.size() > 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStartEndTimestamp(&reports); -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); -// -// StatsLogReport::CountMetricDataWrapper countMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).count_metrics(), &countMetrics); -// EXPECT_EQ(5, countMetrics.data_size()); -// -// auto data = countMetrics.data(0); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(1); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(2); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// // Partial bucket as metric is deactivated. -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(3); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(4); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -//} -// -//TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) { -// auto config = CreateStatsdConfigWithSameDeactivations(); -// -// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; -// -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// -// sp<UidMap> m = new UidMap(); -// sp<StatsPullerManager> pullerManager = new StatsPullerManager(); -// sp<AlarmMonitor> anomalyAlarmMonitor; -// sp<AlarmMonitor> subscriberAlarmMonitor; -// vector<int64_t> activeConfigsBroadcast; -// -// long timeBase1 = 1; -// int broadcastCount = 0; -// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, -// bucketStartTimeNs, [](const ConfigKey& key) { return true; }, -// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, -// const vector<int64_t>& activeConfigs) { -// broadcastCount++; -// EXPECT_EQ(broadcastUid, uid); -// activeConfigsBroadcast.clear(); -// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), -// activeConfigs.begin(), activeConfigs.end()); -// return true; -// }); -// -// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); -// -// EXPECT_EQ(processor.mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// auto& eventActivationMap = metricProducer->mEventActivationMap; -// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap; -// -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is -// // triggered by screen on event (tracker index 2). -// EXPECT_EQ(eventActivationMap.size(), 2u); -// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); -// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap.size(), 1u); -// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); -// EXPECT_EQ(eventDeactivationMap[3].size(), 2u); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[3][1], eventActivationMap[2]); -// EXPECT_EQ(broadcastCount, 0); -// -// std::unique_ptr<LogEvent> event; -// -// // Event that should be ignored. -// event = CreateAppCrashEvent(111, bucketStartTimeNs + 1); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 1); -// -// // Activate metric via screen on for 2 minutes. -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 1); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10); -// -// // 1st processed event. -// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); -// -// // Enable battery saver mode activation for 5 minutes. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 10); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 10); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 1); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 + 10); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10); -// -// // 2nd processed event. -// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 + 40); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 40); -// -// // Cancel battery saver mode and screen on activation. -// int64_t firstDeactivation = bucketStartTimeNs + NS_PER_SEC * 61; -// event = CreateScreenBrightnessChangedEvent(64, firstDeactivation); -// processor.OnLogEvent(event.get(), firstDeactivation); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// // New broadcast since the config is no longer active. -// EXPECT_EQ(broadcastCount, 2); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// -// // Should be ignored -// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 61 + 80); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 61 + 80); -// -// // Re-enable battery saver mode activation. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 3); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// -// // 3rd processed event. -// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80); -// -// // Cancel battery saver mode activation. -// int64_t secondDeactivation = bucketStartTimeNs + NS_PER_SEC * 60 * 13; -// event = CreateScreenBrightnessChangedEvent(140, secondDeactivation); -// processor.OnLogEvent(event.get(), secondDeactivation); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(broadcastCount, 4); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// -// // Should be ignored. -// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, -// ADB_DUMP, FAST, &buffer); -// EXPECT_TRUE(buffer.size() > 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStartEndTimestamp(&reports); -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); -// -// StatsLogReport::CountMetricDataWrapper countMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).count_metrics(), &countMetrics); -// EXPECT_EQ(3, countMetrics.data_size()); -// -// auto data = countMetrics.data(0); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(1); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(2); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(555, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// // Partial bucket as metric is deactivated. -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(secondDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos()); -//} -// -//TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { -// auto config = CreateStatsdConfigWithTwoMetricsTwoDeactivations(); -// -// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; -// -// int uid = 12345; -// int64_t cfgId = 98765; -// ConfigKey cfgKey(uid, cfgId); -// -// sp<UidMap> m = new UidMap(); -// sp<StatsPullerManager> pullerManager = new StatsPullerManager(); -// sp<AlarmMonitor> anomalyAlarmMonitor; -// sp<AlarmMonitor> subscriberAlarmMonitor; -// vector<int64_t> activeConfigsBroadcast; -// -// long timeBase1 = 1; -// int broadcastCount = 0; -// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, -// bucketStartTimeNs, [](const ConfigKey& key) { return true; }, -// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, -// const vector<int64_t>& activeConfigs) { -// broadcastCount++; -// EXPECT_EQ(broadcastUid, uid); -// activeConfigsBroadcast.clear(); -// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), -// activeConfigs.begin(), activeConfigs.end()); -// return true; -// }); -// -// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); -// -// EXPECT_EQ(processor.mMetricsManagers.size(), 1u); -// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; -// EXPECT_TRUE(metricsManager->isConfigValid()); -// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 2); -// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; -// auto& eventActivationMap = metricProducer->mEventActivationMap; -// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap; -// sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1]; -// auto& eventActivationMap2 = metricProducer2->mEventActivationMap; -// auto& eventDeactivationMap2 = metricProducer2->mEventDeactivationMap; -// -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_FALSE(metricProducer2->mIsActive); -// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is -// // triggered by screen on event (tracker index 2). -// EXPECT_EQ(eventActivationMap.size(), 2u); -// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); -// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap.size(), 2u); -// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); -// EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end()); -// EXPECT_EQ(eventDeactivationMap[3].size(), 1u); -// EXPECT_EQ(eventDeactivationMap[4].size(), 1u); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// -// EXPECT_EQ(eventActivationMap2.size(), 2u); -// EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end()); -// EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end()); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, 0); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2.size(), 2u); -// EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end()); -// EXPECT_TRUE(eventDeactivationMap2.find(4) != eventDeactivationMap2.end()); -// EXPECT_EQ(eventDeactivationMap[3].size(), 1u); -// EXPECT_EQ(eventDeactivationMap[4].size(), 1u); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// -// std::unique_ptr<LogEvent> event; -// -// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5); -// event = CreateMoveToForegroundEvent(1111, bucketStartTimeNs + 5); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_FALSE(metricProducer2->mIsActive); -// EXPECT_EQ(broadcastCount, 0); -// -// // Activated by battery save mode. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_EQ(broadcastCount, 1); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// EXPECT_TRUE(metricProducer2->mIsActive); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, 0); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// -// // First processed event. -// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); -// event = CreateMoveToForegroundEvent(2222, bucketStartTimeNs + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); -// -// // Activated by screen on event. -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// bucketStartTimeNs + 20); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// EXPECT_TRUE(metricProducer2->mIsActive); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// -// // 2nd processed event. -// // The activation by screen_on event expires, but the one by battery save mode is still active. -// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); -// event = CreateMoveToForegroundEvent(3333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// EXPECT_TRUE(metricProducer2->mIsActive); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// // No new broadcast since the config should still be active. -// EXPECT_EQ(broadcastCount, 1); -// -// // 3rd processed event. -// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); -// event = CreateMoveToForegroundEvent(4444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); -// -// // All activations expired. -// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8); -// event = CreateMoveToForegroundEvent(5555, bucketStartTimeNs + NS_PER_SEC * 60 * 8); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8); -// EXPECT_FALSE(metricsManager->isActive()); -// // New broadcast since the config is no longer active. -// EXPECT_EQ(broadcastCount, 2); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// EXPECT_FALSE(metricProducer2->mIsActive); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// -// // Re-activate metric via screen on. -// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_EQ(broadcastCount, 3); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// EXPECT_TRUE(metricProducer2->mIsActive); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// -// // 4th processed event. -// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); -// event = CreateMoveToForegroundEvent(6666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); -// -// // Re-enable battery saver mode activation. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_EQ(broadcastCount, 3); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// EXPECT_TRUE(metricProducer2->mIsActive); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// -// // 5th processed event. -// event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); -// event = CreateMoveToForegroundEvent(7777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); -// -// // Cancel battery saver mode and screen on activation. -// event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60); -// processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60); -// EXPECT_FALSE(metricsManager->isActive()); -// // New broadcast since the config is no longer active. -// EXPECT_EQ(broadcastCount, 4); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// EXPECT_FALSE(metricProducer2->mIsActive); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// -// // Screen-on activation expired. -// event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13); -// event = CreateMoveToForegroundEvent(8888, bucketStartTimeNs + NS_PER_SEC * 60 * 13); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_EQ(broadcastCount, 4); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// EXPECT_FALSE(metricProducer2->mIsActive); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// -// event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); -// event = CreateMoveToForegroundEvent(9999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); -// -// // Re-enable battery saver mode activation. -// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_TRUE(metricsManager->isActive()); -// EXPECT_EQ(broadcastCount, 5); -// EXPECT_EQ(activeConfigsBroadcast.size(), 1); -// EXPECT_EQ(activeConfigsBroadcast[0], cfgId); -// EXPECT_TRUE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// EXPECT_TRUE(metricProducer2->mIsActive); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// -// // Cancel battery saver mode and screen on activation. -// event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16); -// processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 16); -// EXPECT_FALSE(metricsManager->isActive()); -// EXPECT_EQ(broadcastCount, 6); -// EXPECT_EQ(activeConfigsBroadcast.size(), 0); -// EXPECT_FALSE(metricProducer->mIsActive); -// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); -// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); -// EXPECT_FALSE(metricProducer2->mIsActive); -// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); -// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); -// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); -// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); -// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); -// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); -// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, -// ADB_DUMP, FAST, &buffer); -// EXPECT_TRUE(buffer.size() > 0); -// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); -// backfillDimensionPath(&reports); -// backfillStartEndTimestamp(&reports); -// EXPECT_EQ(1, reports.reports_size()); -// EXPECT_EQ(2, reports.reports(0).metrics_size()); -// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); -// EXPECT_EQ(5, reports.reports(0).metrics(1).count_metrics().data_size()); -// -// StatsLogReport::CountMetricDataWrapper countMetrics; -// -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).count_metrics(), &countMetrics); -// EXPECT_EQ(5, countMetrics.data_size()); -// -// auto data = countMetrics.data(0); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(1); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(2); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// // Partial bucket as metric is deactivated. -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(3); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(4); -// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// -// countMetrics.clear_data(); -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(1).count_metrics(), &countMetrics); -// EXPECT_EQ(5, countMetrics.data_size()); -// -// data = countMetrics.data(0); -// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(2222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(1); -// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(3333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(2); -// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(4444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// // Partial bucket as metric is deactivated. -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(3); -// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(6666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -// -// data = countMetrics.data(4); -// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* uid field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_EQ(7777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); -// EXPECT_EQ(1, data.bucket_info_size()); -// EXPECT_EQ(1, data.bucket_info(0).count()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, -// data.bucket_info(0).end_bucket_elapsed_nanos()); -//} +TEST(MetricActivationE2eTest, TestCountMetric) { + auto config = CreateStatsdConfig(); + + int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; + + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + + sp<UidMap> m = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> subscriberAlarmMonitor; + vector<int64_t> activeConfigsBroadcast; + + long timeBase1 = 1; + int broadcastCount = 0; + StatsLogProcessor processor( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs, + [](const ConfigKey& key) { return true; }, + [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, + const vector<int64_t>& activeConfigs) { + broadcastCount++; + EXPECT_EQ(broadcastUid, uid); + activeConfigsBroadcast.clear(); + activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), + activeConfigs.end()); + return true; + }); + + processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); + + EXPECT_EQ(processor.mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + auto& eventActivationMap = metricProducer->mEventActivationMap; + + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + // Two activations: one is triggered by battery saver mode (tracker index 0), the other is + // triggered by screen on event (tracker index 2). + EXPECT_EQ(eventActivationMap.size(), 2u); + EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); + EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, 0); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + + std::unique_ptr<LogEvent> event; + + event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 5); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 0); + + // Activated by battery save mode. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 10); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 1); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + + // First processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); + + // Activated by screen on event. + event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 20); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + + // 2nd processed event. + // The activation by screen_on event expires, but the one by battery save mode is still active. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + // No new broadcast since the config should still be active. + EXPECT_EQ(broadcastCount, 1); + + // 3rd processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); + + // All activations expired. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + // New broadcast since the config is no longer active. + EXPECT_EQ(broadcastCount, 2); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + + // Re-activate metric via screen on. + event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10, + android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 3); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + + // 4th processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, + ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(buffer.size() > 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStartEndTimestamp(&reports); + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size()); + + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(4, countMetrics.data_size()); + + auto data = countMetrics.data(0); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(1); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(2); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + // Partial bucket as metric is deactivated. + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(3); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); +} + +TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { + auto config = CreateStatsdConfigWithOneDeactivation(); + + int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; + + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + + sp<UidMap> m = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> subscriberAlarmMonitor; + vector<int64_t> activeConfigsBroadcast; + + long timeBase1 = 1; + int broadcastCount = 0; + StatsLogProcessor processor( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs, + [](const ConfigKey& key) { return true; }, + [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, + const vector<int64_t>& activeConfigs) { + broadcastCount++; + EXPECT_EQ(broadcastUid, uid); + activeConfigsBroadcast.clear(); + activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), + activeConfigs.end()); + return true; + }); + + processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); + + EXPECT_EQ(processor.mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + auto& eventActivationMap = metricProducer->mEventActivationMap; + auto& eventDeactivationMap = metricProducer->mEventDeactivationMap; + + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + // Two activations: one is triggered by battery saver mode (tracker index 0), the other is + // triggered by screen on event (tracker index 2). + EXPECT_EQ(eventActivationMap.size(), 2u); + EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); + EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, 0); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap.size(), 1u); + EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); + EXPECT_EQ(eventDeactivationMap[3].size(), 1u); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + + std::unique_ptr<LogEvent> event; + + event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 5); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 0); + + // Activated by battery save mode. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 10); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 1); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + + // First processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); + + // Activated by screen on event. + event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 20); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + + // 2nd processed event. + // The activation by screen_on event expires, but the one by battery save mode is still active. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + // No new broadcast since the config should still be active. + EXPECT_EQ(broadcastCount, 1); + + // 3rd processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); + + // All activations expired. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + // New broadcast since the config is no longer active. + EXPECT_EQ(broadcastCount, 2); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + + // Re-activate metric via screen on. + event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10, + android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 3); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + + // 4th processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); + + // Re-enable battery saver mode activation. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 3); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + + // 5th processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); + + // Cancel battery saver mode activation. + event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 3); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + + // Screen-on activation expired. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + // New broadcast since the config is no longer active. + EXPECT_EQ(broadcastCount, 4); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); + + // Re-enable battery saver mode activation. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 5); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + + // Cancel battery saver mode activation. + event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 6); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, + ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(buffer.size() > 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStartEndTimestamp(&reports); + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); + + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(5, countMetrics.data_size()); + + auto data = countMetrics.data(0); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(1); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(2); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + // Partial bucket as metric is deactivated. + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(3); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(4); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13, + data.bucket_info(0).end_bucket_elapsed_nanos()); +} + +TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { + auto config = CreateStatsdConfigWithTwoDeactivations(); + + int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; + + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + + sp<UidMap> m = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> subscriberAlarmMonitor; + vector<int64_t> activeConfigsBroadcast; + + long timeBase1 = 1; + int broadcastCount = 0; + StatsLogProcessor processor( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs, + [](const ConfigKey& key) { return true; }, + [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, + const vector<int64_t>& activeConfigs) { + broadcastCount++; + EXPECT_EQ(broadcastUid, uid); + activeConfigsBroadcast.clear(); + activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), + activeConfigs.end()); + return true; + }); + + processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); + + EXPECT_EQ(processor.mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + auto& eventActivationMap = metricProducer->mEventActivationMap; + auto& eventDeactivationMap = metricProducer->mEventDeactivationMap; + + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + // Two activations: one is triggered by battery saver mode (tracker index 0), the other is + // triggered by screen on event (tracker index 2). + EXPECT_EQ(eventActivationMap.size(), 2u); + EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); + EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, 0); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap.size(), 2u); + EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); + EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end()); + EXPECT_EQ(eventDeactivationMap[3].size(), 1u); + EXPECT_EQ(eventDeactivationMap[4].size(), 1u); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + std::unique_ptr<LogEvent> event; + + event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 5); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 0); + + // Activated by battery save mode. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 10); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 1); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + // First processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); + + // Activated by screen on event. + event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 20); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + // 2nd processed event. + // The activation by screen_on event expires, but the one by battery save mode is still active. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + // No new broadcast since the config should still be active. + EXPECT_EQ(broadcastCount, 1); + + // 3rd processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); + + // All activations expired. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + // New broadcast since the config is no longer active. + EXPECT_EQ(broadcastCount, 2); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + // Re-activate metric via screen on. + event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10, + android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 3); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + // 4th processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); + + // Re-enable battery saver mode activation. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 3); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + // 5th processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); + + // Cancel battery saver mode and screen on activation. + event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + // New broadcast since the config is no longer active. + EXPECT_EQ(broadcastCount, 4); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + // Screen-on activation expired. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 4); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); + + // Re-enable battery saver mode activation. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 5); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + // Cancel battery saver mode and screen on activation. + event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 6); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, + ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(buffer.size() > 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStartEndTimestamp(&reports); + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); + + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(5, countMetrics.data_size()); + + auto data = countMetrics.data(0); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(1); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(2); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + // Partial bucket as metric is deactivated. + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(3); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(4); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, + data.bucket_info(0).end_bucket_elapsed_nanos()); +} + +TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) { + auto config = CreateStatsdConfigWithSameDeactivations(); + + int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; + + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + + sp<UidMap> m = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> subscriberAlarmMonitor; + vector<int64_t> activeConfigsBroadcast; + + long timeBase1 = 1; + int broadcastCount = 0; + StatsLogProcessor processor( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs, + [](const ConfigKey& key) { return true; }, + [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, + const vector<int64_t>& activeConfigs) { + broadcastCount++; + EXPECT_EQ(broadcastUid, uid); + activeConfigsBroadcast.clear(); + activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), + activeConfigs.end()); + return true; + }); + + processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); + + EXPECT_EQ(processor.mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + auto& eventActivationMap = metricProducer->mEventActivationMap; + auto& eventDeactivationMap = metricProducer->mEventDeactivationMap; + + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + // Two activations: one is triggered by battery saver mode (tracker index 0), the other is + // triggered by screen on event (tracker index 2). + EXPECT_EQ(eventActivationMap.size(), 2u); + EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); + EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, 0); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap.size(), 1u); + EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); + EXPECT_EQ(eventDeactivationMap[3].size(), 2u); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[3][1], eventActivationMap[2]); + EXPECT_EQ(broadcastCount, 0); + + std::unique_ptr<LogEvent> event; + + // Event that should be ignored. + event = CreateAppCrashEvent(bucketStartTimeNs + 1, 111); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 1); + + // Activate metric via screen on for 2 minutes. + event = CreateScreenStateChangedEvent(bucketStartTimeNs + 10, android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 10); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 1); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10); + + // 1st processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); + + // Enable battery saver mode activation for 5 minutes. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 10); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 10); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 1); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 + 10); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10); + + // 2nd processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 40, 333); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 40); + + // Cancel battery saver mode and screen on activation. + int64_t firstDeactivation = bucketStartTimeNs + NS_PER_SEC * 61; + event = CreateScreenBrightnessChangedEvent(firstDeactivation, 64); + processor.OnLogEvent(event.get(), firstDeactivation); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + // New broadcast since the config is no longer active. + EXPECT_EQ(broadcastCount, 2); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + + // Should be ignored + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 61 + 80, 444); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 61 + 80); + + // Re-enable battery saver mode activation. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 3); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + + // 3rd processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80, 555); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80); + + // Cancel battery saver mode activation. + int64_t secondDeactivation = bucketStartTimeNs + NS_PER_SEC * 60 * 13; + event = CreateScreenBrightnessChangedEvent(secondDeactivation, 140); + processor.OnLogEvent(event.get(), secondDeactivation); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(broadcastCount, 4); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + + // Should be ignored. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80, 666); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, + ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(buffer.size() > 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStartEndTimestamp(&reports); + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); + + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(3, countMetrics.data_size()); + + auto data = countMetrics.data(0); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(1); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(2); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(555, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + // Partial bucket as metric is deactivated. + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(secondDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos()); +} + +TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { + auto config = CreateStatsdConfigWithTwoMetricsTwoDeactivations(); + + int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs + int64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL; + + int uid = 12345; + int64_t cfgId = 98765; + ConfigKey cfgKey(uid, cfgId); + + sp<UidMap> m = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> subscriberAlarmMonitor; + vector<int64_t> activeConfigsBroadcast; + + long timeBase1 = 1; + int broadcastCount = 0; + StatsLogProcessor processor( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs, + [](const ConfigKey& key) { return true; }, + [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid, + const vector<int64_t>& activeConfigs) { + broadcastCount++; + EXPECT_EQ(broadcastUid, uid); + activeConfigsBroadcast.clear(); + activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), + activeConfigs.end()); + return true; + }); + + processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); + + EXPECT_EQ(processor.mMetricsManagers.size(), 1u); + sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 2); + sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0]; + auto& eventActivationMap = metricProducer->mEventActivationMap; + auto& eventDeactivationMap = metricProducer->mEventDeactivationMap; + sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1]; + auto& eventActivationMap2 = metricProducer2->mEventActivationMap; + auto& eventDeactivationMap2 = metricProducer2->mEventDeactivationMap; + + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_FALSE(metricProducer2->mIsActive); + // Two activations: one is triggered by battery saver mode (tracker index 0), the other is + // triggered by screen on event (tracker index 2). + EXPECT_EQ(eventActivationMap.size(), 2u); + EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); + EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, 0); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap.size(), 2u); + EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); + EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end()); + EXPECT_EQ(eventDeactivationMap[3].size(), 1u); + EXPECT_EQ(eventDeactivationMap[4].size(), 1u); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + + EXPECT_EQ(eventActivationMap2.size(), 2u); + EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end()); + EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end()); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, 0); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2.size(), 2u); + EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end()); + EXPECT_TRUE(eventDeactivationMap2.find(4) != eventDeactivationMap2.end()); + EXPECT_EQ(eventDeactivationMap[3].size(), 1u); + EXPECT_EQ(eventDeactivationMap[4].size(), 1u); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + + std::unique_ptr<LogEvent> event; + + event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 5); + event = CreateMoveToForegroundEvent(bucketStartTimeNs + 5, 1111); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 5); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_FALSE(metricProducer2->mIsActive); + EXPECT_EQ(broadcastCount, 0); + + // Activated by battery save mode. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 10); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_EQ(broadcastCount, 1); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + EXPECT_TRUE(metricProducer2->mIsActive); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, 0); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + + // First processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); + event = CreateMoveToForegroundEvent(bucketStartTimeNs + 15, 2222); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 15); + + // Activated by screen on event. + event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), bucketStartTimeNs + 20); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + EXPECT_TRUE(metricProducer2->mIsActive); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + + // 2nd processed event. + // The activation by screen_on event expires, but the one by battery save mode is still active. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); + event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 3333); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + EXPECT_TRUE(metricProducer2->mIsActive); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + // No new broadcast since the config should still be active. + EXPECT_EQ(broadcastCount, 1); + + // 3rd processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); + event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 4444); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25); + + // All activations expired. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8); + event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 5555); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8); + EXPECT_FALSE(metricsManager->isActive()); + // New broadcast since the config is no longer active. + EXPECT_EQ(broadcastCount, 2); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + EXPECT_FALSE(metricProducer2->mIsActive); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + + // Re-activate metric via screen on. + event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10, + android::view::DISPLAY_STATE_ON); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_EQ(broadcastCount, 3); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + EXPECT_TRUE(metricProducer2->mIsActive); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + + // 4th processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); + event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 6666); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1); + + // Re-enable battery saver mode activation. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_EQ(broadcastCount, 3); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + EXPECT_TRUE(metricProducer2->mIsActive); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + + // 5th processed event. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); + event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 7777); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40); + + // Cancel battery saver mode and screen on activation. + event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60); + EXPECT_FALSE(metricsManager->isActive()); + // New broadcast since the config is no longer active. + EXPECT_EQ(broadcastCount, 4); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + EXPECT_FALSE(metricProducer2->mIsActive); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + + // Screen-on activation expired. + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13); + event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 8888); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_EQ(broadcastCount, 4); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + EXPECT_FALSE(metricProducer2->mIsActive); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + + event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); + event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 9999); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1); + + // Re-enable battery saver mode activation. + event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_TRUE(metricsManager->isActive()); + EXPECT_EQ(broadcastCount, 5); + EXPECT_EQ(activeConfigsBroadcast.size(), 1); + EXPECT_EQ(activeConfigsBroadcast[0], cfgId); + EXPECT_TRUE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + EXPECT_TRUE(metricProducer2->mIsActive); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + + // Cancel battery saver mode and screen on activation. + event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140); + processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16); + EXPECT_FALSE(metricsManager->isActive()); + EXPECT_EQ(broadcastCount, 6); + EXPECT_EQ(activeConfigsBroadcast.size(), 0); + EXPECT_FALSE(metricProducer->mIsActive); + EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]); + EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]); + EXPECT_FALSE(metricProducer2->mIsActive); + EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); + EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); + EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]); + EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, + ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(buffer.size() > 0); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + backfillDimensionPath(&reports); + backfillStartEndTimestamp(&reports); + EXPECT_EQ(1, reports.reports_size()); + EXPECT_EQ(2, reports.reports(0).metrics_size()); + EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); + EXPECT_EQ(5, reports.reports(0).metrics(1).count_metrics().data_size()); + + StatsLogReport::CountMetricDataWrapper countMetrics; + + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(5, countMetrics.data_size()); + + auto data = countMetrics.data(0); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(1); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(2); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + // Partial bucket as metric is deactivated. + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(3); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(4); + EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + countMetrics.clear_data(); + sortMetricDataByDimensionsValue(reports.reports(0).metrics(1).count_metrics(), &countMetrics); + EXPECT_EQ(5, countMetrics.data_size()); + + data = countMetrics.data(0); + EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(2222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(1); + EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(3333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(2); + EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(4444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + // Partial bucket as metric is deactivated. + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(3); + EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(6666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, + data.bucket_info(0).end_bucket_elapsed_nanos()); + + data = countMetrics.data(4); + EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* uid field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_EQ(7777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int()); + EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11, + data.bucket_info(0).end_bucket_elapsed_nanos()); +} #else GTEST_LOG_(INFO) << "This test does nothing.\n"; diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp index 7d93fcced0ac..e8fb523deeb2 100644 --- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp @@ -97,250 +97,247 @@ StatsdConfig CreateStatsdConfig() { } } // namespace -// TODO(b/149590301): Update these tests to use new socket schema. -//// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests, -//// we should use the real API which will clear the data after dump data is called. -//TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) { -// auto config = CreateStatsdConfig(); -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// -// int appUid = 123; -// auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1); -// auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201); -// auto crashEvent3= CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101); -// -// auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51); -// auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299); -// auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001); -// -// auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16); -// auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249); -// -// auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351); -// auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2); -// -// auto screenTurnedOnEvent = -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 2); -// auto screenTurnedOffEvent = -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 200); -// auto screenTurnedOnEvent2 = -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 2 * bucketSizeNs - 100); -// -// std::vector<AttributionNodeInternal> attributions = { -// CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")}; -// auto syncOnEvent1 = -// CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50); -// auto syncOffEvent1 = -// CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300); -// auto syncOnEvent2 = -// CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000); -// -// auto moveToBackgroundEvent1 = -// CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15); -// auto moveToForegroundEvent1 = -// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250); -// -// auto moveToBackgroundEvent2 = -// CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350); -// auto moveToForegroundEvent2 = -// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1); -// -// /* -// bucket #1 bucket #2 -// -// -// | | | | | | | | | | (crashEvents) -// |-------------------------------------|-----------------------------------|--------- -// -// | | (MoveToBkground) -// -// | | (MoveToForeground) -// -// | | (SyncIsOn) -// | (SyncIsOff) -// | | (ScreenIsOn) -// | (ScreenIsOff) -// */ -// std::vector<std::unique_ptr<LogEvent>> events; -// events.push_back(std::move(crashEvent1)); -// events.push_back(std::move(crashEvent2)); -// events.push_back(std::move(crashEvent3)); -// events.push_back(std::move(crashEvent4)); -// events.push_back(std::move(crashEvent5)); -// events.push_back(std::move(crashEvent6)); -// events.push_back(std::move(crashEvent7)); -// events.push_back(std::move(crashEvent8)); -// events.push_back(std::move(crashEvent9)); -// events.push_back(std::move(crashEvent10)); -// events.push_back(std::move(screenTurnedOnEvent)); -// events.push_back(std::move(screenTurnedOffEvent)); -// events.push_back(std::move(screenTurnedOnEvent2)); -// events.push_back(std::move(syncOnEvent1)); -// events.push_back(std::move(syncOffEvent1)); -// events.push_back(std::move(syncOnEvent2)); -// events.push_back(std::move(moveToBackgroundEvent1)); -// events.push_back(std::move(moveToForegroundEvent1)); -// events.push_back(std::move(moveToBackgroundEvent2)); -// events.push_back(std::move(moveToForegroundEvent2)); -// -// 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); -// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1); -// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1); -// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1); -// auto data = reports.reports(0).metrics(0).count_metrics().data(0); -// // Validate dimension value. -// 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); -// // Uid field. -// 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(), appUid); -//} -// -//TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) { -// auto config = CreateStatsdConfig(); -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor( -// bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// -// int appUid = 123; -// auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1); -// auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201); -// auto crashEvent3 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101); -// -// auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51); -// auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299); -// auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001); -// -// auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16); -// auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249); -// -// auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351); -// auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2); -// -// auto screenTurnedOnEvent = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 2); -// auto screenTurnedOffEvent = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200); -// auto screenTurnedOnEvent2 = -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + 2 * bucketSizeNs - 100); -// -// std::vector<AttributionNodeInternal> attributions = { -// CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")}; -// auto syncOnEvent1 = CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50); -// auto syncOffEvent1 = -// CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300); -// auto syncOnEvent2 = -// CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000); -// -// auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15); -// auto moveToForegroundEvent1 = -// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250); -// -// auto moveToBackgroundEvent2 = -// CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350); -// auto moveToForegroundEvent2 = -// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1); -// -// /* -// bucket #1 bucket #2 -// -// -// | | | | | | | | | | (crashEvents) -// |-------------------------------------|-----------------------------------|--------- -// -// | | (MoveToBkground) -// -// | | (MoveToForeground) -// -// | | (SyncIsOn) -// | (SyncIsOff) -// | | (ScreenIsOn) -// | (ScreenIsOff) -// */ -// std::vector<std::unique_ptr<LogEvent>> events; -// events.push_back(std::move(crashEvent1)); -// events.push_back(std::move(crashEvent2)); -// events.push_back(std::move(crashEvent3)); -// events.push_back(std::move(crashEvent4)); -// events.push_back(std::move(crashEvent5)); -// events.push_back(std::move(crashEvent6)); -// events.push_back(std::move(crashEvent7)); -// events.push_back(std::move(crashEvent8)); -// events.push_back(std::move(crashEvent9)); -// events.push_back(std::move(crashEvent10)); -// events.push_back(std::move(screenTurnedOnEvent)); -// events.push_back(std::move(screenTurnedOffEvent)); -// events.push_back(std::move(screenTurnedOnEvent2)); -// events.push_back(std::move(syncOnEvent1)); -// events.push_back(std::move(syncOffEvent1)); -// events.push_back(std::move(syncOnEvent2)); -// events.push_back(std::move(moveToBackgroundEvent1)); -// events.push_back(std::move(moveToForegroundEvent1)); -// events.push_back(std::move(moveToBackgroundEvent2)); -// events.push_back(std::move(moveToForegroundEvent2)); -// -// 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); -// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1); -// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2); -// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1); -// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3); -// auto data = reports.reports(0).metrics(0).count_metrics().data(0); -// // Validate dimension value. -// 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); -// // Uid field. -// 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(), appUid); -//} +// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests, +// we should use the real API which will clear the data after dump data is called. +TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) { + auto config = CreateStatsdConfig(); + uint64_t bucketStartTimeNs = 10000000000; + uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + + int appUid = 123; + auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid); + auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid); + auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid); + + auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid); + auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid); + auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid); + + auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid); + auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid); + + auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid); + auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid); + + auto screenTurnedOnEvent = CreateScreenStateChangedEvent( + bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON); + auto screenTurnedOffEvent = CreateScreenStateChangedEvent( + bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF); + auto screenTurnedOnEvent2 = + CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100, + android::view::DisplayStateEnum::DISPLAY_STATE_ON); + + std::vector<int> attributionUids = {appUid, appUid + 1}; + std::vector<string> attributionTags = {"App1", "GMSCoreModule1"}; + + auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids, + attributionTags, "ReadEmail"); + auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids, + attributionTags, "ReadEmail"); + auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000, + attributionUids, attributionTags, "ReadDoc"); + + auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid); + auto moveToForegroundEvent1 = + CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid); + + auto moveToBackgroundEvent2 = + CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid); + auto moveToForegroundEvent2 = + CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid); + + /* + bucket #1 bucket #2 + + + | | | | | | | | | | (crashEvents) + |-------------------------------------|-----------------------------------|--------- + + | | (MoveToBkground) + + | | (MoveToForeground) + + | | (SyncIsOn) + | (SyncIsOff) + | | (ScreenIsOn) + | (ScreenIsOff) + */ + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back(std::move(crashEvent1)); + events.push_back(std::move(crashEvent2)); + events.push_back(std::move(crashEvent3)); + events.push_back(std::move(crashEvent4)); + events.push_back(std::move(crashEvent5)); + events.push_back(std::move(crashEvent6)); + events.push_back(std::move(crashEvent7)); + events.push_back(std::move(crashEvent8)); + events.push_back(std::move(crashEvent9)); + events.push_back(std::move(crashEvent10)); + events.push_back(std::move(screenTurnedOnEvent)); + events.push_back(std::move(screenTurnedOffEvent)); + events.push_back(std::move(screenTurnedOnEvent2)); + events.push_back(std::move(syncOnEvent1)); + events.push_back(std::move(syncOffEvent1)); + events.push_back(std::move(syncOnEvent2)); + events.push_back(std::move(moveToBackgroundEvent1)); + events.push_back(std::move(moveToForegroundEvent1)); + events.push_back(std::move(moveToBackgroundEvent2)); + events.push_back(std::move(moveToForegroundEvent2)); + + 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); + EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1); + EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1); + EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1); + auto data = reports.reports(0).metrics(0).count_metrics().data(0); + // Validate dimension value. + 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); + // Uid field. + 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(), appUid); +} + +TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) { + auto config = CreateStatsdConfig(); + uint64_t bucketStartTimeNs = 10000000000; + uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + + int appUid = 123; + auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid); + auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid); + auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid); + + auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid); + auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid); + auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid); + + auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid); + auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid); + + auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid); + auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid); + + auto screenTurnedOnEvent = CreateScreenStateChangedEvent( + bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON); + auto screenTurnedOffEvent = CreateScreenStateChangedEvent( + bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF); + auto screenTurnedOnEvent2 = + CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100, + android::view::DisplayStateEnum::DISPLAY_STATE_ON); + + std::vector<int> attributionUids = {appUid, appUid + 1}; + std::vector<string> attributionTags = {"App1", "GMSCoreModule1"}; + + auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids, + attributionTags, "ReadEmail"); + auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids, + attributionTags, "ReadEmail"); + auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000, + attributionUids, attributionTags, "ReadDoc"); + + auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid); + auto moveToForegroundEvent1 = + CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid); + + auto moveToBackgroundEvent2 = + CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid); + auto moveToForegroundEvent2 = + CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid); + + /* + bucket #1 bucket #2 + + + | | | | | | | | | | (crashEvents) + |-------------------------------------|-----------------------------------|--------- + + | | (MoveToBkground) + + | | (MoveToForeground) + + | | (SyncIsOn) + | (SyncIsOff) + | | (ScreenIsOn) + | (ScreenIsOff) + */ + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back(std::move(crashEvent1)); + events.push_back(std::move(crashEvent2)); + events.push_back(std::move(crashEvent3)); + events.push_back(std::move(crashEvent4)); + events.push_back(std::move(crashEvent5)); + events.push_back(std::move(crashEvent6)); + events.push_back(std::move(crashEvent7)); + events.push_back(std::move(crashEvent8)); + events.push_back(std::move(crashEvent9)); + events.push_back(std::move(crashEvent10)); + events.push_back(std::move(screenTurnedOnEvent)); + events.push_back(std::move(screenTurnedOffEvent)); + events.push_back(std::move(screenTurnedOnEvent2)); + events.push_back(std::move(syncOnEvent1)); + events.push_back(std::move(syncOffEvent1)); + events.push_back(std::move(syncOnEvent2)); + events.push_back(std::move(moveToBackgroundEvent1)); + events.push_back(std::move(moveToForegroundEvent1)); + events.push_back(std::move(moveToBackgroundEvent2)); + events.push_back(std::move(moveToForegroundEvent2)); + + 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); + EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1); + EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2); + EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1); + EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3); + auto data = reports.reports(0).metrics(0).count_metrics().data(0); + // Validate dimension value. + 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); + // Uid field. + 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(), appUid); +} #else GTEST_LOG_(INFO) << "This test does nothing.\n"; diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp index 9ec831b567bf..b97590761785 100644 --- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp @@ -113,96 +113,107 @@ StatsdConfig MakeGaugeMetricConfig(int64_t minTime) { } } // anonymous namespace -// TODO(b/149590301): Update this test to use new socket schema. -//TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) { -// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); -// SendConfig(service, MakeConfig()); -// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are -// // initialized with. -// -// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get()); -// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get()); -// -// ConfigMetricsReport report = GetReports(service->mProcessor, start + 3); -// // Expect no metrics since the bucket has not finished yet. -// EXPECT_EQ(1, report.metrics_size()); -// EXPECT_EQ(0, report.metrics(0).count_metrics().data_size()); -//} -// -//TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) { -// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); -// SendConfig(service, MakeConfig()); -// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are -// // initialized with. -// -// // Force the uidmap to update at timestamp 2. -// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get()); -// // This is a new installation, so there shouldn't be a split (should be same as the without -// // split case). -// service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"), -// String16("")); -// // Goes into the second bucket. -// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get()); -// -// ConfigMetricsReport report = GetReports(service->mProcessor, start + 4); -// EXPECT_EQ(1, report.metrics_size()); -// EXPECT_EQ(0, report.metrics(0).count_metrics().data_size()); -//} -// -//TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) { -// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); -// SendConfig(service, MakeConfig()); -// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are -// // initialized with. -// service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())}, -// {String16("")}); -// -// // Force the uidmap to update at timestamp 2. -// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get()); -// service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"), -// String16("")); -// // Goes into the second bucket. -// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get()); -// -// ConfigMetricsReport report = GetReports(service->mProcessor, start + 4); -// backfillStartEndTimestamp(&report); -// -// ASSERT_EQ(1, report.metrics_size()); -// ASSERT_EQ(1, report.metrics(0).count_metrics().data_size()); -// ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size()); -// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0). -// has_start_bucket_elapsed_nanos()); -// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0). -// has_end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count()); -//} -// -//TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) { -// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); -// SendConfig(service, MakeConfig()); -// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are -// // initialized with. -// service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())}, -// {String16("")}); -// -// // Force the uidmap to update at timestamp 2. -// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get()); -// service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1); -// // Goes into the second bucket. -// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get()); -// -// ConfigMetricsReport report = GetReports(service->mProcessor, start + 4); -// backfillStartEndTimestamp(&report); -// -// ASSERT_EQ(1, report.metrics_size()); -// ASSERT_EQ(1, report.metrics(0).count_metrics().data_size()); -// ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size()); -// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0). -// has_start_bucket_elapsed_nanos()); -// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0). -// has_end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count()); -//} +TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) { + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + SendConfig(service, MakeConfig()); + int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are + // initialized with. + + service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get()); + service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 2, 100).get()); + + ConfigMetricsReport report = GetReports(service->mProcessor, start + 3); + // Expect no metrics since the bucket has not finished yet. + EXPECT_EQ(1, report.metrics_size()); + EXPECT_EQ(0, report.metrics(0).count_metrics().data_size()); +} + +TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) { + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + SendConfig(service, MakeConfig()); + int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are + // initialized with. + + // Force the uidmap to update at timestamp 2. + service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get()); + // This is a new installation, so there shouldn't be a split (should be same as the without + // split case). + service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"), + String16("")); + // Goes into the second bucket. + service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get()); + + ConfigMetricsReport report = GetReports(service->mProcessor, start + 4); + EXPECT_EQ(1, report.metrics_size()); + EXPECT_EQ(0, report.metrics(0).count_metrics().data_size()); +} + +TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) { + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + SendConfig(service, MakeConfig()); + int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are + // initialized with. + service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())}, + {String16("")}); + + // Force the uidmap to update at timestamp 2. + service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get()); + service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"), + String16("")); + // Goes into the second bucket. + service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get()); + + ConfigMetricsReport report = GetReports(service->mProcessor, start + 4); + backfillStartEndTimestamp(&report); + + ASSERT_EQ(1, report.metrics_size()); + ASSERT_EQ(1, report.metrics(0).count_metrics().data_size()); + ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size()); + EXPECT_TRUE(report.metrics(0) + .count_metrics() + .data(0) + .bucket_info(0) + .has_start_bucket_elapsed_nanos()); + EXPECT_TRUE(report.metrics(0) + .count_metrics() + .data(0) + .bucket_info(0) + .has_end_bucket_elapsed_nanos()); + EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count()); +} + +TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) { + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + SendConfig(service, MakeConfig()); + int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are + // initialized with. + service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())}, + {String16("")}); + + // Force the uidmap to update at timestamp 2. + service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get()); + service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1); + // Goes into the second bucket. + service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get()); + + ConfigMetricsReport report = GetReports(service->mProcessor, start + 4); + backfillStartEndTimestamp(&report); + + ASSERT_EQ(1, report.metrics_size()); + ASSERT_EQ(1, report.metrics(0).count_metrics().data_size()); + ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size()); + EXPECT_TRUE(report.metrics(0) + .count_metrics() + .data(0) + .bucket_info(0) + .has_start_bucket_elapsed_nanos()); + EXPECT_TRUE(report.metrics(0) + .count_metrics() + .data(0) + .bucket_info(0) + .has_end_bucket_elapsed_nanos()); + EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count()); +} TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) { shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp index 99dbaf17c85c..a87bb71b12bc 100644 --- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp @@ -64,317 +64,313 @@ StatsdConfig CreateStatsdConfig(bool useCondition = true) { } // namespace -// TODO(b/149590301): Update this test to use new socket schema. -//TEST(ValueMetricE2eTest, TestPulledEvents) { -// auto config = CreateStatsdConfig(); -// int64_t baseTimeNs = getElapsedRealtimeNs(); -// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, -// SharedRefBase::make<FakeSubsystemSleepCallback>(), -// android::util::SUBSYSTEM_SLEEP_STATE); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// processor->mPullerManager->ForceClearPullerCache(); -// -// int startBucketNum = processor->mMetricsManagers.begin()->second-> -// mAllMetricProducers[0]->getCurrentBucketNum(); -// EXPECT_GT(startBucketNum, (int64_t)0); -// -// // When creating the config, the value metric producer should register the alarm at the -// // end of the current bucket. -// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); -// EXPECT_EQ(bucketSizeNs, -// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); -// int64_t& expectedPullTimeNs = -// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs); -// -// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 55); -// processor->OnLogEvent(screenOffEvent.get()); -// -// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// configAddedTimeNs + 65); -// processor->OnLogEvent(screenOnEvent.get()); -// -// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 75); -// processor->OnLogEvent(screenOffEvent.get()); -// -// // Pulling alarm arrives on time and reset the sequential pulling alarm. -// processor->informPullAlarmFired(expectedPullTimeNs + 1); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs); -// -// processor->informPullAlarmFired(expectedPullTimeNs + 1); -// -// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// configAddedTimeNs + 2 * bucketSizeNs + 15); -// processor->OnLogEvent(screenOnEvent.get()); -// -// processor->informPullAlarmFired(expectedPullTimeNs + 1); -// -// processor->informPullAlarmFired(expectedPullTimeNs + 1); -// -// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 4 * bucketSizeNs + 11); -// processor->OnLogEvent(screenOffEvent.get()); -// -// processor->informPullAlarmFired(expectedPullTimeNs + 1); -// -// processor->informPullAlarmFired(expectedPullTimeNs + 1); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, 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(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// StatsLogReport::ValueMetricDataWrapper valueMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).value_metrics(), &valueMetrics); -// EXPECT_GT((int)valueMetrics.data_size(), 1); -// -// auto data = valueMetrics.data(0); -// EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* subsystem name field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); -// // We have 4 buckets, the first one was incomplete since the condition was unknown. -// EXPECT_EQ(4, data.bucket_info_size()); -// -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, data.bucket_info(0).values_size()); -// -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, data.bucket_info(1).values_size()); -// -// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, data.bucket_info(2).values_size()); -// -// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, data.bucket_info(3).values_size()); -//} -// -//TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) { -// auto config = CreateStatsdConfig(); -// int64_t baseTimeNs = getElapsedRealtimeNs(); -// // 10 mins == 2 bucket durations. -// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000; -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, -// SharedRefBase::make<FakeSubsystemSleepCallback>(), -// android::util::SUBSYSTEM_SLEEP_STATE); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// processor->mPullerManager->ForceClearPullerCache(); -// -// int startBucketNum = processor->mMetricsManagers.begin()->second-> -// mAllMetricProducers[0]->getCurrentBucketNum(); -// EXPECT_GT(startBucketNum, (int64_t)0); -// -// // When creating the config, the value metric producer should register the alarm at the -// // end of the current bucket. -// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); -// EXPECT_EQ(bucketSizeNs, -// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); -// int64_t& expectedPullTimeNs = -// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs); -// -// // Screen off/on/off events. -// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 55); -// processor->OnLogEvent(screenOffEvent.get()); -// -// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// configAddedTimeNs + 65); -// processor->OnLogEvent(screenOnEvent.get()); -// -// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 75); -// processor->OnLogEvent(screenOffEvent.get()); -// -// // Pulling alarm arrives late by 2 buckets and 1 ns. 2 buckets late is too far away in the -// // future, data will be skipped. -// processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs); -// -// // This screen state change will start a new bucket. -// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, -// configAddedTimeNs + 4 * bucketSizeNs + 65); -// processor->OnLogEvent(screenOnEvent.get()); -// -// // The alarm is delayed but we already created a bucket thanks to the screen state condition. -// // This bucket does not have to be skipped since the alarm arrives in time for the next bucket. -// processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs); -// -// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, -// configAddedTimeNs + 6 * bucketSizeNs + 31); -// processor->OnLogEvent(screenOffEvent.get()); -// -// processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs); -// -// processor->informPullAlarmFired(expectedPullTimeNs + 1); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, 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(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// StatsLogReport::ValueMetricDataWrapper valueMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).value_metrics(), &valueMetrics); -// EXPECT_GT((int)valueMetrics.data_size(), 1); -// -// auto data = valueMetrics.data(0); -// EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* subsystem name field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); -// EXPECT_EQ(3, data.bucket_info_size()); -// -// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, data.bucket_info(0).values_size()); -// -// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, data.bucket_info(1).values_size()); -// -// EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, data.bucket_info(2).values_size()); -//} -// -//TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) { -// auto config = CreateStatsdConfig(false); -// int64_t baseTimeNs = getElapsedRealtimeNs(); -// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; -// int64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000; -// -// auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher(); -// *config.add_atom_matcher() = batterySaverStartMatcher; -// const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets. -// auto metric_activation = config.add_metric_activation(); -// metric_activation->set_metric_id(metricId); -// metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY); -// auto event_activation = metric_activation->add_event_activation(); -// event_activation->set_atom_matcher_id(batterySaverStartMatcher.id()); -// event_activation->set_ttl_seconds(ttlNs / 1000000000); -// -// ConfigKey cfgKey; -// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, -// SharedRefBase::make<FakeSubsystemSleepCallback>(), -// android::util::SUBSYSTEM_SLEEP_STATE); -// EXPECT_EQ(processor->mMetricsManagers.size(), 1u); -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); -// processor->mPullerManager->ForceClearPullerCache(); -// -// int startBucketNum = processor->mMetricsManagers.begin()->second-> -// mAllMetricProducers[0]->getCurrentBucketNum(); -// EXPECT_GT(startBucketNum, (int64_t)0); -// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); -// -// // When creating the config, the value metric producer should register the alarm at the -// // end of the current bucket. -// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); -// EXPECT_EQ(bucketSizeNs, -// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); -// int64_t& expectedPullTimeNs = -// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs); -// -// // Pulling alarm arrives on time and reset the sequential pulling alarm. -// processor->informPullAlarmFired(expectedPullTimeNs + 1); // 15 mins + 1 ns. -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs); -// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); -// -// // Activate the metric. A pull occurs here -// const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis. -// auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs); -// processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms. -// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); -// -// processor->informPullAlarmFired(expectedPullTimeNs + 1); // 20 mins + 1 ns. -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, expectedPullTimeNs); -// -// processor->informPullAlarmFired(expectedPullTimeNs + 2); // 25 mins + 2 ns. -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs); -// -// // Create random event to deactivate metric. -// auto deactivationEvent = CreateScreenBrightnessChangedEvent(50, activationNs + ttlNs + 1); -// processor->OnLogEvent(deactivationEvent.get()); -// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); -// -// processor->informPullAlarmFired(expectedPullTimeNs + 3); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, expectedPullTimeNs); -// -// processor->informPullAlarmFired(expectedPullTimeNs + 4); -// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs); -// -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, 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(1, reports.reports_size()); -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// StatsLogReport::ValueMetricDataWrapper valueMetrics; -// sortMetricDataByDimensionsValue( -// reports.reports(0).metrics(0).value_metrics(), &valueMetrics); -// EXPECT_GT((int)valueMetrics.data_size(), 0); -// -// auto data = valueMetrics.data(0); -// EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); -// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); -// EXPECT_EQ(1 /* subsystem name field */, -// data.dimensions_in_what().value_tuple().dimensions_value(0).field()); -// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); -// // We have 2 full buckets, the two surrounding the activation are dropped. -// EXPECT_EQ(2, data.bucket_info_size()); -// -// auto bucketInfo = data.bucket_info(0); -// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, bucketInfo.values_size()); -// -// bucketInfo = data.bucket_info(1); -// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos()); -// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); -// EXPECT_EQ(1, bucketInfo.values_size()); -//} +TEST(ValueMetricE2eTest, TestPulledEvents) { + auto config = CreateStatsdConfig(); + int64_t baseTimeNs = getElapsedRealtimeNs(); + int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + SharedRefBase::make<FakeSubsystemSleepCallback>(), + android::util::SUBSYSTEM_SLEEP_STATE); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + processor->mPullerManager->ForceClearPullerCache(); + + int startBucketNum = processor->mMetricsManagers.begin() + ->second->mAllMetricProducers[0] + ->getCurrentBucketNum(); + EXPECT_GT(startBucketNum, (int64_t)0); + + // When creating the config, the value metric producer should register the alarm at the + // end of the current bucket. + EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); + EXPECT_EQ(bucketSizeNs, + processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); + int64_t& expectedPullTimeNs = + processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs); + + auto screenOffEvent = + CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + auto screenOnEvent = + CreateScreenStateChangedEvent(configAddedTimeNs + 65, android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(screenOnEvent.get()); + + screenOffEvent = + CreateScreenStateChangedEvent(configAddedTimeNs + 75, android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + // Pulling alarm arrives on time and reset the sequential pulling alarm. + processor->informPullAlarmFired(expectedPullTimeNs + 1); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs); + + processor->informPullAlarmFired(expectedPullTimeNs + 1); + + screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 2 * bucketSizeNs + 15, + android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(screenOnEvent.get()); + + processor->informPullAlarmFired(expectedPullTimeNs + 1); + + processor->informPullAlarmFired(expectedPullTimeNs + 1); + + screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 4 * bucketSizeNs + 11, + android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + processor->informPullAlarmFired(expectedPullTimeNs + 1); + + processor->informPullAlarmFired(expectedPullTimeNs + 1); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, 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(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + StatsLogReport::ValueMetricDataWrapper valueMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics); + EXPECT_GT((int)valueMetrics.data_size(), 1); + + auto data = valueMetrics.data(0); + EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* subsystem name field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); + // We have 4 buckets, the first one was incomplete since the condition was unknown. + EXPECT_EQ(4, data.bucket_info_size()); + + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(1, data.bucket_info(0).values_size()); + + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); + EXPECT_EQ(1, data.bucket_info(1).values_size()); + + EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos()); + EXPECT_EQ(1, data.bucket_info(2).values_size()); + + EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos()); + EXPECT_EQ(1, data.bucket_info(3).values_size()); +} + +TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) { + auto config = CreateStatsdConfig(); + int64_t baseTimeNs = getElapsedRealtimeNs(); + // 10 mins == 2 bucket durations. + int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000; + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + SharedRefBase::make<FakeSubsystemSleepCallback>(), + android::util::SUBSYSTEM_SLEEP_STATE); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + processor->mPullerManager->ForceClearPullerCache(); + + int startBucketNum = processor->mMetricsManagers.begin() + ->second->mAllMetricProducers[0] + ->getCurrentBucketNum(); + EXPECT_GT(startBucketNum, (int64_t)0); + + // When creating the config, the value metric producer should register the alarm at the + // end of the current bucket. + EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); + EXPECT_EQ(bucketSizeNs, + processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); + int64_t& expectedPullTimeNs = + processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs); + + // Screen off/on/off events. + auto screenOffEvent = + CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + auto screenOnEvent = + CreateScreenStateChangedEvent(configAddedTimeNs + 65, android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(screenOnEvent.get()); + + screenOffEvent = + CreateScreenStateChangedEvent(configAddedTimeNs + 75, android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + // Pulling alarm arrives late by 2 buckets and 1 ns. 2 buckets late is too far away in the + // future, data will be skipped. + processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs); + + // This screen state change will start a new bucket. + screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 4 * bucketSizeNs + 65, + android::view::DISPLAY_STATE_ON); + processor->OnLogEvent(screenOnEvent.get()); + + // The alarm is delayed but we already created a bucket thanks to the screen state condition. + // This bucket does not have to be skipped since the alarm arrives in time for the next bucket. + processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs); + + screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 6 * bucketSizeNs + 31, + android::view::DISPLAY_STATE_OFF); + processor->OnLogEvent(screenOffEvent.get()); + + processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs); + + processor->informPullAlarmFired(expectedPullTimeNs + 1); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, 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(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + StatsLogReport::ValueMetricDataWrapper valueMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics); + EXPECT_GT((int)valueMetrics.data_size(), 1); + + auto data = valueMetrics.data(0); + EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* subsystem name field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); + EXPECT_EQ(3, data.bucket_info_size()); + + EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(1, data.bucket_info(0).values_size()); + + EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos()); + EXPECT_EQ(1, data.bucket_info(1).values_size()); + + EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos()); + EXPECT_EQ(1, data.bucket_info(2).values_size()); +} + +TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) { + auto config = CreateStatsdConfig(false); + int64_t baseTimeNs = getElapsedRealtimeNs(); + int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000; + + auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher(); + *config.add_atom_matcher() = batterySaverStartMatcher; + const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets. + auto metric_activation = config.add_metric_activation(); + metric_activation->set_metric_id(metricId); + metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY); + auto event_activation = metric_activation->add_event_activation(); + event_activation->set_atom_matcher_id(batterySaverStartMatcher.id()); + event_activation->set_ttl_seconds(ttlNs / 1000000000); + + ConfigKey cfgKey; + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + SharedRefBase::make<FakeSubsystemSleepCallback>(), + android::util::SUBSYSTEM_SLEEP_STATE); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); + processor->mPullerManager->ForceClearPullerCache(); + + int startBucketNum = processor->mMetricsManagers.begin() + ->second->mAllMetricProducers[0] + ->getCurrentBucketNum(); + EXPECT_GT(startBucketNum, (int64_t)0); + EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); + + // When creating the config, the value metric producer should register the alarm at the + // end of the current bucket. + EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size()); + EXPECT_EQ(bucketSizeNs, + processor->mPullerManager->mReceivers.begin()->second.front().intervalNs); + int64_t& expectedPullTimeNs = + processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs; + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs); + + // Pulling alarm arrives on time and reset the sequential pulling alarm. + processor->informPullAlarmFired(expectedPullTimeNs + 1); // 15 mins + 1 ns. + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs); + EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); + + // Activate the metric. A pull occurs here + const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis. + auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs); + processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms. + EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); + + processor->informPullAlarmFired(expectedPullTimeNs + 1); // 20 mins + 1 ns. + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, expectedPullTimeNs); + + processor->informPullAlarmFired(expectedPullTimeNs + 2); // 25 mins + 2 ns. + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs); + + // Create random event to deactivate metric. + auto deactivationEvent = CreateScreenBrightnessChangedEvent(activationNs + ttlNs + 1, 50); + processor->OnLogEvent(deactivationEvent.get()); + EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive()); + + processor->informPullAlarmFired(expectedPullTimeNs + 3); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, expectedPullTimeNs); + + processor->informPullAlarmFired(expectedPullTimeNs + 4); + EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs); + + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, 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(1, reports.reports_size()); + EXPECT_EQ(1, reports.reports(0).metrics_size()); + StatsLogReport::ValueMetricDataWrapper valueMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics); + EXPECT_GT((int)valueMetrics.data_size(), 0); + + auto data = valueMetrics.data(0); + EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); + EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); + EXPECT_EQ(1 /* subsystem name field */, + data.dimensions_in_what().value_tuple().dimensions_value(0).field()); + EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty()); + // We have 2 full buckets, the two surrounding the activation are dropped. + EXPECT_EQ(2, data.bucket_info_size()); + + auto bucketInfo = data.bucket_info(0); + EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); + EXPECT_EQ(1, bucketInfo.values_size()); + + bucketInfo = data.bucket_info(1); + EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos()); + EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos()); + EXPECT_EQ(1, bucketInfo.values_size()); +} /** * Test initialization of a simple value metric that is sliced by a state. diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp index 21092e2260d9..ddd8f956737e 100644 --- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp @@ -61,292 +61,290 @@ StatsdConfig CreateStatsdConfig(DurationMetric::AggregationType aggregationType) return config; } -std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"), - CreateAttribution(222, "GMSCoreModule1"), - CreateAttribution(222, "GMSCoreModule2")}; - -std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"), - CreateAttribution(222, "GMSCoreModule1"), - CreateAttribution(222, "GMSCoreModule2")}; - -// TODO(b/149590301): Update this helper to use new socket schema. -///* -//Events: -//Screen off is met from (200ns,1 min+500ns]. -//Acquire event for wl1 from 2ns to 1min+2ns -//Acquire event for wl2 from 1min-10ns to 2min-15ns -//*/ -//void FeedEvents(StatsdConfig config, sp<StatsLogProcessor> processor) { -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_t bucketSizeNs = -// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; -// -// auto screenTurnedOnEvent = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1); -// auto screenTurnedOffEvent = CreateScreenStateChangedEvent( -// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200); -// auto screenTurnedOnEvent2 = -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, -// bucketStartTimeNs + bucketSizeNs + 500); -// -// auto acquireEvent1 = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2); -// auto releaseEvent1 = -// CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2); -// auto acquireEvent2 = -// CreateAcquireWakelockEvent(attributions2, "wl2", bucketStartTimeNs + bucketSizeNs - 10); -// auto releaseEvent2 = CreateReleaseWakelockEvent(attributions2, "wl2", -// bucketStartTimeNs + 2 * bucketSizeNs - 15); -// -// std::vector<std::unique_ptr<LogEvent>> events; -// -// events.push_back(std::move(screenTurnedOnEvent)); -// events.push_back(std::move(screenTurnedOffEvent)); -// events.push_back(std::move(screenTurnedOnEvent2)); -// events.push_back(std::move(acquireEvent1)); -// events.push_back(std::move(acquireEvent2)); -// events.push_back(std::move(releaseEvent1)); -// events.push_back(std::move(releaseEvent2)); -// -// sortLogEventsByTimestamp(&events); -// -// for (const auto& event : events) { -// processor->OnLogEvent(event.get()); -// } -//} +std::vector<int> attributionUids1 = {111, 222, 222}; +std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1", "GMSCoreModule2"}; + +std::vector<int> attributionUids2 = {111, 222, 222}; +std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1", "GMSCoreModule2"}; + +/* +Events: +Screen off is met from (200ns,1 min+500ns]. +Acquire event for wl1 from 2ns to 1min+2ns +Acquire event for wl2 from 1min-10ns to 2min-15ns +*/ +void FeedEvents(StatsdConfig config, sp<StatsLogProcessor> processor) { + uint64_t bucketStartTimeNs = 10000000000; + uint64_t bucketSizeNs = + TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL; + + auto screenTurnedOnEvent = CreateScreenStateChangedEvent( + bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON); + auto screenTurnedOffEvent = CreateScreenStateChangedEvent( + bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF); + auto screenTurnedOnEvent2 = + CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 500, + android::view::DisplayStateEnum::DISPLAY_STATE_ON); + + auto acquireEvent1 = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1, + attributionTags1, "wl1"); + auto releaseEvent1 = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, + attributionUids1, attributionTags1, "wl1"); + auto acquireEvent2 = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 10, + attributionUids2, attributionTags2, "wl2"); + auto releaseEvent2 = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 15, + attributionUids2, attributionTags2, "wl2"); + + std::vector<std::unique_ptr<LogEvent>> events; + + events.push_back(std::move(screenTurnedOnEvent)); + events.push_back(std::move(screenTurnedOffEvent)); + events.push_back(std::move(screenTurnedOnEvent2)); + events.push_back(std::move(acquireEvent1)); + events.push_back(std::move(acquireEvent2)); + events.push_back(std::move(releaseEvent1)); + events.push_back(std::move(releaseEvent2)); + + sortLogEventsByTimestamp(&events); + + for (const auto& event : events) { + processor->OnLogEvent(event.get()); + } +} } // namespace -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) { -// ConfigKey cfgKey; -// auto config = CreateStatsdConfig(DurationMetric::SUM); -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_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()); -// FeedEvents(config, processor); -// vector<uint8_t> buffer; -// ConfigMetricsReportList reports; -// 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); -// // Only 1 dimension output. The tag dimension in the predicate has been aggregated. -// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); -// -// auto data = reports.reports(0).metrics(0).duration_metrics().data(0); -// // Validate dimension value. -// ValidateAttributionUidDimension(data.dimensions_in_what(), -// android::util::WAKELOCK_STATE_CHANGED, 111); -// // Validate bucket info. -// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1); -// data = reports.reports(0).metrics(0).duration_metrics().data(0); -// // The wakelock holding interval starts from the screen off event and to the end of the 1st -// // bucket. -// EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200); -//} -// -//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) { -// ConfigKey cfgKey; -// auto config = CreateStatsdConfig(DurationMetric::SUM); -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_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()); -// FeedEvents(config, processor); -// vector<uint8_t> buffer; -// ConfigMetricsReportList reports; -// 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); -// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); -// // Dump the report after the end of 2nd bucket. -// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2); -// auto data = reports.reports(0).metrics(0).duration_metrics().data(0); -// // Validate dimension value. -// ValidateAttributionUidDimension(data.dimensions_in_what(), -// android::util::WAKELOCK_STATE_CHANGED, 111); -// // Two output buckets. -// // The wakelock holding interval in the 1st bucket starts from the screen off event and to -// // the end of the 1st bucket. -// EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), -// bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200)); -// // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and -// // ends at the second screen on event. -// EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL); -//} -//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) { -// ConfigKey cfgKey; -// auto config = CreateStatsdConfig(DurationMetric::SUM); -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_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()); -// FeedEvents(config, processor); -// vector<uint8_t> buffer; -// ConfigMetricsReportList reports; -// -// std::vector<std::unique_ptr<LogEvent>> events; -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 2 * bucketSizeNs + 90)); -// events.push_back(CreateAcquireWakelockEvent(attributions1, "wl3", -// bucketStartTimeNs + 2 * bucketSizeNs + 100)); -// events.push_back(CreateReleaseWakelockEvent(attributions1, "wl3", -// bucketStartTimeNs + 5 * bucketSizeNs + 100)); -// sortLogEventsByTimestamp(&events); -// for (const auto& event : events) { -// processor->OnLogEvent(event.get()); -// } -// -// processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * 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); -// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); -// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6); -// auto data = reports.reports(0).metrics(0).duration_metrics().data(0); -// ValidateAttributionUidDimension(data.dimensions_in_what(), -// android::util::WAKELOCK_STATE_CHANGED, 111); -// // The last wakelock holding spans 4 buckets. -// EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100); -// EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs); -// EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs); -// EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL); -//} -// -//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) { -// ConfigKey cfgKey; -// auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE); -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_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()); -// FeedEvents(config, processor); -// 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); -// -// // When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as -// // one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by -// // itself. -// EXPECT_EQ(1, reports.reports(0).metrics_size()); -// EXPECT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size()); -//} -// -//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) { -// ConfigKey cfgKey; -// auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE); -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_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()); -// FeedEvents(config, processor); -// 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); -// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); -// // Dump the report after the end of 2nd bucket. One dimension with one bucket. -// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1); -// auto data = reports.reports(0).metrics(0).duration_metrics().data(0); -// // Validate dimension value. -// ValidateAttributionUidDimension(data.dimensions_in_what(), -// android::util::WAKELOCK_STATE_CHANGED, 111); -// // The max is acquire event for wl1 to screen off start. -// EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200); -//} -// -//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) { -// ConfigKey cfgKey; -// auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE); -// uint64_t bucketStartTimeNs = 10000000000; -// uint64_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()); -// FeedEvents(config, processor); -// ConfigMetricsReportList reports; -// vector<uint8_t> buffer; -// -// std::vector<std::unique_ptr<LogEvent>> events; -// events.push_back( -// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, -// bucketStartTimeNs + 2 * bucketSizeNs + 90)); -// events.push_back(CreateAcquireWakelockEvent(attributions1, "wl3", -// bucketStartTimeNs + 2 * bucketSizeNs + 100)); -// events.push_back(CreateReleaseWakelockEvent(attributions1, "wl3", -// bucketStartTimeNs + 5 * bucketSizeNs + 100)); -// sortLogEventsByTimestamp(&events); -// for (const auto& event : events) { -// processor->OnLogEvent(event.get()); -// } -// -// processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * 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); -// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); -// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2); -// auto data = reports.reports(0).metrics(0).duration_metrics().data(0); -// ValidateAttributionUidDimension(data.dimensions_in_what(), -// android::util::WAKELOCK_STATE_CHANGED, 111); -// // The last wakelock holding spans 4 buckets. -// EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs); -// EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(), -// bucketStartTimeNs + 5 * bucketSizeNs); -// EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(), -// bucketStartTimeNs + 6 * bucketSizeNs); -//} +TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) { + ConfigKey cfgKey; + auto config = CreateStatsdConfig(DurationMetric::SUM); + uint64_t bucketStartTimeNs = 10000000000; + uint64_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()); + FeedEvents(config, processor); + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + 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); + // Only 1 dimension output. The tag dimension in the predicate has been aggregated. + EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); + + auto data = reports.reports(0).metrics(0).duration_metrics().data(0); + // Validate dimension value. + ValidateAttributionUidDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, 111); + // Validate bucket info. + EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1); + data = reports.reports(0).metrics(0).duration_metrics().data(0); + // The wakelock holding interval starts from the screen off event and to the end of the 1st + // bucket. + EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200); +} + +TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) { + ConfigKey cfgKey; + auto config = CreateStatsdConfig(DurationMetric::SUM); + uint64_t bucketStartTimeNs = 10000000000; + uint64_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()); + FeedEvents(config, processor); + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + 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); + EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); + // Dump the report after the end of 2nd bucket. + EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2); + auto data = reports.reports(0).metrics(0).duration_metrics().data(0); + // Validate dimension value. + ValidateAttributionUidDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, 111); + // Two output buckets. + // The wakelock holding interval in the 1st bucket starts from the screen off event and to + // the end of the 1st bucket. + EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), + bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200)); + // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and + // ends at the second screen on event. + EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL); +} + +TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) { + ConfigKey cfgKey; + auto config = CreateStatsdConfig(DurationMetric::SUM); + uint64_t bucketStartTimeNs = 10000000000; + uint64_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()); + FeedEvents(config, processor); + vector<uint8_t> buffer; + ConfigMetricsReportList reports; + + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back( + CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 90, + android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, + attributionUids1, attributionTags1, "wl3")); + events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs + 100, + attributionUids1, attributionTags1, "wl3")); + sortLogEventsByTimestamp(&events); + for (const auto& event : events) { + processor->OnLogEvent(event.get()); + } + + processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * 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); + EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); + EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6); + auto data = reports.reports(0).metrics(0).duration_metrics().data(0); + ValidateAttributionUidDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, 111); + // The last wakelock holding spans 4 buckets. + EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100); + EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs); + EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs); + EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL); +} + +TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) { + ConfigKey cfgKey; + auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE); + uint64_t bucketStartTimeNs = 10000000000; + uint64_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()); + FeedEvents(config, processor); + 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); + + // When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as + // one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by + // itself. + EXPECT_EQ(1, reports.reports(0).metrics_size()); + EXPECT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size()); +} + +TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) { + ConfigKey cfgKey; + auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE); + uint64_t bucketStartTimeNs = 10000000000; + uint64_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()); + FeedEvents(config, processor); + 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); + EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); + // Dump the report after the end of 2nd bucket. One dimension with one bucket. + EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1); + auto data = reports.reports(0).metrics(0).duration_metrics().data(0); + // Validate dimension value. + ValidateAttributionUidDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, 111); + // The max is acquire event for wl1 to screen off start. + EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200); +} + +TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) { + ConfigKey cfgKey; + auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE); + uint64_t bucketStartTimeNs = 10000000000; + uint64_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()); + FeedEvents(config, processor); + ConfigMetricsReportList reports; + vector<uint8_t> buffer; + + std::vector<std::unique_ptr<LogEvent>> events; + events.push_back( + CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 90, + android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); + events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, + attributionUids1, attributionTags1, "wl3")); + events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs + 100, + attributionUids1, attributionTags1, "wl3")); + sortLogEventsByTimestamp(&events); + for (const auto& event : events) { + processor->OnLogEvent(event.get()); + } + + processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * 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); + EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1); + EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2); + auto data = reports.reports(0).metrics(0).duration_metrics().data(0); + ValidateAttributionUidDimension(data.dimensions_in_what(), + android::util::WAKELOCK_STATE_CHANGED, 111); + // The last wakelock holding spans 4 buckets. + EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs); + EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(), + bucketStartTimeNs + 5 * bucketSizeNs); + EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(), + bucketStartTimeNs + 6 * bucketSizeNs); +} #else GTEST_LOG_(INFO) << "This test does nothing.\n"; diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp index c0b4f436530f..e8200d5c7f52 100644 --- a/cmds/statsd/tests/external/StatsPuller_test.cpp +++ b/cmds/statsd/tests/external/StatsPuller_test.cpp @@ -15,11 +15,14 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <stdio.h> + #include <chrono> #include <thread> #include <vector> + #include "../metrics/metrics_test_helper.h" #include "src/stats_log_util.h" +#include "stats_event.h" #include "tests/statsd_test_util.h" #ifdef __ANDROID__ @@ -57,13 +60,22 @@ private: FakePuller puller; -// TODO(b/149590301): Update this helper to use new socket schema. -//shared_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) { -// shared_ptr<LogEvent> event = make_shared<LogEvent>(pullTagId, eventTimeNs); -// event->write(value); -// event->init(); -// return event; -//} +std::unique_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, pullTagId); + AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs); + + AStatsEvent_writeInt64(statsEvent, value); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} class StatsPullerTest : public ::testing::Test { public: @@ -80,149 +92,148 @@ public: } // Anonymous namespace. -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST_F(StatsPullerTest, PullSuccess) { -// pullData.push_back(createSimpleEvent(1111L, 33)); -// -// pullSuccess = true; -// -// vector<std::shared_ptr<LogEvent>> dataHolder; -// EXPECT_TRUE(puller.Pull(&dataHolder)); -// EXPECT_EQ(1, dataHolder.size()); -// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); -// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs()); -// EXPECT_EQ(1, dataHolder[0]->size()); -// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value); -// -// sleep_for(std::chrono::seconds(1)); -// -// pullData.clear(); -// pullData.push_back(createSimpleEvent(2222L, 44)); -// -// pullSuccess = true; -// -// EXPECT_TRUE(puller.Pull(&dataHolder)); -// EXPECT_EQ(1, dataHolder.size()); -// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); -// EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs()); -// EXPECT_EQ(1, dataHolder[0]->size()); -// EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value); -//} -// -//TEST_F(StatsPullerTest, PullFailAfterSuccess) { -// pullData.push_back(createSimpleEvent(1111L, 33)); -// -// pullSuccess = true; -// -// vector<std::shared_ptr<LogEvent>> dataHolder; -// EXPECT_TRUE(puller.Pull(&dataHolder)); -// EXPECT_EQ(1, dataHolder.size()); -// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); -// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs()); -// EXPECT_EQ(1, dataHolder[0]->size()); -// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value); -// -// sleep_for(std::chrono::seconds(1)); -// -// pullData.clear(); -// pullData.push_back(createSimpleEvent(2222L, 44)); -// -// pullSuccess = false; -// dataHolder.clear(); -// EXPECT_FALSE(puller.Pull(&dataHolder)); -// EXPECT_EQ(0, dataHolder.size()); -// -// pullSuccess = true; -// dataHolder.clear(); -// EXPECT_FALSE(puller.Pull(&dataHolder)); -// EXPECT_EQ(0, dataHolder.size()); -//} -// -//// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown -//TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) { -// pullData.push_back(createSimpleEvent(1111L, 33)); -// pullSuccess = true; -// // timeout is 0.5 -// pullDelayNs = (long)(0.8 * NS_PER_SEC); -// -// vector<std::shared_ptr<LogEvent>> dataHolder; -// EXPECT_FALSE(puller.Pull(&dataHolder)); -// EXPECT_EQ(0, dataHolder.size()); -// -// pullData.clear(); -// pullData.push_back(createSimpleEvent(2222L, 44)); -// -// pullSuccess = true; -// dataHolder.clear(); -// EXPECT_FALSE(puller.Pull(&dataHolder)); -// EXPECT_EQ(0, dataHolder.size()); -//} -// -//TEST_F(StatsPullerTest, PullFail) { -// pullData.push_back(createSimpleEvent(1111L, 33)); -// -// pullSuccess = false; -// -// vector<std::shared_ptr<LogEvent>> dataHolder; -// EXPECT_FALSE(puller.Pull(&dataHolder)); -// EXPECT_EQ(0, dataHolder.size()); -//} -// -//TEST_F(StatsPullerTest, PullTakeTooLong) { -// pullData.push_back(createSimpleEvent(1111L, 33)); -// -// pullSuccess = true; -// pullDelayNs = NS_PER_SEC; -// -// vector<std::shared_ptr<LogEvent>> dataHolder; -// EXPECT_FALSE(puller.Pull(&dataHolder)); -// EXPECT_EQ(0, dataHolder.size()); -//} -// -//TEST_F(StatsPullerTest, PullTooFast) { -// pullData.push_back(createSimpleEvent(1111L, 33)); -// -// pullSuccess = true; -// -// vector<std::shared_ptr<LogEvent>> dataHolder; -// EXPECT_TRUE(puller.Pull(&dataHolder)); -// EXPECT_EQ(1, dataHolder.size()); -// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); -// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs()); -// EXPECT_EQ(1, dataHolder[0]->size()); -// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value); -// -// pullData.clear(); -// pullData.push_back(createSimpleEvent(2222L, 44)); -// -// pullSuccess = true; -// -// dataHolder.clear(); -// EXPECT_TRUE(puller.Pull(&dataHolder)); -// EXPECT_EQ(1, dataHolder.size()); -// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); -// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs()); -// EXPECT_EQ(1, dataHolder[0]->size()); -// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value); -//} -// -//TEST_F(StatsPullerTest, PullFailsAndTooFast) { -// pullData.push_back(createSimpleEvent(1111L, 33)); -// -// pullSuccess = false; -// -// vector<std::shared_ptr<LogEvent>> dataHolder; -// EXPECT_FALSE(puller.Pull(&dataHolder)); -// EXPECT_EQ(0, dataHolder.size()); -// -// pullData.clear(); -// pullData.push_back(createSimpleEvent(2222L, 44)); -// -// pullSuccess = true; -// -// EXPECT_FALSE(puller.Pull(&dataHolder)); -// EXPECT_EQ(0, dataHolder.size()); -//} +TEST_F(StatsPullerTest, PullSuccess) { + pullData.push_back(createSimpleEvent(1111L, 33)); + + pullSuccess = true; + + vector<std::shared_ptr<LogEvent>> dataHolder; + EXPECT_TRUE(puller.Pull(&dataHolder)); + EXPECT_EQ(1, dataHolder.size()); + EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); + EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs()); + EXPECT_EQ(1, dataHolder[0]->size()); + EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value); + + sleep_for(std::chrono::seconds(1)); + + pullData.clear(); + pullData.push_back(createSimpleEvent(2222L, 44)); + + pullSuccess = true; + + EXPECT_TRUE(puller.Pull(&dataHolder)); + EXPECT_EQ(1, dataHolder.size()); + EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); + EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs()); + EXPECT_EQ(1, dataHolder[0]->size()); + EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value); +} + +TEST_F(StatsPullerTest, PullFailAfterSuccess) { + pullData.push_back(createSimpleEvent(1111L, 33)); + + pullSuccess = true; + + vector<std::shared_ptr<LogEvent>> dataHolder; + EXPECT_TRUE(puller.Pull(&dataHolder)); + EXPECT_EQ(1, dataHolder.size()); + EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); + EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs()); + EXPECT_EQ(1, dataHolder[0]->size()); + EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value); + + sleep_for(std::chrono::seconds(1)); + + pullData.clear(); + pullData.push_back(createSimpleEvent(2222L, 44)); + + pullSuccess = false; + dataHolder.clear(); + EXPECT_FALSE(puller.Pull(&dataHolder)); + EXPECT_EQ(0, dataHolder.size()); + + pullSuccess = true; + dataHolder.clear(); + EXPECT_FALSE(puller.Pull(&dataHolder)); + EXPECT_EQ(0, dataHolder.size()); +} + +// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown +TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) { + pullData.push_back(createSimpleEvent(1111L, 33)); + pullSuccess = true; + // timeout is 0.5 + pullDelayNs = (long)(0.8 * NS_PER_SEC); + + vector<std::shared_ptr<LogEvent>> dataHolder; + EXPECT_FALSE(puller.Pull(&dataHolder)); + EXPECT_EQ(0, dataHolder.size()); + + pullData.clear(); + pullData.push_back(createSimpleEvent(2222L, 44)); + + pullSuccess = true; + dataHolder.clear(); + EXPECT_FALSE(puller.Pull(&dataHolder)); + EXPECT_EQ(0, dataHolder.size()); +} + +TEST_F(StatsPullerTest, PullFail) { + pullData.push_back(createSimpleEvent(1111L, 33)); + + pullSuccess = false; + + vector<std::shared_ptr<LogEvent>> dataHolder; + EXPECT_FALSE(puller.Pull(&dataHolder)); + EXPECT_EQ(0, dataHolder.size()); +} + +TEST_F(StatsPullerTest, PullTakeTooLong) { + pullData.push_back(createSimpleEvent(1111L, 33)); + + pullSuccess = true; + pullDelayNs = NS_PER_SEC; + + vector<std::shared_ptr<LogEvent>> dataHolder; + EXPECT_FALSE(puller.Pull(&dataHolder)); + EXPECT_EQ(0, dataHolder.size()); +} + +TEST_F(StatsPullerTest, PullTooFast) { + pullData.push_back(createSimpleEvent(1111L, 33)); + + pullSuccess = true; + + vector<std::shared_ptr<LogEvent>> dataHolder; + EXPECT_TRUE(puller.Pull(&dataHolder)); + EXPECT_EQ(1, dataHolder.size()); + EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); + EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs()); + EXPECT_EQ(1, dataHolder[0]->size()); + EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value); + + pullData.clear(); + pullData.push_back(createSimpleEvent(2222L, 44)); + + pullSuccess = true; + + dataHolder.clear(); + EXPECT_TRUE(puller.Pull(&dataHolder)); + EXPECT_EQ(1, dataHolder.size()); + EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId()); + EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs()); + EXPECT_EQ(1, dataHolder[0]->size()); + EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value); +} + +TEST_F(StatsPullerTest, PullFailsAndTooFast) { + pullData.push_back(createSimpleEvent(1111L, 33)); + + pullSuccess = false; + + vector<std::shared_ptr<LogEvent>> dataHolder; + EXPECT_FALSE(puller.Pull(&dataHolder)); + EXPECT_EQ(0, dataHolder.size()); + + pullData.clear(); + pullData.push_back(createSimpleEvent(2222L, 44)); + + pullSuccess = true; + + EXPECT_FALSE(puller.Pull(&dataHolder)); + EXPECT_EQ(0, dataHolder.size()); +} } // namespace statsd } // namespace os diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp index 81590a2d1e43..f21954f20d08 100644 --- a/cmds/statsd/tests/external/puller_util_test.cpp +++ b/cmds/statsd/tests/external/puller_util_test.cpp @@ -13,12 +13,16 @@ // limitations under the License. #include "external/puller_util.h" + #include <gmock/gmock.h> #include <gtest/gtest.h> #include <stdio.h> + #include <vector> -#include "statslog.h" + #include "../metrics/metrics_test_helper.h" +#include "stats_event.h" +#include "statslog.h" #ifdef __ANDROID__ @@ -58,212 +62,187 @@ void extractIntoVector(vector<shared_ptr<LogEvent>> events, ret.push_back(vec); } } + +std::shared_ptr<LogEvent> makeUidLogEvent(uint64_t timestampNs, int uid, int data1, int data2) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, uidAtomTagId); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, uid); + AStatsEvent_writeInt32(statsEvent, data1); + AStatsEvent_writeInt32(statsEvent, data2); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::shared_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +std::shared_ptr<LogEvent> makeNonUidAtomLogEvent(uint64_t timestampNs, int data1) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, nonUidAtomTagId); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, data1); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::shared_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + } // anonymous namespace -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST(puller_util, MergeNoDimension) { -// vector<shared_ptr<LogEvent>> inputData; -// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// // 30->22->31 -// event->write(isolatedUid); -// event->write(hostNonAdditiveData); -// event->write(isolatedAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// // 20->22->21 -// event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// event->write(hostUid); -// event->write(hostNonAdditiveData); -// event->write(hostAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); -// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)) -// .WillRepeatedly(Return(hostUid)); -// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) -// .WillRepeatedly(ReturnArg<0>()); -// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); -// -// vector<vector<int>> actual; -// extractIntoVector(inputData, actual); -// vector<int> expectedV1 = {20, 22, 52}; -// EXPECT_EQ(1, (int)actual.size()); -// EXPECT_THAT(actual, Contains(expectedV1)); -//} -// -//TEST(puller_util, MergeWithDimension) { -// vector<shared_ptr<LogEvent>> inputData; -// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// // 30->32->31 -// event->write(isolatedUid); -// event->write(isolatedNonAdditiveData); -// event->write(isolatedAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// // 20->32->21 -// event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// event->write(hostUid); -// event->write(isolatedNonAdditiveData); -// event->write(hostAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// // 20->22->21 -// event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// event->write(hostUid); -// event->write(hostNonAdditiveData); -// event->write(hostAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); -// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)) -// .WillRepeatedly(Return(hostUid)); -// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) -// .WillRepeatedly(ReturnArg<0>()); -// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); -// -// vector<vector<int>> actual; -// extractIntoVector(inputData, actual); -// vector<int> expectedV1 = {20, 22, 21}; -// vector<int> expectedV2 = {20, 32, 52}; -// EXPECT_EQ(2, (int)actual.size()); -// EXPECT_THAT(actual, Contains(expectedV1)); -// EXPECT_THAT(actual, Contains(expectedV2)); -//} -// -//TEST(puller_util, NoMergeHostUidOnly) { -// vector<shared_ptr<LogEvent>> inputData; -// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// // 20->32->31 -// event->write(hostUid); -// event->write(isolatedNonAdditiveData); -// event->write(isolatedAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// // 20->22->21 -// event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// event->write(hostUid); -// event->write(hostNonAdditiveData); -// event->write(hostAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); -// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)) -// .WillRepeatedly(Return(hostUid)); -// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) -// .WillRepeatedly(ReturnArg<0>()); -// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); -// -// // 20->32->31 -// // 20->22->21 -// vector<vector<int>> actual; -// extractIntoVector(inputData, actual); -// vector<int> expectedV1 = {20, 32, 31}; -// vector<int> expectedV2 = {20, 22, 21}; -// EXPECT_EQ(2, (int)actual.size()); -// EXPECT_THAT(actual, Contains(expectedV1)); -// EXPECT_THAT(actual, Contains(expectedV2)); -//} -// -//TEST(puller_util, IsolatedUidOnly) { -// vector<shared_ptr<LogEvent>> inputData; -// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// // 30->32->31 -// event->write(hostUid); -// event->write(isolatedNonAdditiveData); -// event->write(isolatedAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// // 30->22->21 -// event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// event->write(hostUid); -// event->write(hostNonAdditiveData); -// event->write(hostAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); -// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)) -// .WillRepeatedly(Return(hostUid)); -// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) -// .WillRepeatedly(ReturnArg<0>()); -// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); -// -// // 20->32->31 -// // 20->22->21 -// vector<vector<int>> actual; -// extractIntoVector(inputData, actual); -// vector<int> expectedV1 = {20, 32, 31}; -// vector<int> expectedV2 = {20, 22, 21}; -// EXPECT_EQ(2, (int)actual.size()); -// EXPECT_THAT(actual, Contains(expectedV1)); -// EXPECT_THAT(actual, Contains(expectedV2)); -//} -// -//TEST(puller_util, MultipleIsolatedUidToOneHostUid) { -// vector<shared_ptr<LogEvent>> inputData; -// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// // 30->32->31 -// event->write(isolatedUid); -// event->write(isolatedNonAdditiveData); -// event->write(isolatedAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// // 31->32->21 -// event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// event->write(isolatedUid + 1); -// event->write(isolatedNonAdditiveData); -// event->write(hostAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// // 20->32->21 -// event = make_shared<LogEvent>(uidAtomTagId, timestamp); -// event->write(hostUid); -// event->write(isolatedNonAdditiveData); -// event->write(hostAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); -// EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid)); -// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); -// -// vector<vector<int>> actual; -// extractIntoVector(inputData, actual); -// vector<int> expectedV1 = {20, 32, 73}; -// EXPECT_EQ(1, (int)actual.size()); -// EXPECT_THAT(actual, Contains(expectedV1)); -//} -// -//TEST(puller_util, NoNeedToMerge) { -// vector<shared_ptr<LogEvent>> inputData; -// shared_ptr<LogEvent> event = -// make_shared<LogEvent>(nonUidAtomTagId, timestamp); -// // 32 -// event->write(isolatedNonAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// event = make_shared<LogEvent>(nonUidAtomTagId, timestamp); -// // 22 -// event->write(hostNonAdditiveData); -// event->init(); -// inputData.push_back(event); -// -// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); -// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId, {} /*no additive fields*/); -// -// EXPECT_EQ(2, (int)inputData.size()); -//} +TEST(puller_util, MergeNoDimension) { + vector<shared_ptr<LogEvent>> inputData; + + // 30->22->31 + inputData.push_back( + makeUidLogEvent(timestamp, isolatedUid, hostNonAdditiveData, isolatedAdditiveData)); + + // 20->22->21 + inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData)); + + sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); + EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid)); + EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>()); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); + + vector<vector<int>> actual; + extractIntoVector(inputData, actual); + vector<int> expectedV1 = {20, 22, 52}; + EXPECT_EQ(1, (int)actual.size()); + EXPECT_THAT(actual, Contains(expectedV1)); +} + +TEST(puller_util, MergeWithDimension) { + vector<shared_ptr<LogEvent>> inputData; + + // 30->32->31 + inputData.push_back( + makeUidLogEvent(timestamp, isolatedUid, isolatedNonAdditiveData, isolatedAdditiveData)); + + // 20->32->21 + inputData.push_back( + makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, hostAdditiveData)); + + // 20->22->21 + inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData)); + + sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); + EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid)); + EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>()); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); + + vector<vector<int>> actual; + extractIntoVector(inputData, actual); + vector<int> expectedV1 = {20, 22, 21}; + vector<int> expectedV2 = {20, 32, 52}; + EXPECT_EQ(2, (int)actual.size()); + EXPECT_THAT(actual, Contains(expectedV1)); + EXPECT_THAT(actual, Contains(expectedV2)); +} + +TEST(puller_util, NoMergeHostUidOnly) { + vector<shared_ptr<LogEvent>> inputData; + + // 20->32->31 + inputData.push_back( + makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, isolatedAdditiveData)); + + // 20->22->21 + inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData)); + + sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); + EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid)); + EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>()); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); + + // 20->32->31 + // 20->22->21 + vector<vector<int>> actual; + extractIntoVector(inputData, actual); + vector<int> expectedV1 = {20, 32, 31}; + vector<int> expectedV2 = {20, 22, 21}; + EXPECT_EQ(2, (int)actual.size()); + EXPECT_THAT(actual, Contains(expectedV1)); + EXPECT_THAT(actual, Contains(expectedV2)); +} + +TEST(puller_util, IsolatedUidOnly) { + vector<shared_ptr<LogEvent>> inputData; + + // 30->32->31 + inputData.push_back( + makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, isolatedAdditiveData)); + + // 30->22->21 + inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData)); + + sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); + EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid)); + EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>()); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); + + // 20->32->31 + // 20->22->21 + vector<vector<int>> actual; + extractIntoVector(inputData, actual); + vector<int> expectedV1 = {20, 32, 31}; + vector<int> expectedV2 = {20, 22, 21}; + EXPECT_EQ(2, (int)actual.size()); + EXPECT_THAT(actual, Contains(expectedV1)); + EXPECT_THAT(actual, Contains(expectedV2)); +} + +TEST(puller_util, MultipleIsolatedUidToOneHostUid) { + vector<shared_ptr<LogEvent>> inputData; + + // 30->32->31 + inputData.push_back( + makeUidLogEvent(timestamp, isolatedUid, isolatedNonAdditiveData, isolatedAdditiveData)); + + // 31->32->21 + inputData.push_back( + makeUidLogEvent(timestamp, isolatedUid + 1, isolatedNonAdditiveData, hostAdditiveData)); + + // 20->32->21 + inputData.push_back( + makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, hostAdditiveData)); + + sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); + EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid)); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); + + vector<vector<int>> actual; + extractIntoVector(inputData, actual); + vector<int> expectedV1 = {20, 32, 73}; + EXPECT_EQ(1, (int)actual.size()); + EXPECT_THAT(actual, Contains(expectedV1)); +} + +TEST(puller_util, NoNeedToMerge) { + vector<shared_ptr<LogEvent>> inputData; + + // 32 + inputData.push_back(makeNonUidAtomLogEvent(timestamp, isolatedNonAdditiveData)); + + // 22 + inputData.push_back(makeNonUidAtomLogEvent(timestamp, hostNonAdditiveData)); + + sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId, {} /*no additive fields*/); + + EXPECT_EQ(2, (int)inputData.size()); +} } // namespace statsd } // namespace os diff --git a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp index c4407f48d978..6dc041f9fb6e 100644 --- a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp +++ b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp @@ -42,7 +42,7 @@ std::unique_ptr<LogEvent> makeLogEvent(uint64_t timestampNs) { size_t size; uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/-1, /*pid=*/-1); + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); logEvent->parseBuffer(buf, size); AStatsEvent_release(statsEvent); return logEvent; diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp index b8826780c7b9..d55996cb1b7a 100644 --- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp @@ -13,16 +13,19 @@ // limitations under the License. #include "src/metrics/CountMetricProducer.h" -#include "src/stats_log_util.h" -#include "metrics_test_helper.h" -#include "tests/statsd_test_util.h" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <math.h> #include <stdio.h> + #include <vector> +#include "metrics_test_helper.h" +#include "src/stats_log_util.h" +#include "stats_event.h" +#include "tests/statsd_test_util.h" + using namespace testing; using android::sp; using std::set; @@ -37,366 +40,392 @@ namespace statsd { const ConfigKey kConfigKey(0, 12345); -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST(CountMetricProducerTest, TestFirstBucket) { -// CountMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 5, -// 600 * NS_PER_SEC + NS_PER_SEC / 2); -// EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs); -// EXPECT_EQ(10, countProducer.mCurrentBucketNum); -// EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs()); -//} -// -//TEST(CountMetricProducerTest, TestNonDimensionalEvents) { -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; -// int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; -// int tagId = 1; -// -// CountMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// -// LogEvent event1(tagId, bucketStartTimeNs + 1); -// event1.init(); -// LogEvent event2(tagId, bucketStartTimeNs + 2); -// event2.init(); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -// bucketStartTimeNs, bucketStartTimeNs); -// -// // 2 events in bucket 1. -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); -// -// // Flushes at event #2. -// countProducer.flushIfNeededLocked(bucketStartTimeNs + 2); -// EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); -// -// // Flushes. -// countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1); -// EXPECT_EQ(1UL, countProducer.mPastBuckets.size()); -// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != -// countProducer.mPastBuckets.end()); -// const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(1UL, buckets.size()); -// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs); -// EXPECT_EQ(2LL, buckets[0].mCount); -// -// // 1 matched event happens in bucket 2. -// LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2); -// event3.init(); -// -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); -// countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1); -// EXPECT_EQ(1UL, countProducer.mPastBuckets.size()); -// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != -// countProducer.mPastBuckets.end()); -// EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1]; -// EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs); -// EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs); -// EXPECT_EQ(1LL, bucketInfo2.mCount); -// -// // nothing happens in bucket 3. we should not record anything for bucket 3. -// countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1); -// EXPECT_EQ(1UL, countProducer.mPastBuckets.size()); -// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != -// countProducer.mPastBuckets.end()); -// const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(2UL, buckets3.size()); -//} -// -//TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) { -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// -// CountMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// metric.set_condition(StringToId("SCREEN_ON")); -// -// LogEvent event1(1, bucketStartTimeNs + 1); -// event1.init(); -// -// LogEvent event2(1, bucketStartTimeNs + 10); -// event2.init(); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs, -// bucketStartTimeNs); -// -// countProducer.onConditionChanged(true, bucketStartTimeNs); -// countProducer.onMatchedLogEvent(1 /*matcher index*/, event1); -// EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); -// -// countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2); -// // Upon this match event, the matched event1 is flushed. -// countProducer.onMatchedLogEvent(1 /*matcher index*/, event2); -// EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); -// -// countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1); -// EXPECT_EQ(1UL, countProducer.mPastBuckets.size()); -// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != -// countProducer.mPastBuckets.end()); -// { -// const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(1UL, buckets.size()); -// const auto& bucketInfo = buckets[0]; -// EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs); -// EXPECT_EQ(1LL, bucketInfo.mCount); -// } -//} -// -//TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) { -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// -// int tagId = 1; -// int conditionTagId = 2; -// -// CountMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON")); -// MetricConditionLink* link = metric.add_links(); -// link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID")); -// buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what()); -// buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition()); -// -// LogEvent event1(tagId, bucketStartTimeNs + 1); -// event1.write("111"); // uid -// event1.init(); -// ConditionKey key1; -// key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = -// {getMockedDimensionKey(conditionTagId, 2, "111")}; -// -// LogEvent event2(tagId, bucketStartTimeNs + 10); -// event2.write("222"); // uid -// event2.init(); -// ConditionKey key2; -// 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(_, key2, _)).WillOnce(Return(ConditionState::kTrue)); -// -// CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard, -// bucketStartTimeNs, bucketStartTimeNs); -// -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); -// countProducer.flushIfNeededLocked(bucketStartTimeNs + 1); -// EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); -// -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); -// countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1); -// EXPECT_EQ(1UL, countProducer.mPastBuckets.size()); -// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != -// countProducer.mPastBuckets.end()); -// const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(1UL, buckets.size()); -// const auto& bucketInfo = buckets[0]; -// EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs); -// EXPECT_EQ(1LL, bucketInfo.mCount); -//} -// -//TEST(CountMetricProducerTest, TestEventWithAppUpgrade) { -// sp<AlarmMonitor> alarmMonitor; -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; -// -// int tagId = 1; -// int conditionTagId = 2; -// -// CountMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// Alert alert; -// alert.set_num_buckets(3); -// alert.set_trigger_if_sum_gt(2); -// LogEvent event1(tagId, bucketStartTimeNs + 1); -// event1.write("111"); // uid -// event1.init(); -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard, -// bucketStartTimeNs, bucketStartTimeNs); -// -// sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor); -// EXPECT_TRUE(anomalyTracker != nullptr); -// -// // Bucket is flushed yet. -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); -// EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); -// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); -// -// // App upgrade forces bucket flush. -// // Check that there's a past bucket and the bucket end is not adjusted. -// countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); -// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ((long long)bucketStartTimeNs, -// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs); -// EXPECT_EQ((long long)eventUpgradeTimeNs, -// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs); -// EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs); -// // Anomaly tracker only contains full buckets. -// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); -// -// int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs(); -// // Next event occurs in same bucket as partial bucket created. -// LogEvent event2(tagId, bucketStartTimeNs + 59 * NS_PER_SEC + 10); -// event2.write("222"); // uid -// event2.init(); -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); -// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs); -// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); -// -// // Third event in following bucket. -// LogEvent event3(tagId, bucketStartTimeNs + 62 * NS_PER_SEC + 10); -// event3.write("333"); // uid -// event3.init(); -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); -// EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs); -// EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); -//} -// -//TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) { -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC; -// -// int tagId = 1; -// int conditionTagId = 2; -// -// CountMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// LogEvent event1(tagId, bucketStartTimeNs + 1); -// event1.write("111"); // uid -// event1.init(); -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard, -// bucketStartTimeNs, bucketStartTimeNs); -// -// // Bucket is flushed yet. -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); -// EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); -// -// // App upgrade forces bucket flush. -// // Check that there's a past bucket and the bucket end is not adjusted. -// countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); -// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ((int64_t)bucketStartTimeNs, -// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, -// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs); -// EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs); -// -// // Next event occurs in same bucket as partial bucket created. -// LogEvent event2(tagId, bucketStartTimeNs + 70 * NS_PER_SEC + 10); -// event2.write("222"); // uid -// event2.init(); -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); -// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// -// // Third event in following bucket. -// LogEvent event3(tagId, bucketStartTimeNs + 121 * NS_PER_SEC + 10); -// event3.write("333"); // uid -// event3.init(); -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); -// EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ((int64_t)eventUpgradeTimeNs, -// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, -// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs); -//} -// -//TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) { -// sp<AlarmMonitor> alarmMonitor; -// Alert alert; -// alert.set_id(11); -// alert.set_metric_id(1); -// alert.set_trigger_if_sum_gt(2); -// alert.set_num_buckets(2); -// const int32_t refPeriodSec = 1; -// alert.set_refractory_period_secs(refPeriodSec); -// -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; -// int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; -// -// CountMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -// bucketStartTimeNs, bucketStartTimeNs); -// -// sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor); -// -// int tagId = 1; -// LogEvent event1(tagId, bucketStartTimeNs + 1); -// event1.init(); -// LogEvent event2(tagId, bucketStartTimeNs + 2); -// event2.init(); -// LogEvent event3(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1); -// event3.init(); -// LogEvent event4(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1); -// event4.init(); -// LogEvent event5(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2); -// event5.init(); -// LogEvent event6(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3); -// event6.init(); -// LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC); -// event7.init(); -// -// // Two events in bucket #0. -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); -// -// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size()); -// EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second); -// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U); -// -// // One event in bucket #2. No alarm as bucket #0 is trashed out. -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); -// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size()); -// EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second); -// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U); -// -// // Two events in bucket #3. -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4); -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5); -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6); -// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size()); -// EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second); -// // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6 -// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), -// std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); -// -// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7); -// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size()); -// EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second); -// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), -// std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); -//} +namespace { + +void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, atomId); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); +} + +void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId, string uid) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, atomId); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeString(statsEvent, uid.c_str()); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); +} + +} // namespace + +TEST(CountMetricProducerTest, TestFirstBucket) { + CountMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 5, + 600 * NS_PER_SEC + NS_PER_SEC / 2); + EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs); + EXPECT_EQ(10, countProducer.mCurrentBucketNum); + EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs()); +} + +TEST(CountMetricProducerTest, TestNonDimensionalEvents) { + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; + int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; + int tagId = 1; + + CountMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + bucketStartTimeNs, bucketStartTimeNs); + + // 2 events in bucket 1. + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, bucketStartTimeNs + 1, tagId); + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, bucketStartTimeNs + 2, tagId); + + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); + + // Flushes at event #2. + countProducer.flushIfNeededLocked(bucketStartTimeNs + 2); + EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); + + // Flushes. + countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1); + EXPECT_EQ(1UL, countProducer.mPastBuckets.size()); + EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != + countProducer.mPastBuckets.end()); + const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(1UL, buckets.size()); + EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs); + EXPECT_EQ(2LL, buckets[0].mCount); + + // 1 matched event happens in bucket 2. + LogEvent event3(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 2, tagId); + + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); + + countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1); + EXPECT_EQ(1UL, countProducer.mPastBuckets.size()); + EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != + countProducer.mPastBuckets.end()); + EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1]; + EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs); + EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs); + EXPECT_EQ(1LL, bucketInfo2.mCount); + + // nothing happens in bucket 3. we should not record anything for bucket 3. + countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1); + EXPECT_EQ(1UL, countProducer.mPastBuckets.size()); + EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != + countProducer.mPastBuckets.end()); + const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(2UL, buckets3.size()); +} + +TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) { + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + + CountMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + metric.set_condition(StringToId("SCREEN_ON")); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs, + bucketStartTimeNs); + + countProducer.onConditionChanged(true, bucketStartTimeNs); + + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, bucketStartTimeNs + 1, /*atomId=*/1); + countProducer.onMatchedLogEvent(1 /*matcher index*/, event1); + + EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); + + countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2); + + // Upon this match event, the matched event1 is flushed. + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, bucketStartTimeNs + 10, /*atomId=*/1); + countProducer.onMatchedLogEvent(1 /*matcher index*/, event2); + EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); + + countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1); + EXPECT_EQ(1UL, countProducer.mPastBuckets.size()); + EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != + countProducer.mPastBuckets.end()); + + const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(1UL, buckets.size()); + const auto& bucketInfo = buckets[0]; + EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs); + EXPECT_EQ(1LL, bucketInfo.mCount); +} + +TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) { + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + + int tagId = 1; + int conditionTagId = 2; + + CountMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON")); + MetricConditionLink* link = metric.add_links(); + link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID")); + buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what()); + buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition()); + + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111"); + + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, bucketStartTimeNs + 10, tagId, /*uid=*/"222"); + + ConditionKey key1; + key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = { + getMockedDimensionKey(conditionTagId, 2, "111")}; + + ConditionKey key2; + 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(_, key2, _)).WillOnce(Return(ConditionState::kTrue)); + + CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard, + bucketStartTimeNs, bucketStartTimeNs); + + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); + countProducer.flushIfNeededLocked(bucketStartTimeNs + 1); + EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); + + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); + countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1); + EXPECT_EQ(1UL, countProducer.mPastBuckets.size()); + EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != + countProducer.mPastBuckets.end()); + const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(1UL, buckets.size()); + const auto& bucketInfo = buckets[0]; + EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs); + EXPECT_EQ(1LL, bucketInfo.mCount); +} + +TEST(CountMetricProducerTest, TestEventWithAppUpgrade) { + sp<AlarmMonitor> alarmMonitor; + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; + + int tagId = 1; + int conditionTagId = 2; + + CountMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + Alert alert; + alert.set_num_buckets(3); + alert.set_trigger_if_sum_gt(2); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard, + bucketStartTimeNs, bucketStartTimeNs); + + sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor); + EXPECT_TRUE(anomalyTracker != nullptr); + + // Bucket is flushed yet. + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111"); + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); + EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); + EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); + + // App upgrade forces bucket flush. + // Check that there's a past bucket and the bucket end is not adjusted. + countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ((long long)bucketStartTimeNs, + countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs); + EXPECT_EQ((long long)eventUpgradeTimeNs, + countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs); + EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs); + // Anomaly tracker only contains full buckets. + EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); + + int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs(); + // Next event occurs in same bucket as partial bucket created. + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, bucketStartTimeNs + 59 * NS_PER_SEC + 10, tagId, /*uid=*/"222"); + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); + EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs); + EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); + + // Third event in following bucket. + LogEvent event3(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event3, bucketStartTimeNs + 62 * NS_PER_SEC + 10, tagId, /*uid=*/"333"); + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); + EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs); + EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); +} + +TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) { + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC; + + int tagId = 1; + int conditionTagId = 2; + + CountMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard, + bucketStartTimeNs, bucketStartTimeNs); + + // Bucket is flushed yet. + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111"); + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); + EXPECT_EQ(0UL, countProducer.mPastBuckets.size()); + + // App upgrade forces bucket flush. + // Check that there's a past bucket and the bucket end is not adjusted. + countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ((int64_t)bucketStartTimeNs, + countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, + countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs); + EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs); + + // Next event occurs in same bucket as partial bucket created. + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, bucketStartTimeNs + 70 * NS_PER_SEC + 10, tagId, /*uid=*/"222"); + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); + EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + + // Third event in following bucket. + LogEvent event3(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event3, bucketStartTimeNs + 121 * NS_PER_SEC + 10, tagId, /*uid=*/"333"); + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); + EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ((int64_t)eventUpgradeTimeNs, + countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, + countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs); +} + +TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) { + sp<AlarmMonitor> alarmMonitor; + Alert alert; + alert.set_id(11); + alert.set_metric_id(1); + alert.set_trigger_if_sum_gt(2); + alert.set_num_buckets(2); + const int32_t refPeriodSec = 1; + alert.set_refractory_period_secs(refPeriodSec); + + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; + int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; + + CountMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + bucketStartTimeNs, bucketStartTimeNs); + + sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor); + + int tagId = 1; + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, bucketStartTimeNs + 1, tagId); + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, bucketStartTimeNs + 2, tagId); + LogEvent event3(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event3, bucketStartTimeNs + 2 * bucketSizeNs + 1, tagId); + LogEvent event4(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event4, bucketStartTimeNs + 3 * bucketSizeNs + 1, tagId); + LogEvent event5(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event5, bucketStartTimeNs + 3 * bucketSizeNs + 2, tagId); + LogEvent event6(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event6, bucketStartTimeNs + 3 * bucketSizeNs + 3, tagId); + LogEvent event7(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event7, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC, tagId); + + // Two events in bucket #0. + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); + + EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size()); + EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second); + EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U); + + // One event in bucket #2. No alarm as bucket #0 is trashed out. + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); + EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size()); + EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second); + EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U); + + // Two events in bucket #3. + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4); + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5); + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6); + EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size()); + EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second); + // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6 + EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), + std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); + + countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7); + EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size()); + EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second); + EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), + std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); +} TEST(CountMetricProducerTest, TestOneWeekTimeUnit) { CountMetric metric; diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp index 66613749aaea..6143dc0dc5d1 100644 --- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp @@ -13,17 +13,20 @@ // limitations under the License. #include "src/metrics/DurationMetricProducer.h" -#include "src/stats_log_util.h" -#include "metrics_test_helper.h" -#include "src/condition/ConditionWizard.h" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <stdio.h> + #include <set> #include <unordered_map> #include <vector> +#include "metrics_test_helper.h" +#include "src/condition/ConditionWizard.h" +#include "src/stats_log_util.h" +#include "stats_event.h" + using namespace android::os::statsd; using namespace testing; using android::sp; @@ -39,6 +42,22 @@ namespace statsd { const ConfigKey kConfigKey(0, 12345); +namespace { + +void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, atomId); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); +} + +} // namespace + TEST(DurationMetricTrackerTest, TestFirstBucket) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); DurationMetric metric; @@ -56,383 +75,386 @@ TEST(DurationMetricTrackerTest, TestFirstBucket) { EXPECT_EQ(660000000005, durationProducer.getCurrentBucketEndTimeNs()); } -// TODO(b/149590301): Update these to use new socket schema. -//TEST(DurationMetricTrackerTest, TestNoCondition) { -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// -// DurationMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// metric.set_aggregation_type(DurationMetric_AggregationType_SUM); -// -// int tagId = 1; -// LogEvent event1(tagId, bucketStartTimeNs + 1); -// event1.init(); -// LogEvent event2(tagId, bucketStartTimeNs + bucketSizeNs + 2); -// event2.init(); -// -// FieldMatcher dimensions; -// DurationMetricProducer durationProducer( -// kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */, -// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs); -// -// durationProducer.onMatchedLogEvent(1 /* start index*/, event1); -// durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); -// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1); -// EXPECT_EQ(1UL, durationProducer.mPastBuckets.size()); -// EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != -// durationProducer.mPastBuckets.end()); -// const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(2UL, buckets.size()); -// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs); -// EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs); -// EXPECT_EQ(2LL, buckets[1].mDuration); -//} -// -//TEST(DurationMetricTrackerTest, TestNonSlicedCondition) { -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// -// DurationMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// metric.set_aggregation_type(DurationMetric_AggregationType_SUM); -// -// int tagId = 1; -// LogEvent event1(tagId, bucketStartTimeNs + 1); -// event1.init(); -// LogEvent event2(tagId, bucketStartTimeNs + 2); -// event2.init(); -// LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1); -// event3.init(); -// LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3); -// event4.init(); -// -// FieldMatcher dimensions; -// DurationMetricProducer durationProducer( -// kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */, -// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs); -// durationProducer.mCondition = ConditionState::kFalse; -// -// EXPECT_FALSE(durationProducer.mCondition); -// EXPECT_FALSE(durationProducer.isConditionSliced()); -// -// durationProducer.onMatchedLogEvent(1 /* start index*/, event1); -// durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); -// durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1); -// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); -// -// durationProducer.onMatchedLogEvent(1 /* start index*/, event3); -// durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2); -// durationProducer.onMatchedLogEvent(2 /* stop index*/, event4); -// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1); -// EXPECT_EQ(1UL, durationProducer.mPastBuckets.size()); -// EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != -// durationProducer.mPastBuckets.end()); -// const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(1UL, buckets2.size()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs); -// EXPECT_EQ(1LL, buckets2[0].mDuration); -//} -// -//TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) { -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// -// DurationMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// metric.set_aggregation_type(DurationMetric_AggregationType_SUM); -// -// int tagId = 1; -// LogEvent event1(tagId, bucketStartTimeNs + 1); -// event1.init(); -// LogEvent event2(tagId, bucketStartTimeNs + 2); -// event2.init(); -// LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1); -// event3.init(); -// LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3); -// event4.init(); -// -// FieldMatcher dimensions; -// DurationMetricProducer durationProducer( -// kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */, -// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs); -// -// EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition); -// EXPECT_FALSE(durationProducer.isConditionSliced()); -// -// durationProducer.onMatchedLogEvent(1 /* start index*/, event1); -// durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); -// durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1); -// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); -// -// durationProducer.onMatchedLogEvent(1 /* start index*/, event3); -// durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2); -// durationProducer.onMatchedLogEvent(2 /* stop index*/, event4); -// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1); -// EXPECT_EQ(1UL, durationProducer.mPastBuckets.size()); -// const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(1UL, buckets2.size()); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs); -// EXPECT_EQ(1LL, buckets2[0].mDuration); -//} -// -//TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) { -// /** -// * The duration starts from the first bucket, through the two partial buckets (10-70sec), -// * another bucket, and ends at the beginning of the next full bucket. -// * Expected buckets: -// * - [10,25]: 14 secs -// * - [25,70]: All 45 secs -// * - [70,130]: All 60 secs -// * - [130, 210]: Only 5 secs (event ended at 135sec) -// */ -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; -// int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC; -// int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC; -// -// int tagId = 1; -// -// DurationMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// metric.set_aggregation_type(DurationMetric_AggregationType_SUM); -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// FieldMatcher dimensions; -// DurationMetricProducer durationProducer( -// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */, -// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs); -// -// LogEvent start_event(tagId, startTimeNs); -// start_event.init(); -// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event); -// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); -// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs); -// -// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); -// EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// std::vector<DurationBucket> buckets = -// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs); -// EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketEndNs); -// EXPECT_EQ(eventUpgradeTimeNs - startTimeNs, buckets[0].mDuration); -// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs); -// -// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket. -// LogEvent end_event(tagId, endTimeNs); -// end_event.init(); -// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event); -// buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(3UL, buckets.size()); -// EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - eventUpgradeTimeNs, buckets[1].mDuration); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs); -// EXPECT_EQ(bucketSizeNs, buckets[2].mDuration); -//} -// -//TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) { -// /** -// * Expected buckets (start at 11s, upgrade at 75s, end at 135s): -// * - [10,70]: 59 secs -// * - [70,75]: 5 sec -// * - [75,130]: 55 secs -// */ -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC; -// int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC; -// int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC; -// -// int tagId = 1; -// -// DurationMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// metric.set_aggregation_type(DurationMetric_AggregationType_SUM); -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// FieldMatcher dimensions; -// DurationMetricProducer durationProducer( -// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */, -// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs); -// -// LogEvent start_event(tagId, startTimeNs); -// start_event.init(); -// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event); -// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); -// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs); -// -// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); -// EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// std::vector<DurationBucket> buckets = -// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration); -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs); -// EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketEndNs); -// EXPECT_EQ(eventUpgradeTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration); -// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs); -// -// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket. -// LogEvent end_event(tagId, endTimeNs); -// end_event.init(); -// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event); -// buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(3UL, buckets.size()); -// EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - eventUpgradeTimeNs, buckets[2].mDuration); -//} -// -//TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) { -// sp<AlarmMonitor> alarmMonitor; -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; -// int64_t startTimeNs = bucketStartTimeNs + 1; -// int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC; -// -// int tagId = 1; -// -// // Setup metric with alert. -// DurationMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// metric.set_aggregation_type(DurationMetric_AggregationType_SUM); -// Alert alert; -// alert.set_num_buckets(3); -// alert.set_trigger_if_sum_gt(2); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// FieldMatcher dimensions; -// DurationMetricProducer durationProducer( -// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */, -// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs); -// -// sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor); -// EXPECT_TRUE(anomalyTracker != nullptr); -// -// LogEvent start_event(tagId, startTimeNs); -// start_event.init(); -// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event); -// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); -// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket. -// LogEvent end_event(tagId, endTimeNs); -// end_event.init(); -// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event); -// -// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, -// anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); -//} -// -//TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) { -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; -// int64_t startTimeNs = bucketStartTimeNs + 1; -// int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC; -// -// int tagId = 1; -// -// DurationMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE); -// LogEvent event1(tagId, startTimeNs); -// event1.write("111"); // uid -// event1.init(); -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// FieldMatcher dimensions; -// DurationMetricProducer durationProducer( -// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */, -// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs); -// -// LogEvent start_event(tagId, startTimeNs); -// start_event.init(); -// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event); -// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); -// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs); -// -// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); -// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs); -// -// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket. -// LogEvent end_event(tagId, endTimeNs); -// end_event.init(); -// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event); -// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// -// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1); -// std::vector<DurationBucket> buckets = -// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(1UL, buckets.size()); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs); -// EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration); -//} -// -//TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) { -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; -// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC; -// int64_t startTimeNs = bucketStartTimeNs + 1; -// int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC; -// -// int tagId = 1; -// -// DurationMetric metric; -// metric.set_id(1); -// metric.set_bucket(ONE_MINUTE); -// metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE); -// LogEvent event1(tagId, startTimeNs); -// event1.write("111"); // uid -// event1.init(); -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// FieldMatcher dimensions; -// DurationMetricProducer durationProducer( -// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */, -// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs); -// -// LogEvent start_event(tagId, startTimeNs); -// start_event.init(); -// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event); -// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); -// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs); -// -// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); -// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs); -// -// // Stop occurs in the same partial bucket as created for the app upgrade. -// LogEvent end_event(tagId, endTimeNs); -// end_event.init(); -// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event); -// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs); -// -// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1); -// std::vector<DurationBucket> buckets = -// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; -// EXPECT_EQ(1UL, buckets.size()); -// EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketStartNs); -// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs); -// EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration); -//} +TEST(DurationMetricTrackerTest, TestNoCondition) { + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + + DurationMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + metric.set_aggregation_type(DurationMetric_AggregationType_SUM); + + int tagId = 1; + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, bucketStartTimeNs + 1, tagId); + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, bucketStartTimeNs + bucketSizeNs + 2, tagId); + + FieldMatcher dimensions; + DurationMetricProducer durationProducer(kConfigKey, metric, -1 /*no condition*/, + 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, + dimensions, bucketStartTimeNs, bucketStartTimeNs); + + durationProducer.onMatchedLogEvent(1 /* start index*/, event1); + durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); + durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1); + EXPECT_EQ(1UL, durationProducer.mPastBuckets.size()); + EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != + durationProducer.mPastBuckets.end()); + const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(2UL, buckets.size()); + EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs); + EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs); + EXPECT_EQ(2LL, buckets[1].mDuration); +} + +TEST(DurationMetricTrackerTest, TestNonSlicedCondition) { + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + + DurationMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + metric.set_aggregation_type(DurationMetric_AggregationType_SUM); + + int tagId = 1; + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, bucketStartTimeNs + 1, tagId); + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, bucketStartTimeNs + 2, tagId); + LogEvent event3(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId); + LogEvent event4(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId); + + FieldMatcher dimensions; + DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */, + 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, + dimensions, bucketStartTimeNs, bucketStartTimeNs); + durationProducer.mCondition = ConditionState::kFalse; + + EXPECT_FALSE(durationProducer.mCondition); + EXPECT_FALSE(durationProducer.isConditionSliced()); + + durationProducer.onMatchedLogEvent(1 /* start index*/, event1); + durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); + durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1); + EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); + + durationProducer.onMatchedLogEvent(1 /* start index*/, event3); + durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2); + durationProducer.onMatchedLogEvent(2 /* stop index*/, event4); + durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1); + EXPECT_EQ(1UL, durationProducer.mPastBuckets.size()); + EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) != + durationProducer.mPastBuckets.end()); + const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(1UL, buckets2.size()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs); + EXPECT_EQ(1LL, buckets2[0].mDuration); +} + +TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) { + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + + DurationMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + metric.set_aggregation_type(DurationMetric_AggregationType_SUM); + + int tagId = 1; + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, bucketStartTimeNs + 1, tagId); + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, bucketStartTimeNs + 2, tagId); + LogEvent event3(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId); + LogEvent event4(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId); + + FieldMatcher dimensions; + DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */, + 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, + dimensions, bucketStartTimeNs, bucketStartTimeNs); + + EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition); + EXPECT_FALSE(durationProducer.isConditionSliced()); + + durationProducer.onMatchedLogEvent(1 /* start index*/, event1); + durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); + durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1); + EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); + + durationProducer.onMatchedLogEvent(1 /* start index*/, event3); + durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2); + durationProducer.onMatchedLogEvent(2 /* stop index*/, event4); + durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1); + EXPECT_EQ(1UL, durationProducer.mPastBuckets.size()); + const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(1UL, buckets2.size()); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs); + EXPECT_EQ(1LL, buckets2[0].mDuration); +} + +TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) { + /** + * The duration starts from the first bucket, through the two partial buckets (10-70sec), + * another bucket, and ends at the beginning of the next full bucket. + * Expected buckets: + * - [10,25]: 14 secs + * - [25,70]: All 45 secs + * - [70,130]: All 60 secs + * - [130, 210]: Only 5 secs (event ended at 135sec) + */ + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; + int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC; + int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC; + + int tagId = 1; + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, startTimeNs, tagId); + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, endTimeNs, tagId); + + DurationMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + metric.set_aggregation_type(DurationMetric_AggregationType_SUM); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + FieldMatcher dimensions; + DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, + 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, + dimensions, bucketStartTimeNs, bucketStartTimeNs); + + durationProducer.onMatchedLogEvent(1 /* start index*/, event1); + EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); + EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs); + + durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + std::vector<DurationBucket> buckets = + durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs); + EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketEndNs); + EXPECT_EQ(eventUpgradeTimeNs - startTimeNs, buckets[0].mDuration); + EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs); + + // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket. + durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); + buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(3UL, buckets.size()); + EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - eventUpgradeTimeNs, buckets[1].mDuration); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs); + EXPECT_EQ(bucketSizeNs, buckets[2].mDuration); +} + +TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) { + /** + * Expected buckets (start at 11s, upgrade at 75s, end at 135s): + * - [10,70]: 59 secs + * - [70,75]: 5 sec + * - [75,130]: 55 secs + */ + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC; + int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC; + int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC; + + int tagId = 1; + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, startTimeNs, tagId); + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, endTimeNs, tagId); + + DurationMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + metric.set_aggregation_type(DurationMetric_AggregationType_SUM); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + FieldMatcher dimensions; + DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, + 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, + dimensions, bucketStartTimeNs, bucketStartTimeNs); + + durationProducer.onMatchedLogEvent(1 /* start index*/, event1); + EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); + EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs); + + durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + std::vector<DurationBucket> buckets = + durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs); + EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketEndNs); + EXPECT_EQ(eventUpgradeTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration); + EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs); + + // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket. + durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); + buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(3UL, buckets.size()); + EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - eventUpgradeTimeNs, buckets[2].mDuration); +} + +TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) { + sp<AlarmMonitor> alarmMonitor; + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; + int64_t startTimeNs = bucketStartTimeNs + 1; + int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC; + + int tagId = 1; + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, startTimeNs, tagId); + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, endTimeNs, tagId); + + // Setup metric with alert. + DurationMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + metric.set_aggregation_type(DurationMetric_AggregationType_SUM); + Alert alert; + alert.set_num_buckets(3); + alert.set_trigger_if_sum_gt(2); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + FieldMatcher dimensions; + DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, + 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, + dimensions, bucketStartTimeNs, bucketStartTimeNs); + + sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor); + EXPECT_TRUE(anomalyTracker != nullptr); + + durationProducer.onMatchedLogEvent(1 /* start index*/, event1); + durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + + // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket. + durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); + EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, + anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); +} + +TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) { + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; + int64_t startTimeNs = bucketStartTimeNs + 1; + int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC; + + int tagId = 1; + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, startTimeNs, tagId); + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, endTimeNs, tagId); + + DurationMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + FieldMatcher dimensions; + DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, + 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, + dimensions, bucketStartTimeNs, bucketStartTimeNs); + + durationProducer.onMatchedLogEvent(1 /* start index*/, event1); + EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); + EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs); + + durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs); + + // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket. + durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); + EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + + durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1); + std::vector<DurationBucket> buckets = + durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(1UL, buckets.size()); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs); + EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration); +} + +TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) { + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; + int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC; + int64_t startTimeNs = bucketStartTimeNs + 1; + int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC; + + int tagId = 1; + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, startTimeNs, tagId); + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, endTimeNs, tagId); + + DurationMetric metric; + metric.set_id(1); + metric.set_bucket(ONE_MINUTE); + metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + FieldMatcher dimensions; + DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, + 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, + dimensions, bucketStartTimeNs, bucketStartTimeNs); + + durationProducer.onMatchedLogEvent(1 /* start index*/, event1); + EXPECT_EQ(0UL, durationProducer.mPastBuckets.size()); + EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs); + + durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs); + + // Stop occurs in the same partial bucket as created for the app upgrade. + durationProducer.onMatchedLogEvent(2 /* stop index*/, event2); + EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs); + + durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1); + std::vector<DurationBucket> buckets = + durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY]; + EXPECT_EQ(1UL, buckets.size()); + EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketStartNs); + EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs); + EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration); +} } // namespace statsd } // namespace os diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index d416f1395727..e2eee032a43b 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -410,40 +410,75 @@ FieldMatcher CreateDimensions(const int atomId, const std::vector<int>& fields) return dimensions; } -// TODO(b/149590301): Update these helpers to use new socket schema. -//std::unique_ptr<LogEvent> CreateScreenStateChangedEvent( -// const android::view::DisplayStateEnum state, uint64_t timestampNs) { -// auto event = std::make_unique<LogEvent>(android::util::SCREEN_STATE_CHANGED, timestampNs); -// EXPECT_TRUE(event->write(state)); -// event->init(); -// return event; -//} -// -//std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) { -// auto event = std::make_unique<LogEvent>( -// android::util::BATTERY_SAVER_MODE_STATE_CHANGED, timestampNs); -// EXPECT_TRUE(event->write(BatterySaverModeStateChanged::ON)); -// event->init(); -// return event; -//} -// -//std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) { -// auto event = std::make_unique<LogEvent>( -// android::util::BATTERY_SAVER_MODE_STATE_CHANGED, timestampNs); -// EXPECT_TRUE(event->write(BatterySaverModeStateChanged::OFF)); -// event->init(); -// return event; -//} -// -//std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent( -// int level, uint64_t timestampNs) { -// auto event = std::make_unique<LogEvent>(android::util::SCREEN_BRIGHTNESS_CHANGED, timestampNs); -// EXPECT_TRUE(event->write(level)); -// event->init(); -// return event; -// -//} -// +std::unique_ptr<LogEvent> CreateScreenStateChangedEvent( + uint64_t timestampNs, const android::view::DisplayStateEnum state) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::SCREEN_STATE_CHANGED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, state); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::BATTERY_SAVER_MODE_STATE_CHANGED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::ON); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::BATTERY_SAVER_MODE_STATE_CHANGED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::OFF); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::SCREEN_BRIGHTNESS_CHANGED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, level); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + //std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent( // const std::vector<AttributionNodeInternal>& attributions, const string& jobName, // const ScheduledJobStateChanged::State state, uint64_t timestampNs) { @@ -470,121 +505,212 @@ FieldMatcher CreateDimensions(const int atomId, const std::vector<int>& fields) // attributions, name, ScheduledJobStateChanged::FINISHED, timestampNs); //} // -//std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent( -// const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName, -// const WakelockStateChanged::State state, uint64_t timestampNs) { -// auto event = std::make_unique<LogEvent>(android::util::WAKELOCK_STATE_CHANGED, timestampNs); -// event->write(attributions); -// event->write(android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK); -// event->write(wakelockName); -// event->write(state); -// event->init(); -// return event; -//} -// -//std::unique_ptr<LogEvent> CreateAcquireWakelockEvent( -// const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName, -// uint64_t timestampNs) { -// return CreateWakelockStateChangedEvent( -// attributions, wakelockName, WakelockStateChanged::ACQUIRE, timestampNs); -//} -// -//std::unique_ptr<LogEvent> CreateReleaseWakelockEvent( -// const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName, -// uint64_t timestampNs) { -// return CreateWakelockStateChangedEvent( -// attributions, wakelockName, WakelockStateChanged::RELEASE, timestampNs); -//} -// -//std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent( -// const int uid, const ActivityForegroundStateChanged::State state, uint64_t timestampNs) { -// auto event = std::make_unique<LogEvent>( -// android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, timestampNs); -// event->write(uid); -// event->write("pkg_name"); -// event->write("class_name"); -// event->write(state); -// event->init(); -// return event; -//} -// -//std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs) { -// return CreateActivityForegroundStateChangedEvent( -// uid, ActivityForegroundStateChanged::BACKGROUND, timestampNs); -//} -// -//std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs) { -// return CreateActivityForegroundStateChangedEvent( -// uid, ActivityForegroundStateChanged::FOREGROUND, timestampNs); -//} -// -//std::unique_ptr<LogEvent> CreateSyncStateChangedEvent( -// const std::vector<AttributionNodeInternal>& attributions, const string& name, -// const SyncStateChanged::State state, uint64_t timestampNs) { -// auto event = std::make_unique<LogEvent>(android::util::SYNC_STATE_CHANGED, timestampNs); -// event->write(attributions); -// event->write(name); -// event->write(state); -// event->init(); -// return event; -//} -// -//std::unique_ptr<LogEvent> CreateSyncStartEvent( -// const std::vector<AttributionNodeInternal>& attributions, const string& name, -// uint64_t timestampNs) { -// return CreateSyncStateChangedEvent(attributions, name, SyncStateChanged::ON, timestampNs); -//} -// -//std::unique_ptr<LogEvent> CreateSyncEndEvent( -// const std::vector<AttributionNodeInternal>& attributions, const string& name, -// uint64_t timestampNs) { -// return CreateSyncStateChangedEvent(attributions, name, SyncStateChanged::OFF, timestampNs); -//} -// -//std::unique_ptr<LogEvent> CreateProcessLifeCycleStateChangedEvent( -// const int uid, const ProcessLifeCycleStateChanged::State state, uint64_t timestampNs) { -// auto logEvent = std::make_unique<LogEvent>( -// android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, timestampNs); -// logEvent->write(uid); -// logEvent->write(""); -// logEvent->write(state); -// logEvent->init(); -// return logEvent; -//} -// -//std::unique_ptr<LogEvent> CreateAppCrashEvent(const int uid, uint64_t timestampNs) { -// return CreateProcessLifeCycleStateChangedEvent( -// uid, ProcessLifeCycleStateChanged::CRASHED, timestampNs); -//} -// -//std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs) { -// auto event = std::make_unique<LogEvent>(android::util::APP_CRASH_OCCURRED, timestampNs); -// event->write(uid); -// event->write("eventType"); -// event->write("processName"); -// event->init(); -// return event; -//} -// -//std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent( -// int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs) { -// auto logEvent = std::make_unique<LogEvent>( -// android::util::ISOLATED_UID_CHANGED, timestampNs); -// logEvent->write(hostUid); -// logEvent->write(isolatedUid); -// logEvent->write(is_create); -// logEvent->init(); -// return logEvent; -//} -// -//std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent( -// int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs) { -// auto event = std::make_unique<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, timestampNs); -// event->write(uid); -// event->write(state); -// event->init(); -// return event; -//} +std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(uint64_t timestampNs, + const vector<int>& attributionUids, + const vector<string>& attributionTags, + const string& wakelockName, + const WakelockStateChanged::State state) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::WAKELOCK_STATE_CHANGED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + vector<const char*> cTags(attributionTags.size()); + for (int i = 0; i < cTags.size(); i++) { + cTags[i] = attributionTags[i].c_str(); + } + + AStatsEvent_writeAttributionChain(statsEvent, + reinterpret_cast<const uint32_t*>(attributionUids.data()), + cTags.data(), attributionUids.size()); + AStatsEvent_writeInt32(statsEvent, android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK); + AStatsEvent_writeString(statsEvent, wakelockName.c_str()); + AStatsEvent_writeInt32(statsEvent, state); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(uint64_t timestampNs, + const vector<int>& attributionUids, + const vector<string>& attributionTags, + const string& wakelockName) { + return CreateWakelockStateChangedEvent(timestampNs, attributionUids, attributionTags, + wakelockName, WakelockStateChanged::ACQUIRE); +} + +std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(uint64_t timestampNs, + const vector<int>& attributionUids, + const vector<string>& attributionTags, + const string& wakelockName) { + return CreateWakelockStateChangedEvent(timestampNs, attributionUids, attributionTags, + wakelockName, WakelockStateChanged::RELEASE); +} + +std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent( + uint64_t timestampNs, const int uid, const ActivityForegroundStateChanged::State state) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::ACTIVITY_FOREGROUND_STATE_CHANGED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, uid); + AStatsEvent_writeString(statsEvent, "pkg_name"); + AStatsEvent_writeString(statsEvent, "class_name"); + AStatsEvent_writeInt32(statsEvent, state); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid) { + return CreateActivityForegroundStateChangedEvent(timestampNs, uid, + ActivityForegroundStateChanged::BACKGROUND); +} + +std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid) { + return CreateActivityForegroundStateChangedEvent(timestampNs, uid, + ActivityForegroundStateChanged::FOREGROUND); +} + +std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(uint64_t timestampNs, + const vector<int>& attributionUids, + const vector<string>& attributionTags, + const string& name, + const SyncStateChanged::State state) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::SYNC_STATE_CHANGED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + vector<const char*> cTags(attributionTags.size()); + for (int i = 0; i < cTags.size(); i++) { + cTags[i] = attributionTags[i].c_str(); + } + + AStatsEvent_writeAttributionChain(statsEvent, + reinterpret_cast<const uint32_t*>(attributionUids.data()), + cTags.data(), attributionUids.size()); + AStatsEvent_writeString(statsEvent, name.c_str()); + AStatsEvent_writeInt32(statsEvent, state); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs, + const vector<int>& attributionUids, + const vector<string>& attributionTags, + const string& name) { + return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name, + SyncStateChanged::ON); +} + +std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs, + const vector<int>& attributionUids, + const vector<string>& attributionTags, + const string& name) { + return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name, + SyncStateChanged::OFF); +} + +std::unique_ptr<LogEvent> CreateProcessLifeCycleStateChangedEvent( + uint64_t timestampNs, const int uid, const ProcessLifeCycleStateChanged::State state) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, uid); + AStatsEvent_writeString(statsEvent, ""); + AStatsEvent_writeInt32(statsEvent, state); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +std::unique_ptr<LogEvent> CreateAppCrashEvent(uint64_t timestampNs, const int uid) { + return CreateProcessLifeCycleStateChangedEvent(timestampNs, uid, + ProcessLifeCycleStateChanged::CRASHED); +} + +std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::APP_CRASH_OCCURRED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, uid); + AStatsEvent_writeString(statsEvent, "eventType"); + AStatsEvent_writeString(statsEvent, "processName"); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int hostUid, + int isolatedUid, bool is_create) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::ISOLATED_UID_CHANGED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, hostUid); + AStatsEvent_writeInt32(statsEvent, isolatedUid); + AStatsEvent_writeInt32(statsEvent, is_create); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent( + uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, android::util::UID_PROCESS_STATE_CHANGED); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, uid); + AStatsEvent_writeInt32(statsEvent, state); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs, const StatsdConfig& config, const ConfigKey& key, diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h index c8326eef5698..4916327319ac 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -166,11 +166,10 @@ FieldMatcher CreateAttributionUidDimensions(const int atomId, // Create log event for screen state changed. std::unique_ptr<LogEvent> CreateScreenStateChangedEvent( - const android::view::DisplayStateEnum state, uint64_t timestampNs); + uint64_t timestampNs, const android::view::DisplayStateEnum state); // Create log event for screen brightness state changed. -std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent( - int level, uint64_t timestampNs); +std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level); // Create log event when scheduled job starts. std::unique_ptr<LogEvent> CreateStartScheduledJobEvent( @@ -188,45 +187,42 @@ std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs); std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs); // Create log event for app moving to background. -std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs); +std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid); // Create log event for app moving to foreground. -std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs); +std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid); // Create log event when the app sync starts. -std::unique_ptr<LogEvent> CreateSyncStartEvent( - const std::vector<AttributionNodeInternal>& attributions, const string& name, - uint64_t timestampNs); +std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs, const vector<int>& uids, + const vector<string>& tags, const string& name); // Create log event when the app sync ends. -std::unique_ptr<LogEvent> CreateSyncEndEvent( - const std::vector<AttributionNodeInternal>& attributions, const string& name, - uint64_t timestampNs); +std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs, const vector<int>& uids, + const vector<string>& tags, const string& name); // Create log event when the app sync ends. -std::unique_ptr<LogEvent> CreateAppCrashEvent( - const int uid, uint64_t timestampNs); +std::unique_ptr<LogEvent> CreateAppCrashEvent(uint64_t timestampNs, const int uid); // Create log event for an app crash. -std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs); +std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid); // Create log event for acquiring wakelock. -std::unique_ptr<LogEvent> CreateAcquireWakelockEvent( - const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName, - uint64_t timestampNs); +std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(uint64_t timestampNs, const vector<int>& uids, + const vector<string>& tags, + const string& wakelockName); // Create log event for releasing wakelock. -std::unique_ptr<LogEvent> CreateReleaseWakelockEvent( - const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName, - uint64_t timestampNs); +std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(uint64_t timestampNs, const vector<int>& uids, + const vector<string>& tags, + const string& wakelockName); // Create log event for releasing wakelock. -std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent( - int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs); +std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int isolatedUid, + int hostUid, bool is_create); // Create log event for uid process state change. std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent( - int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs); + uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state); // Helper function to create an AttributionNodeInternal proto. AttributionNodeInternal CreateAttribution(const int& uid, const string& tag); |