You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
742 lines
33 KiB
742 lines
33 KiB
4 months ago
|
// 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;
|
||
|
const uint64_t protoHash = 0x123456789;
|
||
|
|
||
|
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"), protoHash,
|
||
|
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"), protoHash,
|
||
|
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"), protoHash,
|
||
|
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"), protoHash,
|
||
|
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), protoHash,
|
||
|
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), protoHash,
|
||
|
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), protoHash,
|
||
|
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
|