The key change is to revamp how we parse/store/match a log event, especially how we match repeated field and attribution nodes, and how we construct dimensions and compare them. + We use a integer to encode the field of a log element. And also encode the FieldMatcher into an integer and a bit mask. The log matching becomes 2 integer operations. + Dimension is stored as encoded field and value pair. Checking if 2 dimensions are equal is then becoming checking if the underlying integers are equal. The integers are stored contiguously in memory, so it's much faster than previous tree structure. Start review from FieldValue.h Test: statsd_test + new unit tests Bug: 72659059 Change-Id: Iec8daeacdd3f39ab297c10ab9cd7b710a9c42e86
587 lines
24 KiB
C++
587 lines
24 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 "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 {
|
|
|
|
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 writeAttributionNodesToEvent(LogEvent* event, const std::vector<int> &uids) {
|
|
std::vector<AttributionNode> nodes;
|
|
for (size_t i = 0; i < uids.size(); ++i) {
|
|
AttributionNode node;
|
|
node.set_uid(uids[i]);
|
|
nodes.push_back(node);
|
|
}
|
|
event->write(nodes); // attribution chain.
|
|
}
|
|
|
|
void makeWakeLockEvent(
|
|
LogEvent* event, const std::vector<int> &uids, const string& wl, int acquire) {
|
|
writeAttributionNodesToEvent(event, uids);
|
|
event->write(wl);
|
|
event->write(acquire);
|
|
event->init();
|
|
}
|
|
|
|
std::map<int64_t, std::vector<HashableDimensionKey>> getWakeLockQueryKey(
|
|
const Position position,
|
|
const std::vector<int> &uids, const string& conditionName) {
|
|
std::map<int64_t, std::vector<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)].push_back(dim);
|
|
}
|
|
return outputKeyMap;
|
|
}
|
|
|
|
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);
|
|
|
|
LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
|
|
|
|
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) {
|
|
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);
|
|
|
|
LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
|
|
|
|
// 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);
|
|
// result should still be true
|
|
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
|
|
EXPECT_TRUE(changedCache[0]);
|
|
}
|
|
|
|
TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
|
|
for (Position position :
|
|
{ Position::ANY, Position::FIRST, Position::LAST}) {
|
|
vector<Matcher> dimensionInCondition;
|
|
std::unordered_set<HashableDimensionKey> dimensionKeys;
|
|
|
|
SimplePredicate simplePredicate = getWakeLockHeldCondition(
|
|
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
|
|
position);
|
|
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 event(1 /*tagId*/, 0 /*timestamp*/);
|
|
makeWakeLockEvent(&event, uids, "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(uids.size(), conditionTracker.mSlicedConditionState.size());
|
|
}
|
|
EXPECT_TRUE(changedCache[0]);
|
|
|
|
// Now test query
|
|
const auto queryKey = getWakeLockQueryKey(position, uids, conditionName);
|
|
conditionCache[0] = ConditionState::kNotEvaluated;
|
|
|
|
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
|
conditionCache, dimensionKeys);
|
|
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
|
|
|
|
// another wake lock acquired by this uid
|
|
LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
|
|
makeWakeLockEvent(&event2, uids, "wl2", 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) {
|
|
EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
|
|
} else {
|
|
EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
|
|
}
|
|
|
|
// wake lock 1 release
|
|
LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
|
|
makeWakeLockEvent(&event3, uids, "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 wake lock 2 is still held for this uid
|
|
EXPECT_FALSE(changedCache[0]);
|
|
if (position == Position::FIRST ||
|
|
position == Position::LAST) {
|
|
EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
|
|
} else {
|
|
EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
|
|
}
|
|
|
|
LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
|
|
makeWakeLockEvent(&event4, uids, "wl2", 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, dimensionInCondition,
|
|
conditionCache, dimensionKeys);
|
|
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
|
|
vector<Matcher> dimensionInCondition;
|
|
std::unordered_set<HashableDimensionKey> dimensionKeys;
|
|
|
|
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);
|
|
|
|
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, dimensionInCondition,
|
|
conditionCache, dimensionKeys);
|
|
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;
|
|
dimensionKeys.clear();
|
|
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
|
conditionCache, dimensionKeys);
|
|
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
|
|
}
|
|
|
|
TEST(SimpleConditionTrackerTest, TestStopAll) {
|
|
for (Position position :
|
|
{Position::ANY, Position::FIRST, Position::LAST}) {
|
|
vector<Matcher> dimensionInCondition;
|
|
std::unordered_set<HashableDimensionKey> dimensionKeys;
|
|
SimplePredicate simplePredicate = getWakeLockHeldCondition(
|
|
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
|
|
position);
|
|
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]);
|
|
|
|
// Now test query
|
|
const auto queryKey = getWakeLockQueryKey(position, uid_list1, conditionName);
|
|
conditionCache[0] = ConditionState::kNotEvaluated;
|
|
|
|
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
|
conditionCache, dimensionKeys);
|
|
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]);
|
|
|
|
// TEST QUERY
|
|
const auto queryKey2 = getWakeLockQueryKey(position, uid_list2, conditionName);
|
|
conditionCache[0] = ConditionState::kNotEvaluated;
|
|
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
|
conditionCache, dimensionKeys);
|
|
|
|
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());
|
|
|
|
// TEST QUERY
|
|
const auto queryKey3 = getWakeLockQueryKey(position, uid_list1, conditionName);
|
|
conditionCache[0] = ConditionState::kNotEvaluated;
|
|
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
|
conditionCache, dimensionKeys);
|
|
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
|
|
|
|
// TEST QUERY
|
|
const auto queryKey4 = getWakeLockQueryKey(position, uid_list2, conditionName);
|
|
conditionCache[0] = ConditionState::kNotEvaluated;
|
|
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
|
|
conditionCache, dimensionKeys);
|
|
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
|
|
}
|
|
}
|
|
|
|
} // namespace statsd
|
|
} // namespace os
|
|
} // namespace android
|
|
#else
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif
|