Files
frameworks_base/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
tsaichristine 6e2e92d968 Pass initial conditions to combination conditions and metrics
SimplePredicates have a configurable initial value that can be set to
unknown or false. Previously, CombinationPredicates and MetricProducers
were automatically initialized with an unknown condition value instead
of being synced with the conditions of the SimplePredicates that they
rely on.

An initial condition cache is used to store initial conditions of
ConditionTrackers after they are initialized.
CombinationConditionTrackers evaluate their initial condition based on
the initial conditions of their child SimpleConditionTrackers.
MetricProducers also use the initial condition cache to set its
condition during initialization.

Added unit tests in SimpleConditionTracker_test to check that
SimpleConditionTrackers have the correct initial conditions based on
what the InitialValue is set to and the condition is updated properly
after the first few condition change events.

Added unit test in MetricsManager_test to check that all
ConditionTrackers and MetricProducers have the correct initial
conditions.

Test: m statsd_test && adb sync data && adb shell
data/nativetest64/statsd_test/statsd_test64
Bug: b/156762672

Change-Id: I9f6088f8c92fb18eb2ca8632aaa338fb0ed8e679
2020-06-01 09:25:02 -07:00

740 lines
32 KiB
C++

// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/condition/SimpleConditionTracker.h"
#include "stats_event.h"
#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
#include <vector>
#include <numeric>
using std::map;
using std::unordered_map;
using std::vector;
#ifdef __ANDROID__
namespace android {
namespace os {
namespace statsd {
namespace {
const ConfigKey kConfigKey(0, 12345);
const int ATTRIBUTION_NODE_FIELD_ID = 1;
const int ATTRIBUTION_UID_FIELD_ID = 1;
const int TAG_ID = 1;
SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
bool outputSlicedUid, Position position) {
SimplePredicate simplePredicate;
simplePredicate.set_start(StringToId("WAKE_LOCK_ACQUIRE"));
simplePredicate.set_stop(StringToId("WAKE_LOCK_RELEASE"));
simplePredicate.set_stop_all(StringToId("RELEASE_ALL"));
if (outputSlicedUid) {
simplePredicate.mutable_dimensions()->set_field(TAG_ID);
simplePredicate.mutable_dimensions()->add_child()->set_field(ATTRIBUTION_NODE_FIELD_ID);
simplePredicate.mutable_dimensions()->mutable_child(0)->set_position(position);
simplePredicate.mutable_dimensions()->mutable_child(0)->add_child()->set_field(
ATTRIBUTION_UID_FIELD_ID);
}
simplePredicate.set_count_nesting(countNesting);
simplePredicate.set_initial_value(defaultFalse ? SimplePredicate_InitialValue_FALSE
: SimplePredicate_InitialValue_UNKNOWN);
return simplePredicate;
}
void makeWakeLockEvent(LogEvent* logEvent, uint32_t atomId, uint64_t timestamp,
const vector<int>& uids, const string& wl, int acquire) {
AStatsEvent* statsEvent = AStatsEvent_obtain();
AStatsEvent_setAtomId(statsEvent, atomId);
AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
vector<std::string> tags(uids.size()); // vector of empty strings
writeAttribution(statsEvent, uids, tags);
AStatsEvent_writeString(statsEvent, wl.c_str());
AStatsEvent_writeInt32(statsEvent, acquire);
parseStatsEventToLogEvent(statsEvent, logEvent);
}
} // anonymous namespace
std::map<int64_t, HashableDimensionKey> getWakeLockQueryKey(
const Position position,
const std::vector<int> &uids, const string& conditionName) {
std::map<int64_t, HashableDimensionKey> outputKeyMap;
std::vector<int> uid_indexes;
int pos[] = {1, 1, 1};
int depth = 2;
Field field(1, pos, depth);
switch(position) {
case Position::FIRST:
uid_indexes.push_back(0);
break;
case Position::LAST:
uid_indexes.push_back(uids.size() - 1);
field.setField(0x02018001);
break;
case Position::ANY:
uid_indexes.resize(uids.size());
std::iota(uid_indexes.begin(), uid_indexes.end(), 0);
field.setField(0x02010001);
break;
default:
break;
}
for (const int idx : uid_indexes) {
Value value((int32_t)uids[idx]);
HashableDimensionKey dim;
dim.addValue(FieldValue(field, value));
outputKeyMap[StringToId(conditionName)] = dim;
}
return outputKeyMap;
}
TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueFalse) {
SimplePredicate simplePredicate;
simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
simplePredicate.set_count_nesting(false);
simplePredicate.set_initial_value(SimplePredicate_InitialValue_FALSE);
unordered_map<int64_t, int> trackerNameIndexMap;
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
0 /*tracker index*/, simplePredicate,
trackerNameIndexMap);
ConditionKey queryKey;
vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
// Check that initial condition is false.
conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
vector<MatchingState> matcherState;
vector<bool> changedCache(1, false);
// Matched stop event.
// Check that condition is still false.
unique_ptr<LogEvent> screenOffEvent =
CreateScreenStateChangedEvent(/*timestamp=*/50, android::view::DISPLAY_STATE_OFF);
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched); // On matcher not matched
matcherState.push_back(MatchingState::kMatched); // Off matcher matched
conditionCache[0] = ConditionState::kNotEvaluated;
conditionTracker.evaluateCondition(*screenOffEvent, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
EXPECT_FALSE(changedCache[0]);
// Matched start event.
// Check that condition has changed to true.
unique_ptr<LogEvent> screenOnEvent =
CreateScreenStateChangedEvent(/*timestamp=*/100, android::view::DISPLAY_STATE_ON);
matcherState.clear();
matcherState.push_back(MatchingState::kMatched); // On matcher matched
matcherState.push_back(MatchingState::kNotMatched); // Off matcher not matched
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
conditionTracker.evaluateCondition(*screenOnEvent, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
EXPECT_TRUE(changedCache[0]);
}
TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueUnknown) {
SimplePredicate simplePredicate;
simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
simplePredicate.set_count_nesting(false);
simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
unordered_map<int64_t, int> trackerNameIndexMap;
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
0 /*tracker index*/, simplePredicate,
trackerNameIndexMap);
ConditionKey queryKey;
vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
// Check that initial condition is unknown.
conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
vector<MatchingState> matcherState;
vector<bool> changedCache(1, false);
// Matched stop event.
// Check that condition is changed to false.
unique_ptr<LogEvent> screenOffEvent =
CreateScreenStateChangedEvent(/*timestamp=*/50, android::view::DISPLAY_STATE_OFF);
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched); // On matcher not matched
matcherState.push_back(MatchingState::kMatched); // Off matcher matched
conditionCache[0] = ConditionState::kNotEvaluated;
conditionTracker.evaluateCondition(*screenOffEvent, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
EXPECT_TRUE(changedCache[0]);
// Matched start event.
// Check that condition has changed to true.
unique_ptr<LogEvent> screenOnEvent =
CreateScreenStateChangedEvent(/*timestamp=*/100, android::view::DISPLAY_STATE_ON);
matcherState.clear();
matcherState.push_back(MatchingState::kMatched); // On matcher matched
matcherState.push_back(MatchingState::kNotMatched); // Off matcher not matched
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
conditionTracker.evaluateCondition(*screenOnEvent, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
EXPECT_TRUE(changedCache[0]);
}
TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
SimplePredicate simplePredicate;
simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
simplePredicate.set_count_nesting(false);
simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
unordered_map<int64_t, int> trackerNameIndexMap;
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), 0 /*tracker index*/,
simplePredicate, trackerNameIndexMap);
EXPECT_FALSE(conditionTracker.isSliced());
// 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);
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);
// not matched start or stop. condition doesn't change
EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
EXPECT_FALSE(changedCache[0]);
// prepare a case for match start.
matcherState.clear();
matcherState.push_back(MatchingState::kMatched);
matcherState.push_back(MatchingState::kNotMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// now condition should change to true.
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
EXPECT_TRUE(changedCache[0]);
// match nothing.
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kNotMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
EXPECT_FALSE(changedCache[0]);
// the case for match stop.
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// condition changes to false.
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
EXPECT_TRUE(changedCache[0]);
// match stop again.
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// condition should still be false. not changed.
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
EXPECT_FALSE(changedCache[0]);
}
TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
std::vector<sp<ConditionTracker>> allConditions;
SimplePredicate simplePredicate;
simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
simplePredicate.set_count_nesting(true);
unordered_map<int64_t, int> trackerNameIndexMap;
trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
EXPECT_FALSE(conditionTracker.isSliced());
// 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;
matcherState.push_back(MatchingState::kMatched);
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(ConditionState::kTrue, conditionCache[0]);
EXPECT_TRUE(changedCache[0]);
// prepare for another matched start.
matcherState.clear();
matcherState.push_back(MatchingState::kMatched);
matcherState.push_back(MatchingState::kNotMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
EXPECT_FALSE(changedCache[0]);
// ONE MATCHED STOP
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// result should still be true
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
EXPECT_FALSE(changedCache[0]);
// ANOTHER MATCHED STOP
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
EXPECT_TRUE(changedCache[0]);
}
TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
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_UID2";
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> uids = {111, 222, 333};
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids, "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) {
ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
} else {
ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(changedCache[0]);
if (position == Position::FIRST || position == Position::LAST) {
ASSERT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), 1u);
EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
} else {
EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(),
uids.size());
}
// Now test query
const auto queryKey = getWakeLockQueryKey(position, uids, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
conditionTracker.isConditionMet(queryKey, allPredicates, false, 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, uids, "wl2", /*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]);
if (position == Position::FIRST || position == Position::LAST) {
ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
} else {
ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
// wake lock 1 release
LogEvent event3(/*uid=*/0, /*pid=*/0);
makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/0);
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 wake lock 2 is still held for this uid
EXPECT_FALSE(changedCache[0]);
if (position == Position::FIRST || position == Position::LAST) {
ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
} else {
ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
LogEvent event4(/*uid=*/0, /*pid=*/0);
makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/0);
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);
ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
if (position == Position::FIRST || position == Position::LAST) {
ASSERT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), 1u);
EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
} else {
EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(),
uids.size());
}
// query again
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);
ASSERT_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);
ASSERT_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) {
ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
} else {
ASSERT_EQ(uids1.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(changedCache[0]);
{
if (position == Position::FIRST || position == Position::LAST) {
ASSERT_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) {
ASSERT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
} else {
ASSERT_EQ(uids1.size() + uids2.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(changedCache[0]);
{
if (position == Position::FIRST || position == Position::LAST) {
ASSERT_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]);
ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
{
if (position == Position::FIRST || position == Position::LAST) {
ASSERT_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
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif