Add ability to transform string fields in atom events.
- Add string transformation config in SimpleAtomMatcher which includes
regex string and the replacement string.
- CombinationMatcher is not supported.
- Apply transformation for events before atom matching.
Bug: 308006155
Test: statsd_test
Change-Id: Ic76081b2bdac6c3bd1cce639d4468b229efa6a16
diff --git a/lib/libstatsgtestmatchers/include/gtest_matchers.h b/lib/libstatsgtestmatchers/include/gtest_matchers.h
index 084346d..3d9b792 100644
--- a/lib/libstatsgtestmatchers/include/gtest_matchers.h
+++ b/lib/libstatsgtestmatchers/include/gtest_matchers.h
@@ -206,13 +206,30 @@
EQ_MATCHER(PluggedStateChanged, PROPERTY_EQ(PluggedStateChanged, state));
TYPE_PRINTER(PluggedStateChanged, PROPERTY_PRINT(state));
+EQ_MATCHER(WakelockStateChanged,
+ REPEATED_PROPERTY_MATCHER(WakelockStateChanged, attribution_node, EqAttributionNode),
+ PROPERTY_EQ(WakelockStateChanged, type),
+ PROPERTY_EQ(WakelockStateChanged, tag),
+ PROPERTY_EQ(WakelockStateChanged, state),
+ PROPERTY_EQ(WakelockStateChanged, process_state)
+);
+TYPE_PRINTER(WakelockStateChanged,
+ REPEATED_PROPERTY_PRINT(attribution_node)
+ PROPERTY_PRINT(type)
+ PROPERTY_PRINT(tag)
+ PROPERTY_PRINT(state)
+ PROPERTY_PRINT(process_state)
+);
+
EQ_MATCHER(Atom,
PROPERTY_MATCHER(Atom, screen_state_changed, EqScreenStateChanged),
- PROPERTY_MATCHER(Atom, test_atom_reported, EqTestAtomReported)
+ PROPERTY_MATCHER(Atom, test_atom_reported, EqTestAtomReported),
+ PROPERTY_MATCHER(Atom, wakelock_state_changed, EqWakelockStateChanged)
);
TYPE_PRINTER(Atom,
PROPERTY_PRINT(screen_state_changed)
PROPERTY_PRINT(test_atom_reported)
+ PROPERTY_PRINT(wakelock_state_changed)
);
EQ_MATCHER(ShellData,
diff --git a/statsd/Android.bp b/statsd/Android.bp
index d1b4a2e..eea4ee8 100644
--- a/statsd/Android.bp
+++ b/statsd/Android.bp
@@ -116,6 +116,7 @@
"server_configurable_flags",
"statsd-aidl-ndk",
"libsqlite_static_noicu",
+ "libstats_regex",
],
shared_libs: [
"libbinder_ndk",
@@ -231,7 +232,6 @@
min_sdk_version: "30",
}
-
cc_defaults {
name: "statsd_test_defaults",
defaults: ["statsd_defaults"],
@@ -367,9 +367,10 @@
"tests/e2e/MetricConditionLink_e2e_test.cpp",
"tests/e2e/PartialBucket_e2e_test.cpp",
"tests/e2e/RestrictedConfig_e2e_test.cpp",
+ "tests/e2e/RestrictedEventMetric_e2e_test.cpp",
+ "tests/e2e/StringReplace_e2e_test.cpp",
"tests/e2e/ValueMetric_pull_e2e_test.cpp",
"tests/e2e/WakelockDuration_e2e_test.cpp",
- "tests/e2e/RestrictedEventMetric_e2e_test.cpp",
"tests/external/puller_util_test.cpp",
"tests/external/StatsCallbackPuller_test.cpp",
"tests/external/StatsPuller_test.cpp",
@@ -452,6 +453,19 @@
],
}
+// Build regex support in a separate library to catch std::regex_error exception.
+cc_library_static {
+ name: "libstats_regex",
+ srcs: ["lib/stats_regex.cpp"],
+ cppflags: ["-fexceptions"],
+ static_libs: ["libbase"],
+ min_sdk_version: "30",
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ ],
+}
+
// ==== java proto device library (for test only) ==============================
java_library {
name: "statsdprotolite",
diff --git a/statsd/lib/stats_regex.cpp b/statsd/lib/stats_regex.cpp
new file mode 100644
index 0000000..b041f66
--- /dev/null
+++ b/statsd/lib/stats_regex.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 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 "stats_regex.h"
+
+#include <log/log.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::regex;
+using std::regex_error;
+using std::regex_replace;
+using std::string;
+using std::unique_ptr;
+
+unique_ptr<regex> createRegex(const string& pattern) {
+ try {
+ return std::make_unique<regex>(pattern);
+ } catch (regex_error& e) {
+ ALOGE("regex_error: %s, pattern: %s", e.what(), pattern.c_str());
+ return nullptr;
+ }
+}
+
+string regexReplace(const string& input, const regex& re, const string& format) {
+ try {
+ return regex_replace(input, re, format);
+ } catch (regex_error& e) {
+ ALOGE("regex_error: %s, input: %s, format: %s", e.what(), input.c_str(), format.c_str());
+ return input;
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/statsd/lib/stats_regex.h b/statsd/lib/stats_regex.h
new file mode 100644
index 0000000..99e76b2
--- /dev/null
+++ b/statsd/lib/stats_regex.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <regex>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+std::unique_ptr<std::regex> createRegex(const std::string& pattern);
+
+std::string regexReplace(const std::string& input, const std::regex& re, const std::string& format);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/statsd/src/StatsLogProcessor.h b/statsd/src/StatsLogProcessor.h
index 1449911..d3e5d82 100644
--- a/statsd/src/StatsLogProcessor.h
+++ b/statsd/src/StatsLogProcessor.h
@@ -488,6 +488,10 @@
FRIEND_TEST(KllMetricE2eTest, TestInitWithKllFieldPositionALL);
FRIEND_TEST(StatsServiceStatsdInitTest, StatsServiceStatsdInitTest);
+
+ FRIEND_TEST(StringReplaceE2eTest, TestPulledDimension);
+ FRIEND_TEST(StringReplaceE2eTest, TestPulledWhat);
+ FRIEND_TEST(StringReplaceE2eTest, TestMultipleMatchersForAtom);
};
} // namespace statsd
diff --git a/statsd/src/guardrail/stats_log_enums.proto b/statsd/src/guardrail/stats_log_enums.proto
index 5fcdfda..d47bc80 100644
--- a/statsd/src/guardrail/stats_log_enums.proto
+++ b/statsd/src/guardrail/stats_log_enums.proto
@@ -143,6 +143,11 @@
INVALID_CONFIG_REASON_RESTRICTED_METRIC_NOT_SUPPORTED = 85;
INVALID_CONFIG_REASON_METRIC_INCORRECT_SAMPLING_PERCENTAGE = 86;
INVALID_CONFIG_REASON_GAUGE_METRIC_PULLED_WITH_SAMPLING = 87;
+ INVALID_CONFIG_REASON_MATCHER_NO_VALUE_MATCHER_NOR_STRING_REPLACER = 88;
+ INVALID_CONFIG_REASON_MATCHER_VALUE_MATCHER_WITH_POSITION_ALL = 89;
+ INVALID_CONFIG_REASON_MATCHER_INVALID_VALUE_MATCHER_WITH_STRING_REPLACE = 90;
+ INVALID_CONFIG_REASON_MATCHER_COMBINATION_WITH_STRING_REPLACE = 91;
+ INVALID_CONFIG_REASON_MATCHER_STRING_REPLACE_WITH_NO_VALUE_MATCHER_WITH_POSITION_ANY = 92;
};
enum InvalidQueryReason {
diff --git a/statsd/src/matchers/AtomMatchingTracker.h b/statsd/src/matchers/AtomMatchingTracker.h
index 308f7e1..49c35b2 100644
--- a/statsd/src/matchers/AtomMatchingTracker.h
+++ b/statsd/src/matchers/AtomMatchingTracker.h
@@ -32,6 +32,11 @@
namespace os {
namespace statsd {
+struct MatcherInitResult {
+ optional<InvalidConfigReason> invalidConfigReason;
+ bool hasStringTransformation;
+};
+
class AtomMatchingTracker : public virtual RefBase {
public:
AtomMatchingTracker(const int64_t id, const uint64_t protoHash)
@@ -49,7 +54,7 @@
// CombinationAtomMatchingTrackers using DFS.
// stack: a bit map to record which matcher has been visited on the stack. This is for detecting
// circle dependency.
- virtual optional<InvalidConfigReason> init(
+ virtual MatcherInitResult init(
int matcherIndex, const std::vector<AtomMatcher>& allAtomMatchers,
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
const std::unordered_map<int64_t, int>& matcherMap, std::vector<uint8_t>& stack) = 0;
@@ -70,9 +75,11 @@
// matcherResults: The cached results for all matchers for this event. Parent matchers can
// directly access the children's matching results if they have been evaluated.
// Otherwise, call children matchers' onLogEvent.
+ // matcherTransformations: the cached transformations for all matchers for this event.
virtual void onLogEvent(const LogEvent& event, int matcherIndex,
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
- std::vector<MatchingState>& matcherResults) = 0;
+ std::vector<MatchingState>& matcherResults,
+ std::vector<std::shared_ptr<LogEvent>>& matcherTransformations) = 0;
// Get the tagIds that this matcher cares about. The combined collection is stored
// in MetricMananger, so that we can pass any LogEvents that are not interest of us. It uses
diff --git a/statsd/src/matchers/CombinationAtomMatchingTracker.cpp b/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
index 68811cf..bc75eef 100644
--- a/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
+++ b/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
@@ -25,6 +25,7 @@
namespace statsd {
using std::set;
+using std::shared_ptr;
using std::unordered_map;
using std::vector;
@@ -36,12 +37,16 @@
CombinationAtomMatchingTracker::~CombinationAtomMatchingTracker() {
}
-optional<InvalidConfigReason> CombinationAtomMatchingTracker::init(
+MatcherInitResult CombinationAtomMatchingTracker::init(
int matcherIndex, const vector<AtomMatcher>& allAtomMatchers,
const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
const unordered_map<int64_t, int>& matcherMap, vector<uint8_t>& stack) {
+ MatcherInitResult result{nullopt /* invalidConfigReason */,
+ false /* hasStringTransformation */};
if (mInitialized) {
- return nullopt;
+ // CombinationMatchers do not support string transformations so if mInitialized = true,
+ // we know that there is no string transformation and we do not need to check for it again.
+ return result;
}
// mark this node as visited in the recursion stack.
@@ -51,26 +56,27 @@
// LogicalOperation is missing in the config
if (!matcher.has_operation()) {
- return createInvalidConfigReasonWithMatcher(INVALID_CONFIG_REASON_MATCHER_NO_OPERATION,
- mId);
+ result.invalidConfigReason = createInvalidConfigReasonWithMatcher(
+ INVALID_CONFIG_REASON_MATCHER_NO_OPERATION, mId);
+ return result;
}
mLogicalOperation = matcher.operation();
if (mLogicalOperation == LogicalOperation::NOT && matcher.matcher_size() != 1) {
- return createInvalidConfigReasonWithMatcher(
+ result.invalidConfigReason = createInvalidConfigReasonWithMatcher(
INVALID_CONFIG_REASON_MATCHER_NOT_OPERATION_IS_NOT_UNARY, mId);
+ return result;
}
for (const auto& child : matcher.matcher()) {
auto pair = matcherMap.find(child);
if (pair == matcherMap.end()) {
ALOGW("Matcher %lld not found in the config", (long long)child);
- optional<InvalidConfigReason> invalidConfigReason =
- createInvalidConfigReasonWithMatcher(
- INVALID_CONFIG_REASON_MATCHER_CHILD_NOT_FOUND, mId);
- invalidConfigReason->matcherIds.push_back(child);
- return invalidConfigReason;
+ result.invalidConfigReason = createInvalidConfigReasonWithMatcher(
+ INVALID_CONFIG_REASON_MATCHER_CHILD_NOT_FOUND, mId);
+ result.invalidConfigReason->matcherIds.push_back(child);
+ return result;
}
int childIndex = pair->second;
@@ -78,18 +84,27 @@
// if the child is a visited node in the recursion -> circle detected.
if (stack[childIndex]) {
ALOGE("Circle detected in matcher config");
- optional<InvalidConfigReason> invalidConfigReason =
+ result.invalidConfigReason =
createInvalidConfigReasonWithMatcher(INVALID_CONFIG_REASON_MATCHER_CYCLE, mId);
- invalidConfigReason->matcherIds.push_back(child);
- return invalidConfigReason;
+ result.invalidConfigReason->matcherIds.push_back(child);
+ return result;
}
- optional<InvalidConfigReason> invalidConfigReason =
+ auto [invalidConfigReason, hasStringTransformation] =
allAtomMatchingTrackers[childIndex]->init(
childIndex, allAtomMatchers, allAtomMatchingTrackers, matcherMap, stack);
+ if (hasStringTransformation) {
+ ALOGE("String transformation detected in CombinationMatcher");
+ result.invalidConfigReason = createInvalidConfigReasonWithMatcher(
+ INVALID_CONFIG_REASON_MATCHER_COMBINATION_WITH_STRING_REPLACE, mId);
+ result.hasStringTransformation = true;
+ return result;
+ }
+
if (invalidConfigReason.has_value()) {
ALOGW("child matcher init failed %lld", (long long)child);
invalidConfigReason->matcherIds.push_back(mId);
- return invalidConfigReason;
+ result.invalidConfigReason = invalidConfigReason;
+ return result;
}
mChildren.push_back(childIndex);
@@ -101,7 +116,7 @@
mInitialized = true;
// unmark this node in the recursion stack.
stack[matcherIndex] = false;
- return nullopt;
+ return result;
}
optional<InvalidConfigReason> CombinationAtomMatchingTracker::onConfigUpdated(
@@ -126,7 +141,8 @@
void CombinationAtomMatchingTracker::onLogEvent(
const LogEvent& event, int matcherIndex,
const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
- vector<MatchingState>& matcherResults) {
+ vector<MatchingState>& matcherResults,
+ vector<shared_ptr<LogEvent>>& matcherTransformations) {
// this event has been processed.
if (matcherResults[matcherIndex] != MatchingState::kNotComputed) {
return;
@@ -141,7 +157,8 @@
for (const int childIndex : mChildren) {
if (matcherResults[childIndex] == MatchingState::kNotComputed) {
const sp<AtomMatchingTracker>& child = allAtomMatchingTrackers[childIndex];
- child->onLogEvent(event, childIndex, allAtomMatchingTrackers, matcherResults);
+ child->onLogEvent(event, childIndex, allAtomMatchingTrackers, matcherResults,
+ matcherTransformations);
}
}
diff --git a/statsd/src/matchers/CombinationAtomMatchingTracker.h b/statsd/src/matchers/CombinationAtomMatchingTracker.h
index 1a6146c..9e06533 100644
--- a/statsd/src/matchers/CombinationAtomMatchingTracker.h
+++ b/statsd/src/matchers/CombinationAtomMatchingTracker.h
@@ -31,10 +31,10 @@
public:
CombinationAtomMatchingTracker(const int64_t id, const uint64_t protoHash);
- optional<InvalidConfigReason> init(
- int matcherIndex, const std::vector<AtomMatcher>& allAtomMatchers,
- const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
- const std::unordered_map<int64_t, int>& matcherMap, std::vector<uint8_t>& stack);
+ MatcherInitResult init(int matcherIndex, const std::vector<AtomMatcher>& allAtomMatchers,
+ const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
+ const std::unordered_map<int64_t, int>& matcherMap,
+ std::vector<uint8_t>& stack);
optional<InvalidConfigReason> onConfigUpdated(
const AtomMatcher& matcher,
@@ -44,7 +44,8 @@
void onLogEvent(const LogEvent& event, int matcherIndex,
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
- std::vector<MatchingState>& matcherResults) override;
+ std::vector<MatchingState>& matcherResults,
+ std::vector<std::shared_ptr<LogEvent>>& matcherTransformations) override;
private:
LogicalOperation mLogicalOperation;
diff --git a/statsd/src/matchers/EventMatcherWizard.cpp b/statsd/src/matchers/EventMatcherWizard.cpp
index 18a9074..1dbe5e0 100644
--- a/statsd/src/matchers/EventMatcherWizard.cpp
+++ b/statsd/src/matchers/EventMatcherWizard.cpp
@@ -21,14 +21,16 @@
using std::vector;
-MatchingState EventMatcherWizard::matchLogEvent(const LogEvent& event, int matcherIndex) {
+MatchLogEventResult EventMatcherWizard::matchLogEvent(const LogEvent& event, int matcherIndex) {
if (matcherIndex < 0 || matcherIndex >= (int)mAllEventMatchers.size()) {
- return MatchingState::kNotComputed;
+ return {MatchingState::kNotComputed, nullptr};
}
std::fill(mMatcherCache.begin(), mMatcherCache.end(), MatchingState::kNotComputed);
+ std::fill(mMatcherTransformations.begin(), mMatcherTransformations.end(), nullptr);
mAllEventMatchers[matcherIndex]->onLogEvent(event, matcherIndex, mAllEventMatchers,
- mMatcherCache);
- return mMatcherCache[matcherIndex];
+ mMatcherCache, mMatcherTransformations);
+
+ return {mMatcherCache[matcherIndex], mMatcherTransformations[matcherIndex]};
}
} // namespace statsd
diff --git a/statsd/src/matchers/EventMatcherWizard.h b/statsd/src/matchers/EventMatcherWizard.h
index c4ad150..b2ef311 100644
--- a/statsd/src/matchers/EventMatcherWizard.h
+++ b/statsd/src/matchers/EventMatcherWizard.h
@@ -22,20 +22,27 @@
namespace os {
namespace statsd {
+struct MatchLogEventResult {
+ MatchingState matchingState;
+ std::shared_ptr<LogEvent> transformedEvent;
+};
+
class EventMatcherWizard : public virtual RefBase {
public:
EventMatcherWizard(){}; // for testing
EventMatcherWizard(const std::vector<sp<AtomMatchingTracker>>& eventTrackers)
: mAllEventMatchers(eventTrackers),
- mMatcherCache(eventTrackers.size(), MatchingState::kNotComputed){};
+ mMatcherCache(eventTrackers.size(), MatchingState::kNotComputed),
+ mMatcherTransformations(eventTrackers.size(), nullptr){};
virtual ~EventMatcherWizard(){};
- MatchingState matchLogEvent(const LogEvent& event, int matcherIndex);
+ MatchLogEventResult matchLogEvent(const LogEvent& event, int matcherIndex);
private:
std::vector<sp<AtomMatchingTracker>> mAllEventMatchers;
std::vector<MatchingState> mMatcherCache;
+ std::vector<std::shared_ptr<LogEvent>> mMatcherTransformations;
};
} // namespace statsd
diff --git a/statsd/src/matchers/SimpleAtomMatchingTracker.cpp b/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
index 81d0710..db45560 100644
--- a/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
+++ b/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
@@ -23,6 +23,7 @@
namespace os {
namespace statsd {
+using std::shared_ptr;
using std::unordered_map;
using std::vector;
@@ -41,16 +42,27 @@
SimpleAtomMatchingTracker::~SimpleAtomMatchingTracker() {
}
-optional<InvalidConfigReason> SimpleAtomMatchingTracker::init(
+MatcherInitResult SimpleAtomMatchingTracker::init(
int matcherIndex, const vector<AtomMatcher>& allAtomMatchers,
const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
const unordered_map<int64_t, int>& matcherMap, vector<uint8_t>& stack) {
+ MatcherInitResult result{nullopt /* invalidConfigReason */,
+ false /* hasStringTransformation */};
// no need to do anything.
if (!mInitialized) {
- return createInvalidConfigReasonWithMatcher(
+ result.invalidConfigReason = createInvalidConfigReasonWithMatcher(
INVALID_CONFIG_REASON_MATCHER_TRACKER_NOT_INITIALIZED, mId);
+ return result;
}
- return nullopt;
+
+ for (const FieldValueMatcher& fvm : mMatcher.field_value_matcher()) {
+ if (fvm.has_replace_string()) {
+ result.hasStringTransformation = true;
+ break;
+ }
+ }
+
+ return result;
}
optional<InvalidConfigReason> SimpleAtomMatchingTracker::onConfigUpdated(
@@ -66,7 +78,8 @@
void SimpleAtomMatchingTracker::onLogEvent(
const LogEvent& event, int matcherIndex,
const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
- vector<MatchingState>& matcherResults) {
+ vector<MatchingState>& matcherResults,
+ vector<shared_ptr<LogEvent>>& matcherTransformations) {
if (matcherResults[matcherIndex] != MatchingState::kNotComputed) {
VLOG("Matcher %lld already evaluated ", (long long)mId);
return;
@@ -77,9 +90,13 @@
return;
}
- bool matched = matchesSimple(mUidMap, mMatcher, event);
+ auto [matched, transformedEvent] = matchesSimple(mUidMap, mMatcher, event);
matcherResults[matcherIndex] = matched ? MatchingState::kMatched : MatchingState::kNotMatched;
VLOG("Stats SimpleAtomMatcher %lld matched? %d", (long long)mId, matched);
+
+ if (matched && transformedEvent != nullptr) {
+ matcherTransformations[matcherIndex] = std::move(transformedEvent);
+ }
}
} // namespace statsd
diff --git a/statsd/src/matchers/SimpleAtomMatchingTracker.h b/statsd/src/matchers/SimpleAtomMatchingTracker.h
index 0cfb248..641e9d8 100644
--- a/statsd/src/matchers/SimpleAtomMatchingTracker.h
+++ b/statsd/src/matchers/SimpleAtomMatchingTracker.h
@@ -35,11 +35,10 @@
~SimpleAtomMatchingTracker();
- optional<InvalidConfigReason> init(
- int matcherIndex, const std::vector<AtomMatcher>& allAtomMatchers,
- const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
- const std::unordered_map<int64_t, int>& matcherMap,
- std::vector<uint8_t>& stack) override;
+ MatcherInitResult init(int matcherIndex, const std::vector<AtomMatcher>& allAtomMatchers,
+ const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
+ const std::unordered_map<int64_t, int>& matcherMap,
+ std::vector<uint8_t>& stack) override;
optional<InvalidConfigReason> onConfigUpdated(
const AtomMatcher& matcher,
@@ -47,7 +46,8 @@
void onLogEvent(const LogEvent& event, int matcherIndex,
const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
- std::vector<MatchingState>& matcherResults) override;
+ std::vector<MatchingState>& matcherResults,
+ std::vector<std::shared_ptr<LogEvent>>& matcherTransformations) override;
private:
const SimpleAtomMatcher mMatcher;
diff --git a/statsd/src/matchers/matcher_util.cpp b/statsd/src/matchers/matcher_util.cpp
index 7b5bcb0..347e484 100644
--- a/statsd/src/matchers/matcher_util.cpp
+++ b/statsd/src/matchers/matcher_util.cpp
@@ -20,12 +20,15 @@
#include <fnmatch.h>
+#include "lib/stats_regex.h"
#include "matchers/AtomMatchingTracker.h"
#include "src/statsd_config.pb.h"
#include "stats_util.h"
+using std::regex;
using std::set;
using std::string;
+using std::unique_ptr;
using std::vector;
namespace android {
@@ -127,6 +130,40 @@
return false;
}
+static unique_ptr<LogEvent> getTransformedEvent(const FieldValueMatcher& matcher,
+ const LogEvent& event, int start, int end) {
+ if (!matcher.has_replace_string()) {
+ return nullptr;
+ }
+
+ unique_ptr<regex> re = createRegex(matcher.replace_string().regex());
+ if (re == nullptr) {
+ return nullptr;
+ }
+
+ const string& replacement = matcher.replace_string().replacement();
+ unique_ptr<LogEvent> transformedEvent = nullptr;
+ for (int i = start; i < end; i++) {
+ const LogEvent& eventRef = transformedEvent == nullptr ? event : *transformedEvent;
+ const FieldValue& fieldValue = eventRef.getValues()[i];
+ if (fieldValue.mValue.getType() != STRING) {
+ continue;
+ }
+ const string transformedString =
+ regexReplace(fieldValue.mValue.str_value, *re, replacement);
+ if (transformedString == fieldValue.mValue.str_value) {
+ continue;
+ }
+
+ // String transformation occurred, update the FieldValue in transformedEvent.
+ if (transformedEvent == nullptr) {
+ transformedEvent = std::make_unique<LogEvent>(event);
+ }
+ (*transformedEvent->getMutableValues())[i].mValue.str_value = transformedString;
+ }
+ return transformedEvent;
+}
+
static pair<int, int> getStartEndAtDepth(int targetField, int start, int end, int depth,
const vector<FieldValue>& values) {
// Filter by entry field first
@@ -201,7 +238,24 @@
ranges.push_back(std::make_pair(start, end));
break;
}
+ case Position::ALL:
+ // ALL is only supported for string transformation. If a value_matcher other than
+ // matches_tuple is present, the matcher is invalid. This is enforced when
+ // the AtomMatchingTracker is initialized.
+
+ // fallthrough
case Position::ANY: {
+ // For string transformation, this case is treated the same as Position:ALL.
+ // Given a matcher on attribution_node[ANY].tag with a matches_tuple containing a
+ // child FieldValueMatcher with eq_string: "foo" and regex_replace: "[\d]+$" --> "",
+ // an event with attribution tags: ["bar123", "foo12", "abc230"] will transform to
+ // have attribution tags ["bar", "foo", "abc"] and will be a successful match.
+
+ // Note that if value_matcher is matches_tuple, there should be no string
+ // transformation on this matcher. However, child FieldValueMatchers in
+ // matches_tuple can have string transformations. This is enforced when
+ // AtomMatchingTracker is initialized.
+
if (matcher.value_matcher_case() == FieldValueMatcher::kMatchesTuple) {
// For ANY with matches_tuple, if all the children matchers match in any of the
// sub trees, it's a match.
@@ -220,9 +274,6 @@
ranges.push_back(std::make_pair(start, end));
break;
}
- case Position::ALL:
- ALOGE("Not supported: field matcher with ALL position.");
- break;
case Position::POSITION_UNKNOWN:
break;
}
@@ -234,43 +285,56 @@
return ranges;
}
-static bool matchesSimple(const sp<UidMap>& uidMap, const FieldValueMatcher& matcher,
- const vector<FieldValue>& values, int start, int end, int depth) {
+static MatchResult matchesSimple(const sp<UidMap>& uidMap, const FieldValueMatcher& matcher,
+ const LogEvent& event, int start, int end, int depth) {
if (depth > 2) {
- ALOGE("Depth > 3 not supported");
- return false;
+ ALOGE("Depth >= 3 not supported");
+ return {false, nullptr};
}
if (start >= end) {
- return false;
+ return {false, nullptr};
}
- const vector<pair<int, int>> ranges = computeRanges(matcher, values, start, end, depth);
+ const vector<pair<int, int>> ranges =
+ computeRanges(matcher, event.getValues(), start, end, depth);
if (ranges.empty()) {
// No such field found.
- return false;
+ return {false, nullptr};
}
// ranges should have exactly one start/end pair at this point unless position is ANY and
// value_matcher is matches_tuple.
std::tie(start, end) = ranges[0];
+ unique_ptr<LogEvent> transformedEvent = getTransformedEvent(matcher, event, start, end);
+
+ const vector<FieldValue>& values =
+ transformedEvent == nullptr ? event.getValues() : transformedEvent->getValues();
+
switch (matcher.value_matcher_case()) {
case FieldValueMatcher::kMatchesTuple: {
++depth;
// If any range matches all matchers, good.
+ bool matchResult = false;
for (const auto& [rangeStart, rangeEnd] : ranges) {
bool matched = true;
for (const auto& subMatcher : matcher.matches_tuple().field_value_matcher()) {
- if (!matchesSimple(uidMap, subMatcher, values, rangeStart, rangeEnd, depth)) {
+ const LogEvent& eventRef =
+ transformedEvent == nullptr ? event : *transformedEvent;
+ auto [hasMatched, newTransformedEvent] = matchesSimple(
+ uidMap, subMatcher, eventRef, rangeStart, rangeEnd, depth);
+ if (newTransformedEvent != nullptr) {
+ transformedEvent = std::move(newTransformedEvent);
+ }
+ if (!hasMatched) {
matched = false;
- break;
}
}
- if (matched) return true;
+ matchResult = matchResult || matched;
}
- return false;
+ return {matchResult, std::move(transformedEvent)};
}
// Finally, we get to the point of real value matching.
// If the field matcher ends with ANY, then we have [start, end) range > 1.
@@ -281,18 +345,18 @@
(values[i].mValue.int_value != 0) == matcher.eq_bool()) ||
(values[i].mValue.getType() == LONG &&
(values[i].mValue.long_value != 0) == matcher.eq_bool())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kEqString: {
for (int i = start; i < end; i++) {
if (tryMatchString(uidMap, values[i], matcher.eq_string())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kNeqAnyString: {
const auto& str_list = matcher.neq_any_string();
@@ -305,40 +369,40 @@
}
}
if (notEqAll) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kEqAnyString: {
const auto& str_list = matcher.eq_any_string();
for (int i = start; i < end; i++) {
for (const auto& str : str_list.str_value()) {
if (tryMatchString(uidMap, values[i], str)) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kEqWildcardString: {
for (int i = start; i < end; i++) {
if (tryMatchWildcardString(uidMap, values[i], matcher.eq_wildcard_string())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kEqAnyWildcardString: {
const auto& str_list = matcher.eq_any_wildcard_string();
for (int i = start; i < end; i++) {
for (const auto& str : str_list.str_value()) {
if (tryMatchWildcardString(uidMap, values[i], str)) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kNeqAnyWildcardString: {
const auto& str_list = matcher.neq_any_wildcard_string();
@@ -351,24 +415,24 @@
}
}
if (notEqAll) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kEqInt: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == INT &&
(matcher.eq_int() == values[i].mValue.int_value)) {
- return true;
+ return {true, std::move(transformedEvent)};
}
// eq_int covers both int and long.
if (values[i].mValue.getType() == LONG &&
(matcher.eq_int() == values[i].mValue.long_value)) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kEqAnyInt: {
const auto& int_list = matcher.eq_any_int();
@@ -376,16 +440,16 @@
for (const int int_value : int_list.int_value()) {
if (values[i].mValue.getType() == INT &&
(int_value == values[i].mValue.int_value)) {
- return true;
+ return {true, std::move(transformedEvent)};
}
// eq_any_int covers both int and long.
if (values[i].mValue.getType() == LONG &&
(int_value == values[i].mValue.long_value)) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kNeqAnyInt: {
const auto& int_list = matcher.neq_any_int();
@@ -405,102 +469,113 @@
}
}
if (notEqAll) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kLtInt: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == INT &&
(values[i].mValue.int_value < matcher.lt_int())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
// lt_int covers both int and long.
if (values[i].mValue.getType() == LONG &&
(values[i].mValue.long_value < matcher.lt_int())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kGtInt: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == INT &&
(values[i].mValue.int_value > matcher.gt_int())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
// gt_int covers both int and long.
if (values[i].mValue.getType() == LONG &&
(values[i].mValue.long_value > matcher.gt_int())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kLtFloat: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == FLOAT &&
(values[i].mValue.float_value < matcher.lt_float())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kGtFloat: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == FLOAT &&
(values[i].mValue.float_value > matcher.gt_float())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kLteInt: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == INT &&
(values[i].mValue.int_value <= matcher.lte_int())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
// lte_int covers both int and long.
if (values[i].mValue.getType() == LONG &&
(values[i].mValue.long_value <= matcher.lte_int())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
case FieldValueMatcher::ValueMatcherCase::kGteInt: {
for (int i = start; i < end; i++) {
if (values[i].mValue.getType() == INT &&
(values[i].mValue.int_value >= matcher.gte_int())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
// gte_int covers both int and long.
if (values[i].mValue.getType() == LONG &&
(values[i].mValue.long_value >= matcher.gte_int())) {
- return true;
+ return {true, std::move(transformedEvent)};
}
}
- return false;
+ return {false, std::move(transformedEvent)};
}
default:
- return false;
+ // This only happens if the matcher has a string transformation and no value_matcher. So
+ // the default match result is true. If there is no string transformation either then
+ // this matcher is invalid, which is enforced when the AtomMatchingTracker is
+ // initialized.
+ return {true, std::move(transformedEvent)};
}
}
-bool matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher,
- const LogEvent& event) {
+MatchResult matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher,
+ const LogEvent& event) {
if (event.GetTagId() != simpleMatcher.atom_id()) {
- return false;
+ return {false, nullptr};
}
+ unique_ptr<LogEvent> transformedEvent = nullptr;
for (const auto& matcher : simpleMatcher.field_value_matcher()) {
- if (!matchesSimple(uidMap, matcher, event.getValues(), 0, event.getValues().size(), 0)) {
- return false;
+ const LogEvent& inputEvent = transformedEvent == nullptr ? event : *transformedEvent;
+ auto [hasMatched, newTransformedEvent] =
+ matchesSimple(uidMap, matcher, inputEvent, 0, inputEvent.getValues().size(), 0);
+ if (newTransformedEvent != nullptr) {
+ transformedEvent = std::move(newTransformedEvent);
+ }
+ if (!hasMatched) {
+ return {false, std::move(transformedEvent)};
}
}
- return true;
+ return {true, std::move(transformedEvent)};
}
} // namespace statsd
diff --git a/statsd/src/matchers/matcher_util.h b/statsd/src/matchers/matcher_util.h
index 597b74f..5fb7c42 100644
--- a/statsd/src/matchers/matcher_util.h
+++ b/statsd/src/matchers/matcher_util.h
@@ -33,11 +33,16 @@
kMatched = 1,
};
+struct MatchResult {
+ bool matched;
+ std::unique_ptr<LogEvent> transformedEvent;
+};
+
bool combinationMatch(const std::vector<int>& children, const LogicalOperation& operation,
const std::vector<MatchingState>& matcherResults);
-bool matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher,
- const LogEvent& wrapper);
+MatchResult matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher,
+ const LogEvent& wrapper);
} // namespace statsd
} // namespace os
diff --git a/statsd/src/metrics/GaugeMetricProducer.cpp b/statsd/src/metrics/GaugeMetricProducer.cpp
index cab858b..e9f9477 100644
--- a/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -410,9 +410,10 @@
return;
}
for (const auto& data : allData) {
- if (mEventMatcherWizard->matchLogEvent(*data, mWhatMatcherIndex) ==
- MatchingState::kMatched) {
- LogEvent localCopy = *data;
+ const auto [matchResult, transformedEvent] =
+ mEventMatcherWizard->matchLogEvent(*data, mWhatMatcherIndex);
+ if (matchResult == MatchingState::kMatched) {
+ LogEvent localCopy = transformedEvent == nullptr ? *data : *transformedEvent;
localCopy.setElapsedTimestampNs(timestampNs);
onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
}
@@ -502,9 +503,11 @@
return;
}
for (const auto& data : allData) {
- if (mEventMatcherWizard->matchLogEvent(
- *data, mWhatMatcherIndex) == MatchingState::kMatched) {
- onMatchedLogEventLocked(mWhatMatcherIndex, *data);
+ const auto [matchResult, transformedEvent] =
+ mEventMatcherWizard->matchLogEvent(*data, mWhatMatcherIndex);
+ if (matchResult == MatchingState::kMatched) {
+ onMatchedLogEventLocked(mWhatMatcherIndex,
+ transformedEvent == nullptr ? *data : *transformedEvent);
}
}
}
diff --git a/statsd/src/metrics/MetricsManager.cpp b/statsd/src/metrics/MetricsManager.cpp
index e7e3561..8826848 100644
--- a/statsd/src/metrics/MetricsManager.cpp
+++ b/statsd/src/metrics/MetricsManager.cpp
@@ -44,6 +44,7 @@
using std::set;
using std::string;
+using std::unique_ptr;
using std::vector;
namespace android {
@@ -616,10 +617,12 @@
vector<MatchingState> matcherCache(mAllAtomMatchingTrackers.size(),
MatchingState::kNotComputed);
+ vector<shared_ptr<LogEvent>> matcherTransformations(matcherCache.size(), nullptr);
for (const auto& matcherIndex : matchersIt->second) {
mAllAtomMatchingTrackers[matcherIndex]->onLogEvent(event, matcherIndex,
- mAllAtomMatchingTrackers, matcherCache);
+ mAllAtomMatchingTrackers, matcherCache,
+ matcherTransformations);
}
// Set of metrics that received an activation cancellation.
@@ -661,12 +664,15 @@
// A bitmap to see which ConditionTracker needs to be re-evaluated.
vector<uint8_t> conditionToBeEvaluated(mAllConditionTrackers.size(), false);
+ vector<shared_ptr<LogEvent>> conditionToTransformedLogEvents(mAllConditionTrackers.size(),
+ nullptr);
- for (const auto& pair : mTrackerToConditionMap) {
- if (matcherCache[pair.first] == MatchingState::kMatched) {
- const auto& conditionList = pair.second;
+ for (const auto& [matcherIndex, conditionList] : mTrackerToConditionMap) {
+ if (matcherCache[matcherIndex] == MatchingState::kMatched) {
for (const int conditionIndex : conditionList) {
conditionToBeEvaluated[conditionIndex] = true;
+ conditionToTransformedLogEvents[conditionIndex] =
+ matcherTransformations[matcherIndex];
}
}
}
@@ -676,34 +682,38 @@
// A bitmap to track if a condition has changed value.
vector<uint8_t> changedCache(mAllConditionTrackers.size(), false);
for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
- if (conditionToBeEvaluated[i] == false) {
+ if (!conditionToBeEvaluated[i]) {
continue;
}
sp<ConditionTracker>& condition = mAllConditionTrackers[i];
- condition->evaluateCondition(event, matcherCache, mAllConditionTrackers, conditionCache,
- changedCache);
+ const LogEvent& conditionEvent = conditionToTransformedLogEvents[i] == nullptr
+ ? event
+ : *conditionToTransformedLogEvents[i];
+ condition->evaluateCondition(conditionEvent, matcherCache, mAllConditionTrackers,
+ conditionCache, changedCache);
}
for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
- if (changedCache[i] == false) {
+ if (!changedCache[i]) {
continue;
}
- auto pair = mConditionToMetricMap.find(i);
- if (pair != mConditionToMetricMap.end()) {
- auto& metricList = pair->second;
- for (auto metricIndex : metricList) {
- // Metric cares about non sliced condition, and it's changed.
- // Push the new condition to it directly.
- if (!mAllMetricProducers[metricIndex]->isConditionSliced()) {
- mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i],
- eventTimeNs);
- // Metric cares about sliced conditions, and it may have changed. Send
- // notification, and the metric can query the sliced conditions that are
- // interesting to it.
- } else {
- mAllMetricProducers[metricIndex]->onSlicedConditionMayChange(conditionCache[i],
- eventTimeNs);
- }
+ auto it = mConditionToMetricMap.find(i);
+ if (it == mConditionToMetricMap.end()) {
+ continue;
+ }
+ auto& metricList = it->second;
+ for (auto metricIndex : metricList) {
+ // Metric cares about non sliced condition, and it's changed.
+ // Push the new condition to it directly.
+ if (!mAllMetricProducers[metricIndex]->isConditionSliced()) {
+ mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i],
+ eventTimeNs);
+ // Metric cares about sliced conditions, and it may have changed. Send
+ // notification, and the metric can query the sliced conditions that are
+ // interesting to it.
+ } else {
+ mAllMetricProducers[metricIndex]->onSlicedConditionMayChange(conditionCache[i],
+ eventTimeNs);
}
}
}
@@ -712,13 +722,16 @@
if (matcherCache[i] == MatchingState::kMatched) {
StatsdStats::getInstance().noteMatcherMatched(mConfigKey,
mAllAtomMatchingTrackers[i]->getId());
- auto pair = mTrackerToMetricMap.find(i);
- if (pair != mTrackerToMetricMap.end()) {
- auto& metricList = pair->second;
- for (const int metricIndex : metricList) {
- // pushed metrics are never scheduled pulls
- mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event);
- }
+ auto it = mTrackerToMetricMap.find(i);
+ if (it == mTrackerToMetricMap.end()) {
+ continue;
+ }
+ auto& metricList = it->second;
+ const LogEvent& metricEvent =
+ matcherTransformations[i] == nullptr ? event : *matcherTransformations[i];
+ for (const int metricIndex : metricList) {
+ // pushed metrics are never scheduled pulls
+ mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, metricEvent);
}
}
}
diff --git a/statsd/src/metrics/NumericValueMetricProducer.cpp b/statsd/src/metrics/NumericValueMetricProducer.cpp
index bc17209..88e0975 100644
--- a/statsd/src/metrics/NumericValueMetricProducer.cpp
+++ b/statsd/src/metrics/NumericValueMetricProducer.cpp
@@ -267,15 +267,17 @@
// before calculating the diff between sums of consecutive pulls.
std::unordered_map<HashableDimensionKey, pair<LogEvent, vector<int>>> aggregateEvents;
for (const auto& data : allData) {
- if (mEventMatcherWizard->matchLogEvent(*data, mWhatMatcherIndex) !=
- MatchingState::kMatched) {
+ const auto [matchResult, transformedEvent] =
+ mEventMatcherWizard->matchLogEvent(*data, mWhatMatcherIndex);
+ if (matchResult != MatchingState::kMatched) {
continue;
}
// Get dimensions_in_what key and value indices.
HashableDimensionKey dimensionsInWhat;
vector<int> valueIndices(mFieldMatchers.size(), -1);
- if (!filterValues(mDimensionsInWhat, mFieldMatchers, data->getValues(),
+ const LogEvent& eventRef = transformedEvent == nullptr ? *data : *transformedEvent;
+ if (!filterValues(mDimensionsInWhat, mFieldMatchers, eventRef.getValues(),
dimensionsInWhat, valueIndices)) {
StatsdStats::getInstance().noteBadValueType(mMetricId);
}
@@ -285,9 +287,9 @@
if (it == aggregateEvents.end()) {
aggregateEvents.emplace(std::piecewise_construct,
std::forward_as_tuple(dimensionsInWhat),
- std::forward_as_tuple(*data, valueIndices));
+ std::forward_as_tuple(eventRef, valueIndices));
} else {
- combineValueFields(it->second, *data, valueIndices);
+ combineValueFields(it->second, eventRef, valueIndices);
}
}
@@ -297,9 +299,10 @@
}
} else {
for (const auto& data : allData) {
- if (mEventMatcherWizard->matchLogEvent(*data, mWhatMatcherIndex) ==
- MatchingState::kMatched) {
- LogEvent localCopy = *data;
+ const auto [matchResult, transformedEvent] =
+ mEventMatcherWizard->matchLogEvent(*data, mWhatMatcherIndex);
+ if (matchResult == MatchingState::kMatched) {
+ LogEvent localCopy = transformedEvent == nullptr ? *data : *transformedEvent;
localCopy.setElapsedTimestampNs(eventElapsedTimeNs);
onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
}
diff --git a/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/statsd/src/metrics/parsing_utils/config_update_utils.cpp
index 908fee1..18d7a32 100644
--- a/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ b/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -203,8 +203,9 @@
std::fill(cycleTracker.begin(), cycleTracker.end(), false);
for (size_t matcherIndex = 0; matcherIndex < newAtomMatchingTrackers.size(); matcherIndex++) {
auto& matcher = newAtomMatchingTrackers[matcherIndex];
- invalidConfigReason = matcher->init(matcherIndex, matcherProtos, newAtomMatchingTrackers,
- newAtomMatchingTrackerMap, cycleTracker);
+ const auto [invalidConfigReason, _] =
+ matcher->init(matcherIndex, matcherProtos, newAtomMatchingTrackers,
+ newAtomMatchingTrackerMap, cycleTracker);
if (invalidConfigReason.has_value()) {
return invalidConfigReason;
}
diff --git a/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
index 0feb793..673ff45 100644
--- a/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
+++ b/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
@@ -64,6 +64,71 @@
return true;
}
+// DFS for ensuring there is no
+// 1. value matching in the FieldValueMatcher tree with Position::ALL.
+// 2. string replacement in the FieldValueMatcher tree without a value matcher with Position::ANY.
+// Using vector to keep track of visited FieldValueMatchers since we expect number of
+// FieldValueMatchers to be low.
+optional<InvalidConfigReasonEnum> validateFvmPositionAllAndAny(
+ const FieldValueMatcher& fvm, bool inPositionAll, bool inPositionAny,
+ vector<FieldValueMatcher const*>& visited) {
+ visited.push_back(&fvm);
+ inPositionAll = inPositionAll || fvm.position() == Position::ALL;
+ inPositionAny = inPositionAny || fvm.position() == Position::ANY;
+ if (fvm.value_matcher_case() == FieldValueMatcher::kMatchesTuple) {
+ for (const FieldValueMatcher& childFvm : fvm.matches_tuple().field_value_matcher()) {
+ if (std::find(visited.cbegin(), visited.cend(), &childFvm) != visited.cend()) {
+ continue;
+ }
+ const optional<InvalidConfigReasonEnum> reasonEnum =
+ validateFvmPositionAllAndAny(childFvm, inPositionAll, inPositionAny, visited);
+ if (reasonEnum != nullopt) {
+ return reasonEnum;
+ }
+ }
+ return nullopt;
+ }
+ if (inPositionAll && fvm.value_matcher_case() != FieldValueMatcher::VALUE_MATCHER_NOT_SET) {
+ // value_matcher is set to something other than matches_tuple with Position::ALL
+ return INVALID_CONFIG_REASON_MATCHER_VALUE_MATCHER_WITH_POSITION_ALL;
+ }
+ if (inPositionAny && fvm.value_matcher_case() == FieldValueMatcher::VALUE_MATCHER_NOT_SET &&
+ fvm.has_replace_string()) {
+ // value_matcher is not set and there is a string replacement with Position::ANY
+ return INVALID_CONFIG_REASON_MATCHER_STRING_REPLACE_WITH_NO_VALUE_MATCHER_WITH_POSITION_ANY;
+ }
+ return nullopt;
+}
+
+optional<InvalidConfigReason> validateSimpleAtomMatcher(int64_t matcherId,
+ const SimpleAtomMatcher& simpleMatcher) {
+ for (const FieldValueMatcher& fvm : simpleMatcher.field_value_matcher()) {
+ if (fvm.value_matcher_case() == FieldValueMatcher::VALUE_MATCHER_NOT_SET &&
+ !fvm.has_replace_string()) {
+ return createInvalidConfigReasonWithMatcher(
+ INVALID_CONFIG_REASON_MATCHER_NO_VALUE_MATCHER_NOR_STRING_REPLACER, matcherId);
+ } else if (fvm.has_replace_string() &&
+ !(fvm.value_matcher_case() == FieldValueMatcher::VALUE_MATCHER_NOT_SET ||
+ fvm.value_matcher_case() == FieldValueMatcher::kEqString ||
+ fvm.value_matcher_case() == FieldValueMatcher::kEqAnyString ||
+ fvm.value_matcher_case() == FieldValueMatcher::kNeqAnyString ||
+ fvm.value_matcher_case() == FieldValueMatcher::kEqWildcardString ||
+ fvm.value_matcher_case() == FieldValueMatcher::kEqAnyWildcardString ||
+ fvm.value_matcher_case() == FieldValueMatcher::kNeqAnyWildcardString)) {
+ return createInvalidConfigReasonWithMatcher(
+ INVALID_CONFIG_REASON_MATCHER_INVALID_VALUE_MATCHER_WITH_STRING_REPLACE,
+ matcherId);
+ }
+ vector<FieldValueMatcher const*> visited;
+ const optional<InvalidConfigReasonEnum> reasonEnum = validateFvmPositionAllAndAny(
+ fvm, false /* inPositionAll */, false /* inPositionAny */, visited);
+ if (reasonEnum != nullopt) {
+ return createInvalidConfigReasonWithMatcher(*reasonEnum, matcherId);
+ }
+ }
+ return nullopt;
+}
+
} // namespace
sp<AtomMatchingTracker> createAtomMatchingTracker(
@@ -79,6 +144,12 @@
uint64_t protoHash = Hash64(serializedMatcher);
switch (logMatcher.contents_case()) {
case AtomMatcher::ContentsCase::kSimpleAtomMatcher: {
+ invalidConfigReason =
+ validateSimpleAtomMatcher(logMatcher.id(), logMatcher.simple_atom_matcher());
+ if (invalidConfigReason != nullopt) {
+ ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
+ return nullptr;
+ }
sp<AtomMatchingTracker> simpleAtomMatcher = new SimpleAtomMatchingTracker(
logMatcher.id(), protoHash, logMatcher.simple_atom_matcher(), uidMap);
return simpleAtomMatcher;
@@ -1342,8 +1413,9 @@
vector<uint8_t> stackTracker2(allAtomMatchingTrackers.size(), false);
for (size_t matcherIndex = 0; matcherIndex < allAtomMatchingTrackers.size(); matcherIndex++) {
auto& matcher = allAtomMatchingTrackers[matcherIndex];
- invalidConfigReason = matcher->init(matcherIndex, matcherConfigs, allAtomMatchingTrackers,
- atomMatchingTrackerMap, stackTracker2);
+ const auto [invalidConfigReason, _] =
+ matcher->init(matcherIndex, matcherConfigs, allAtomMatchingTrackers,
+ atomMatchingTrackerMap, stackTracker2);
if (invalidConfigReason.has_value()) {
return invalidConfigReason;
}
diff --git a/statsd/src/shell/ShellSubscriberClient.cpp b/statsd/src/shell/ShellSubscriberClient.cpp
index aaa4126..4ae8e93 100644
--- a/statsd/src/shell/ShellSubscriberClient.cpp
+++ b/statsd/src/shell/ShellSubscriberClient.cpp
@@ -177,23 +177,25 @@
bool ShellSubscriberClient::writeEventToProtoIfMatched(const LogEvent& event,
const SimpleAtomMatcher& matcher,
const sp<UidMap>& uidMap) {
- if (!matchesSimple(uidMap, matcher, event)) {
+ auto [matched, transformedEvent] = matchesSimple(mUidMap, matcher, event);
+ if (!matched) {
return false;
}
+ const LogEvent& eventRef = transformedEvent == nullptr ? event : *transformedEvent;
// Cache atom event in mProtoOut.
uint64_t atomToken = mProtoOut.start(util::FIELD_TYPE_MESSAGE | util::FIELD_COUNT_REPEATED |
FIELD_ID_SHELL_DATA__ATOM);
- event.ToProto(mProtoOut);
+ eventRef.ToProto(mProtoOut);
mProtoOut.end(atomToken);
- const int64_t timestampNs = truncateTimestampIfNecessary(event);
+ const int64_t timestampNs = truncateTimestampIfNecessary(eventRef);
mProtoOut.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED |
FIELD_ID_SHELL_DATA__ELAPSED_TIMESTAMP_NANOS,
static_cast<long long>(timestampNs));
// Update byte size of cached data.
- mCacheSize += getSize(event.getValues()) + sizeof(timestampNs);
+ mCacheSize += getSize(eventRef.getValues()) + sizeof(timestampNs);
return true;
}
diff --git a/statsd/src/statsd_config.proto b/statsd/src/statsd_config.proto
index 9c937a5..a7eef69 100644
--- a/statsd/src/statsd_config.proto
+++ b/statsd/src/statsd_config.proto
@@ -56,6 +56,14 @@
repeated FieldMatcher child = 3;
}
+message StringReplacer {
+ // Regex for matching the string.
+ optional string regex = 1;
+
+ // String with which to replace the matched string.
+ optional string replacement = 2;
+}
+
message FieldValueMatcher {
optional int32 field = 1;
@@ -85,6 +93,11 @@
StringListMatcher eq_any_wildcard_string = 18;
StringListMatcher neq_any_wildcard_string = 19;
}
+
+ // Can only be present if either:
+ // 1. value_matcher is not set.
+ // 2. value_matcher is set to one that is applicable to string fields.
+ optional StringReplacer replace_string = 20;
}
message MessageMatcher {
diff --git a/statsd/tests/LogEntryMatcher_test.cpp b/statsd/tests/LogEntryMatcher_test.cpp
index 5c098c2..2a0be07 100644
--- a/statsd/tests/LogEntryMatcher_test.cpp
+++ b/statsd/tests/LogEntryMatcher_test.cpp
@@ -24,6 +24,7 @@
#include "statsd_test_util.h"
using namespace android::os::statsd;
+using std::shared_ptr;
using std::unordered_map;
using std::vector;
@@ -31,7 +32,7 @@
const int32_t TAG_ID_2 = 28; // hardcoded tag of atom with uid field
const int FIELD_ID_1 = 1;
const int FIELD_ID_2 = 2;
-const int FIELD_ID_3 = 2;
+const int FIELD_ID_3 = 3;
const int ATTRIBUTION_UID_FIELD_ID = 1;
const int ATTRIBUTION_TAG_FIELD_ID = 2;
@@ -151,11 +152,11 @@
makeIntLogEvent(&event, TAG_ID, 0, 11);
// Test
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Wrong tag id.
simpleMatcher->set_atom_id(TAG_ID + 1);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestAttributionMatcher) {
@@ -186,43 +187,43 @@
fieldMatcher->set_eq_string("some value");
// Tag not matched.
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"location3");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"location1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match last node.
attributionMatcher->set_position(Position::LAST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"location3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match any node.
attributionMatcher->set_position(Position::ANY);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"location1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"location2");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"location3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"location4");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Attribution match but primitive field not match.
attributionMatcher->set_position(Position::ANY);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"location2");
fieldMatcher->set_eq_string("wrong value");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldMatcher->set_eq_string("some value");
@@ -232,7 +233,7 @@
ATTRIBUTION_UID_FIELD_ID);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg0");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
UidData uidData;
*uidData.add_app_info() = createApplicationInfo(/*uid*/ 1111, /*version*/ 1, "v1", "pkg0");
@@ -243,47 +244,47 @@
uidMap->updateMap(1, uidData);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg2");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg0");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->set_position(Position::FIRST);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg0");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg3");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg2");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->set_position(Position::LAST);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg0");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg2");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg1");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Uid + tag.
attributionMatcher->set_position(Position::ANY);
@@ -293,96 +294,96 @@
"pkg0");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg1");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg1");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location2");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg2");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg3");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg3");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location1");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->set_position(Position::FIRST);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg0");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg1");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg1");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location2");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg2");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location3");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg3");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location3");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg3");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location1");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->set_position(Position::LAST);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg0");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location1");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg1");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location1");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg1");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location2");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg2");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg3");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
"pkg3");
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
"location1");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestUidFieldMatcher) {
@@ -407,7 +408,7 @@
// Make event without is_uid annotation.
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeIntLogEvent(&event1, TAG_ID, 0, 1111);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1).matched);
// Make event with is_uid annotation.
LogEvent event2(/*uid=*/0, /*pid=*/0);
@@ -416,12 +417,12 @@
// Event has is_uid annotation, so mapping from uid to package name occurs.
simpleMatcher->set_atom_id(TAG_ID_2);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
// Event has is_uid annotation, but uid maps to different package name.
simpleMatcher->mutable_field_value_matcher(0)->set_eq_string(
"pkg2"); // package names are normalized
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
}
TEST(AtomMatcherTest, TestRepeatedUidFieldMatcher) {
@@ -450,35 +451,35 @@
fieldValueMatcher->set_position(Position::FIRST);
fieldValueMatcher->set_eq_string("pkg0");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1).matched);
fieldValueMatcher->set_position(Position::LAST);
fieldValueMatcher->set_eq_string("pkg1");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1).matched);
fieldValueMatcher->set_position(Position::ANY);
fieldValueMatcher->set_eq_string("pkg2");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1).matched);
// is_uid annotation, mapping from uid to package name.
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeRepeatedUidLogEvent(&event2, TAG_ID, intArray);
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
fieldValueMatcher->set_eq_string("pkg0");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
fieldValueMatcher->set_eq_string("pkg1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
fieldValueMatcher->set_position(Position::ANY);
fieldValueMatcher->set_eq_string("pkg");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
fieldValueMatcher->set_eq_string("pkg2"); // package names are normalized
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
}
TEST(AtomMatcherTest, TestNeqAnyStringMatcher_SingleString) {
@@ -498,17 +499,17 @@
// First string matched.
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event1, TAG_ID, 0, "some value");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1).matched);
// Second string matched.
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event2, TAG_ID, 0, "another value");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
// No strings matched.
LogEvent event3(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event3, TAG_ID, 0, "foo");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event3));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event3).matched);
}
TEST(AtomMatcherTest, TestNeqAnyStringMatcher_AttributionUids) {
@@ -551,26 +552,26 @@
fieldMatcher->set_field(FIELD_ID_2);
fieldMatcher->set_eq_string("some value");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
neqStringList->Clear();
neqStringList->add_str_value("pkg1");
neqStringList->add_str_value("pkg3");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->set_position(Position::ANY);
neqStringList->Clear();
neqStringList->add_str_value("maps.com");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
neqStringList->Clear();
neqStringList->add_str_value("PkG3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->set_position(Position::LAST);
neqStringList->Clear();
neqStringList->add_str_value("AID_STATSD");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestEqAnyStringMatcher) {
@@ -613,29 +614,29 @@
fieldMatcher->set_field(FIELD_ID_2);
fieldMatcher->set_eq_string("some value");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
attributionMatcher->set_position(Position::ANY);
eqStringList->Clear();
eqStringList->add_str_value("AID_STATSD");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
eqStringList->Clear();
eqStringList->add_str_value("pkg1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
auto normalStringField = fieldMatcher->mutable_eq_any_string();
normalStringField->add_str_value("some value123");
normalStringField->add_str_value("some value");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
normalStringField->Clear();
normalStringField->add_str_value("AID_STATSD");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
eqStringList->Clear();
eqStringList->add_str_value("maps.com");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestBoolMatcher) {
@@ -656,19 +657,19 @@
// Test
keyValue1->set_eq_bool(true);
keyValue2->set_eq_bool(false);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue1->set_eq_bool(false);
keyValue2->set_eq_bool(false);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue1->set_eq_bool(false);
keyValue2->set_eq_bool(true);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue1->set_eq_bool(true);
keyValue2->set_eq_bool(true);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestStringMatcher) {
@@ -686,7 +687,7 @@
makeStringLogEvent(&event, TAG_ID, 0, "some value");
// Test
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestIntMatcher_EmptyRepeatedField) {
@@ -706,16 +707,16 @@
// Match first int.
fieldValueMatcher->set_position(Position::FIRST);
fieldValueMatcher->set_eq_int(9);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match last int.
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match any int.
fieldValueMatcher->set_position(Position::ANY);
fieldValueMatcher->set_eq_int(13);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestIntMatcher_RepeatedIntField) {
@@ -736,28 +737,28 @@
fieldValueMatcher->set_field(FIELD_ID_1);
fieldValueMatcher->set_position(Position::FIRST);
fieldValueMatcher->set_eq_int(9);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_eq_int(21);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match last int.
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_eq_int(9);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match any int.
fieldValueMatcher->set_position(Position::ANY);
fieldValueMatcher->set_eq_int(13);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_eq_int(21);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_eq_int(9);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestLtIntMatcher_RepeatedIntField) {
@@ -778,34 +779,34 @@
fieldValueMatcher->set_field(FIELD_ID_1);
fieldValueMatcher->set_position(Position::FIRST);
fieldValueMatcher->set_lt_int(9);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_lt_int(21);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_lt_int(23);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match last int.
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_lt_int(9);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_lt_int(8);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match any int.
fieldValueMatcher->set_position(Position::ANY);
fieldValueMatcher->set_lt_int(21);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_lt_int(8);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_lt_int(23);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestStringMatcher_RepeatedStringField) {
@@ -826,31 +827,31 @@
fieldValueMatcher->set_field(FIELD_ID_1);
fieldValueMatcher->set_position(Position::FIRST);
fieldValueMatcher->set_eq_string("str2");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_eq_string("str1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match last int.
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_eq_string("str3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match any int.
fieldValueMatcher->set_position(Position::ANY);
fieldValueMatcher->set_eq_string("str4");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_eq_string("str1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_eq_string("str2");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_eq_string("str3");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestEqAnyStringMatcher_RepeatedStringField) {
@@ -871,43 +872,43 @@
StringListMatcher* eqStringList = fieldValueMatcher->mutable_eq_any_string();
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::ANY);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
eqStringList->add_str_value("str4");
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::ANY);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
eqStringList->add_str_value("str2");
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::ANY);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
eqStringList->add_str_value("str3");
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::ANY);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
eqStringList->add_str_value("str1");
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::ANY);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestNeqAnyStringMatcher_RepeatedStringField) {
@@ -928,43 +929,43 @@
StringListMatcher* neqStringList = fieldValueMatcher->mutable_neq_any_string();
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::ANY);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
neqStringList->add_str_value("str4");
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::ANY);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
neqStringList->add_str_value("str2");
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::ANY);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
neqStringList->add_str_value("str3");
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::ANY);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
neqStringList->add_str_value("str1");
fieldValueMatcher->set_position(Position::FIRST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::LAST);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
fieldValueMatcher->set_position(Position::ANY);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestMultiFieldsMatcher) {
@@ -985,15 +986,15 @@
// Test
keyValue1->set_eq_int(2);
keyValue2->set_eq_int(3);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue1->set_eq_int(2);
keyValue2->set_eq_int(4);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue1->set_eq_int(4);
keyValue2->set_eq_int(3);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestIntComparisonMatcher) {
@@ -1014,43 +1015,43 @@
// eq_int
keyValue->set_eq_int(10);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue->set_eq_int(11);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue->set_eq_int(12);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// lt_int
keyValue->set_lt_int(10);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue->set_lt_int(11);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue->set_lt_int(12);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// lte_int
keyValue->set_lte_int(10);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue->set_lte_int(11);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue->set_lte_int(12);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// gt_int
keyValue->set_gt_int(10);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue->set_gt_int(11);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue->set_gt_int(12);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// gte_int
keyValue->set_gte_int(10);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue->set_gte_int(11);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
keyValue->set_gte_int(12);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
}
TEST(AtomMatcherTest, TestFloatComparisonMatcher) {
@@ -1066,20 +1067,20 @@
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeFloatLogEvent(&event1, TAG_ID, 0, 10.1f);
keyValue->set_lt_float(10.0);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1).matched);
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeFloatLogEvent(&event2, TAG_ID, 0, 9.9f);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
LogEvent event3(/*uid=*/0, /*pid=*/0);
makeFloatLogEvent(&event3, TAG_ID, 0, 10.1f);
keyValue->set_gt_float(10.0);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event3));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event3).matched);
LogEvent event4(/*uid=*/0, /*pid=*/0);
makeFloatLogEvent(&event4, TAG_ID, 0, 9.9f);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event4));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event4).matched);
}
// Helper for the composite matchers.
@@ -1226,17 +1227,17 @@
// Event without is_uid annotation.
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeIntLogEvent(&event1, TAG_ID, 0, 1111);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1).matched);
// Event where mapping from uid to package name occurs.
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeIntWithBoolAnnotationLogEvent(&event2, TAG_ID, 1111, ASTATSLOG_ANNOTATION_ID_IS_UID, true);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
// Event where uid maps to package names that don't fit wildcard pattern.
LogEvent event3(/*uid=*/0, /*pid=*/0);
makeIntWithBoolAnnotationLogEvent(&event3, TAG_ID, 3333, ASTATSLOG_ANNOTATION_ID_IS_UID, true);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event3));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event3).matched);
// Update matcher to match one AID
simpleMatcher->mutable_field_value_matcher(0)->set_eq_wildcard_string(
@@ -1245,12 +1246,12 @@
// Event where mapping from uid to aid doesn't fit wildcard pattern.
LogEvent event4(/*uid=*/0, /*pid=*/0);
makeIntWithBoolAnnotationLogEvent(&event4, TAG_ID, 1005, ASTATSLOG_ANNOTATION_ID_IS_UID, true);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event4));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event4).matched);
// Event where mapping from uid to aid does fit wildcard pattern.
LogEvent event5(/*uid=*/0, /*pid=*/0);
makeIntWithBoolAnnotationLogEvent(&event5, TAG_ID, 1000, ASTATSLOG_ANNOTATION_ID_IS_UID, true);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event5));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event5).matched);
// Update matcher to match multiple AIDs
simpleMatcher->mutable_field_value_matcher(0)->set_eq_wildcard_string("AID_SDCARD_*");
@@ -1258,16 +1259,16 @@
// Event where mapping from uid to aid doesn't fit wildcard pattern.
LogEvent event6(/*uid=*/0, /*pid=*/0);
makeIntWithBoolAnnotationLogEvent(&event6, TAG_ID, 1036, ASTATSLOG_ANNOTATION_ID_IS_UID, true);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event6));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event6).matched);
// Event where mapping from uid to aid does fit wildcard pattern.
LogEvent event7(/*uid=*/0, /*pid=*/0);
makeIntWithBoolAnnotationLogEvent(&event7, TAG_ID, 1034, ASTATSLOG_ANNOTATION_ID_IS_UID, true);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event7));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event7).matched);
LogEvent event8(/*uid=*/0, /*pid=*/0);
makeIntWithBoolAnnotationLogEvent(&event8, TAG_ID, 1035, ASTATSLOG_ANNOTATION_ID_IS_UID, true);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event8));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event8).matched);
}
TEST(AtomMatcherTest, TestWildcardStringMatcher) {
@@ -1284,55 +1285,57 @@
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event1, TAG_ID, 0, "test.string:test_0");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event1));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event1).matched);
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event2, TAG_ID, 0, "test.string:test_19");
- EXPECT_FALSE(
- matchesSimple(uidMap, *simpleMatcher, event2)); // extra character at end of string
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2)
+ .matched); // extra character at end of string
LogEvent event3(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event3, TAG_ID, 0, "extra.test.string:test_1");
EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher,
- event3)); // extra characters at beginning of string
+ event3)
+ .matched); // extra characters at beginning of string
LogEvent event4(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event4, TAG_ID, 0, "test.string:test_");
EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher,
- event4)); // missing character from 0-9 at end of string
+ event4)
+ .matched); // missing character from 0-9 at end of string
LogEvent event5(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event5, TAG_ID, 0, "est.string:test_1");
- EXPECT_FALSE(
- matchesSimple(uidMap, *simpleMatcher, event5)); // missing 't' at beginning of string
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event5)
+ .matched); // missing 't' at beginning of string
LogEvent event6(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event6, TAG_ID, 0, "test.string:test_1extra");
- EXPECT_FALSE(
- matchesSimple(uidMap, *simpleMatcher, event6)); // extra characters at end of string
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event6)
+ .matched); // extra characters at end of string
// Matches any string that contains "test.string:test_" + any extra characters before or after
fieldValueMatcher->set_eq_wildcard_string("*test.string:test_*");
LogEvent event7(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event7, TAG_ID, 0, "test.string:test_");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event7));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event7).matched);
LogEvent event8(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event8, TAG_ID, 0, "extra.test.string:test_");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event8));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event8).matched);
LogEvent event9(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event9, TAG_ID, 0, "test.string:test_extra");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event9));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event9).matched);
LogEvent event10(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event10, TAG_ID, 0, "est.string:test_");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event10));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event10).matched);
LogEvent event11(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event11, TAG_ID, 0, "test.string:test");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event11));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event11).matched);
}
TEST(AtomMatcherTest, TestEqAnyWildcardStringMatcher) {
@@ -1352,17 +1355,17 @@
// First wildcard pattern matched.
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event1, TAG_ID, 0, "first_string_1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event1));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event1).matched);
// Second wildcard pattern matched.
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event2, TAG_ID, 0, "second_string_1");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
// No wildcard patterns matched.
LogEvent event3(/*uid=*/0, /*pid=*/0);
makeStringLogEvent(&event3, TAG_ID, 0, "third_string_1");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event3));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event3).matched);
}
TEST(AtomMatcherTest, TestNeqAnyWildcardStringMatcher) {
@@ -1389,27 +1392,27 @@
// First tag is not matched. neq string list {"tag"}
neqWildcardStrList->add_str_value("tag");
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// First tag is matched. neq string list {"tag", "location_*"}
neqWildcardStrList->add_str_value("location_*");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match last tag.
attributionMatcher->set_position(Position::LAST);
// Last tag is not matched. neq string list {"tag", "location_*"}
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Last tag is matched. neq string list {"tag", "location_*", "location*"}
neqWildcardStrList->add_str_value("location*");
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match any tag.
attributionMatcher->set_position(Position::ANY);
// All tags are matched. neq string list {"tag", "location_*", "location*"}
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Set up another log event.
std::vector<string> attributionTags2 = {"location_1", "location", "string"};
@@ -1417,7 +1420,7 @@
makeAttributionLogEvent(&event2, TAG_ID, 0, attributionUids, attributionTags2, "some value");
// Tag "string" is not matched. neq string list {"tag", "location_*", "location*"}
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
}
TEST(AtomMatcherTest, TestEqAnyIntMatcher) {
@@ -1437,17 +1440,17 @@
// First int matched.
LogEvent event1(/*uid=*/0, /*pid=*/0);
makeIntLogEvent(&event1, TAG_ID, 0, 3);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event1));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event1).matched);
// Second int matched.
LogEvent event2(/*uid=*/0, /*pid=*/0);
makeIntLogEvent(&event2, TAG_ID, 0, 5);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2).matched);
// No ints matched.
LogEvent event3(/*uid=*/0, /*pid=*/0);
makeIntLogEvent(&event3, TAG_ID, 0, 4);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event3));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event3).matched);
}
TEST(AtomMatcherTest, TestNeqAnyIntMatcher) {
@@ -1473,31 +1476,569 @@
// First uid is not matched. neq int list {4444}
neqIntList->add_int_value(4444);
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// First uid is matched. neq int list {4444, 1111}
neqIntList->add_int_value(1111);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match last uid.
attributionMatcher->set_position(Position::LAST);
// Last uid is not matched. neq int list {4444, 1111}
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Last uid is matched. neq int list {4444, 1111, 3333}
neqIntList->add_int_value(3333);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// Match any uid.
attributionMatcher->set_position(Position::ANY);
// Uid 2222 is not matched. neq int list {4444, 1111, 3333}
- EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event).matched);
// All uids are matched. neq int list {4444, 1111, 3333, 2222}
neqIntList->add_int_value(2222);
- EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+ EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event).matched);
+}
+
+TEST(AtomMatcherTest, TestStringReplaceRoot) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value123");
+
+ // Set up the matcher. Replace second field.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(FIELD_ID_2);
+ StringReplacer* stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.int_value, 1111);
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "location1");
+ EXPECT_EQ(fieldValues[2].mValue.int_value, 2222);
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "location2");
+ EXPECT_EQ(fieldValues[4].mValue.int_value, 3333);
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "location3");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "some value");
+}
+
+TEST(AtomMatcherTest, TestStringReplaceAttributionTagFirst) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value123");
+
+ // Set up the matcher. Replace first attribution tag.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* attributionFvm =
+ matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ attributionFvm->set_field(FIELD_ID_1);
+ attributionFvm->set_position(Position::FIRST);
+ FieldValueMatcher* attributionTagFvm =
+ attributionFvm->mutable_matches_tuple()->add_field_value_matcher();
+ attributionTagFvm->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ StringReplacer* stringReplacer = attributionTagFvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.int_value, 1111);
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "location");
+ EXPECT_EQ(fieldValues[2].mValue.int_value, 2222);
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "location2");
+ EXPECT_EQ(fieldValues[4].mValue.int_value, 3333);
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "location3");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "some value123");
+}
+
+TEST(AtomMatcherTest, TestStringReplaceAttributionTagLast) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value123");
+
+ // Set up the matcher. Replace last attribution tag.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* attributionFvm =
+ matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ attributionFvm->set_field(FIELD_ID_1);
+ attributionFvm->set_position(Position::LAST);
+ FieldValueMatcher* attributionTagFvm =
+ attributionFvm->mutable_matches_tuple()->add_field_value_matcher();
+ attributionTagFvm->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ StringReplacer* stringReplacer = attributionTagFvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.int_value, 1111);
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "location1");
+ EXPECT_EQ(fieldValues[2].mValue.int_value, 2222);
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "location2");
+ EXPECT_EQ(fieldValues[4].mValue.int_value, 3333);
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "location");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "some value123");
+}
+
+TEST(AtomMatcherTest, TestStringReplaceAttributionTagAll) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value123");
+
+ // Set up the matcher. Replace all attribution tags.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* attributionFvm =
+ matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ attributionFvm->set_field(FIELD_ID_1);
+ attributionFvm->set_position(Position::ALL);
+ FieldValueMatcher* attributionTagFvm =
+ attributionFvm->mutable_matches_tuple()->add_field_value_matcher();
+ attributionTagFvm->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ StringReplacer* stringReplacer = attributionTagFvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.int_value, 1111);
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "location");
+ EXPECT_EQ(fieldValues[2].mValue.int_value, 2222);
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "location");
+ EXPECT_EQ(fieldValues[4].mValue.int_value, 3333);
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "location");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "some value123");
+}
+
+TEST(AtomMatcherTest, TestStringReplaceNestedAllWithMultipleNestedStringFields) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value123");
+
+ // Manually change uid fields to string fields, as there is no direct way to create a
+ // LogEvent with multiple nested string fields.
+ (*event.getMutableValues())[0].mValue = android::os::statsd::Value("abc1");
+ (*event.getMutableValues())[2].mValue = android::os::statsd::Value("xyz2");
+ (*event.getMutableValues())[4].mValue = android::os::statsd::Value("abc3");
+
+ // Set up the matcher. Replace all attribution tags.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* attributionFvm =
+ matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ attributionFvm->set_field(FIELD_ID_1);
+ attributionFvm->set_position(Position::ALL);
+ FieldValueMatcher* attributionTagFvm =
+ attributionFvm->mutable_matches_tuple()->add_field_value_matcher();
+ attributionTagFvm->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ StringReplacer* stringReplacer = attributionTagFvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.str_value, "abc1");
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "location");
+ EXPECT_EQ(fieldValues[2].mValue.str_value, "xyz2");
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "location");
+ EXPECT_EQ(fieldValues[4].mValue.str_value, "abc3");
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "location");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "some value123");
+}
+
+TEST(AtomMatcherTest, TestStringReplaceRootOnMatchedField) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the matcher. Replace second field and match on replaced field.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(FIELD_ID_2);
+ fvm->set_eq_string("bar");
+ StringReplacer* stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags,
+ "some value123");
+
+ EXPECT_FALSE(matchesSimple(uidMap, matcher.simple_atom_matcher(), event).matched);
+ }
+
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "bar123");
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.int_value, 1111);
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "location1");
+ EXPECT_EQ(fieldValues[2].mValue.int_value, 2222);
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "location2");
+ EXPECT_EQ(fieldValues[4].mValue.int_value, 3333);
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "location3");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "bar");
+ }
+}
+
+TEST(AtomMatcherTest, TestStringReplaceAttributionTagFirstOnMatchedField) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the matcher. Replace first attribution tag and match on that tag.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* attributionFvm =
+ matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ attributionFvm->set_field(FIELD_ID_1);
+ attributionFvm->set_position(Position::FIRST);
+ FieldValueMatcher* attributionTagFvm =
+ attributionFvm->mutable_matches_tuple()->add_field_value_matcher();
+ attributionTagFvm->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ attributionTagFvm->set_eq_string("bar");
+ StringReplacer* stringReplacer = attributionTagFvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags,
+ "some value123");
+
+ EXPECT_FALSE(matchesSimple(uidMap, matcher.simple_atom_matcher(), event).matched);
+ }
+
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ attributionTags = {"bar1", "bar2", "bar3"};
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "bar123");
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.int_value, 1111);
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "bar");
+ EXPECT_EQ(fieldValues[2].mValue.int_value, 2222);
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "bar2");
+ EXPECT_EQ(fieldValues[4].mValue.int_value, 3333);
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "bar3");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "bar123");
+ }
+}
+
+TEST(AtomMatcherTest, TestStringReplaceAttributionTagLastOnMatchedField) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the matcher. Replace last attribution tag and match on that tag.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* attributionFvm =
+ matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ attributionFvm->set_field(FIELD_ID_1);
+ attributionFvm->set_position(Position::LAST);
+ FieldValueMatcher* attributionTagFvm =
+ attributionFvm->mutable_matches_tuple()->add_field_value_matcher();
+ attributionTagFvm->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ attributionTagFvm->set_eq_string("bar");
+ StringReplacer* stringReplacer = attributionTagFvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags,
+ "some value123");
+
+ EXPECT_FALSE(matchesSimple(uidMap, matcher.simple_atom_matcher(), event).matched);
+ }
+
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ attributionTags = {"bar1", "bar2", "bar3"};
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "bar123");
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.int_value, 1111);
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "bar1");
+ EXPECT_EQ(fieldValues[2].mValue.int_value, 2222);
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "bar2");
+ EXPECT_EQ(fieldValues[4].mValue.int_value, 3333);
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "bar");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "bar123");
+ }
+}
+
+TEST(AtomMatcherTest, TestStringReplaceAttributionTagAnyOnMatchedField) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the matcher. Replace all attribution tags but match on any tag.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* attributionFvm =
+ matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ attributionFvm->set_field(FIELD_ID_1);
+ attributionFvm->set_position(Position::ANY);
+ FieldValueMatcher* attributionTagFvm =
+ attributionFvm->mutable_matches_tuple()->add_field_value_matcher();
+ attributionTagFvm->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ attributionTagFvm->set_eq_string("bar");
+ StringReplacer* stringReplacer = attributionTagFvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags,
+ "some value123");
+
+ EXPECT_FALSE(matchesSimple(uidMap, matcher.simple_atom_matcher(), event).matched);
+ }
+
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ attributionTags = {"foo1", "bar2", "foo3"};
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "bar123");
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.int_value, 1111);
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "foo");
+ EXPECT_EQ(fieldValues[2].mValue.int_value, 2222);
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "bar");
+ EXPECT_EQ(fieldValues[4].mValue.int_value, 3333);
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "foo");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "bar123");
+ }
+}
+
+TEST(AtomMatcherTest, TestStringReplaceAttributionTagAnyAndRootOnMatchedFields) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the matcher. Replace all attribution tags but match on any tag.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* attributionFvm =
+ matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ attributionFvm->set_field(FIELD_ID_1);
+ attributionFvm->set_position(Position::ANY);
+ FieldValueMatcher* attributionTagFvm =
+ attributionFvm->mutable_matches_tuple()->add_field_value_matcher();
+ attributionTagFvm->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ attributionTagFvm->set_eq_string("bar");
+ StringReplacer* stringReplacer = attributionTagFvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+ FieldValueMatcher* rootFvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ rootFvm->set_field(FIELD_ID_2);
+ rootFvm->set_eq_string("blah");
+ stringReplacer = rootFvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, {1111, 2222, 3333} /* uids */,
+ {"location1", "location2", "location3"} /* tags */,
+ "some value123" /* name */);
+
+ EXPECT_FALSE(matchesSimple(uidMap, matcher.simple_atom_matcher(), event).matched);
+ }
+
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, {1111, 2222, 3333} /* uids */,
+ {"foo1", "bar2", "foo3"} /* tags */, "bar123" /* name */);
+ EXPECT_FALSE(matchesSimple(uidMap, matcher.simple_atom_matcher(), event).matched);
+ }
+
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, {1111, 2222, 3333} /* uids */,
+ {"foo1", "bar2", "foo3"} /* tags */, "blah123" /* name */);
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.int_value, 1111);
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "foo");
+ EXPECT_EQ(fieldValues[2].mValue.int_value, 2222);
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "bar");
+ EXPECT_EQ(fieldValues[4].mValue.int_value, 3333);
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "foo");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "blah");
+ }
+}
+
+TEST(AtomMatcherTest, TestStringReplaceAttributionTagAnyWithAttributionUidValueMatcher) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the matcher. Replace all attribution tags but match on any uid and tag.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* attributionFvm =
+ matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ attributionFvm->set_field(FIELD_ID_1);
+ attributionFvm->set_position(Position::ANY);
+ FieldValueMatcher* attributionUidFvm =
+ attributionFvm->mutable_matches_tuple()->add_field_value_matcher();
+ attributionUidFvm->set_field(ATTRIBUTION_UID_FIELD_ID);
+ attributionUidFvm->set_eq_int(2222);
+ FieldValueMatcher* attributionTagFvm =
+ attributionFvm->mutable_matches_tuple()->add_field_value_matcher();
+ attributionTagFvm->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ attributionTagFvm->set_eq_string("bar");
+ StringReplacer* stringReplacer = attributionTagFvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, {1111, 2222, 3333} /* uids */,
+ {"location1", "location2", "location3"} /* tags */,
+ "some value123" /* name */);
+
+ EXPECT_FALSE(matchesSimple(uidMap, matcher.simple_atom_matcher(), event).matched);
+ }
+
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, {1111, 3223, 3333} /* uids */,
+ {"foo1", "bar2", "foo3"} /* tags */, "bar123" /* name */);
+ EXPECT_FALSE(matchesSimple(uidMap, matcher.simple_atom_matcher(), event).matched);
+ }
+
+ {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, {1111, 2222, 3333} /* uids */,
+ {"foo1", "bar2", "foo3"} /* tags */, "bar123" /* name */);
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_NE(transformedEvent, nullptr);
+ const vector<FieldValue>& fieldValues = transformedEvent->getValues();
+ ASSERT_EQ(fieldValues.size(), 7);
+ EXPECT_EQ(fieldValues[0].mValue.int_value, 1111);
+ EXPECT_EQ(fieldValues[1].mValue.str_value, "foo");
+ EXPECT_EQ(fieldValues[2].mValue.int_value, 2222);
+ EXPECT_EQ(fieldValues[3].mValue.str_value, "bar");
+ EXPECT_EQ(fieldValues[4].mValue.int_value, 3333);
+ EXPECT_EQ(fieldValues[5].mValue.str_value, "foo");
+ EXPECT_EQ(fieldValues[6].mValue.str_value, "bar123");
+ }
+}
+
+TEST(AtomMatcherTest, TestStringReplaceBadRegex) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value123");
+
+ // Set up the matcher. Replace second field.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(FIELD_ID_2);
+ StringReplacer* stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"(*[\d]+$)"); // bad regex: asterisk not preceded by any expression.
+ stringReplacer->set_replacement("");
+
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_EQ(transformedEvent, nullptr);
+}
+
+TEST(AtomMatcherTest, TestStringReplaceNoop) {
+ sp<UidMap> uidMap = new UidMap();
+
+ // Set up the log event.
+ std::vector<int> attributionUids = {1111, 2222, 3333};
+ std::vector<string> attributionTags = {"location1", "location2", "location3"};
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value123");
+
+ // Set up the matcher. Replace second field.
+ AtomMatcher matcher = CreateSimpleAtomMatcher("matcher", TAG_ID);
+ FieldValueMatcher* fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(FIELD_ID_2);
+ StringReplacer* stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"(this_pattern_should_not_match)");
+ stringReplacer->set_replacement("");
+
+ const auto [hasMatched, transformedEvent] =
+ matchesSimple(uidMap, matcher.simple_atom_matcher(), event);
+ EXPECT_TRUE(hasMatched);
+ ASSERT_EQ(transformedEvent, nullptr);
}
#else
diff --git a/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/statsd/tests/e2e/DurationMetric_e2e_test.cpp
index 6908f57..a6d50d9 100644
--- a/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -466,7 +466,6 @@
TEST(DurationMetricE2eTest, TestWithSlicedCondition) {
StatsdConfig config;
- auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
*config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
*config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
*config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
diff --git a/statsd/tests/e2e/StringReplace_e2e_test.cpp b/statsd/tests/e2e/StringReplace_e2e_test.cpp
new file mode 100644
index 0000000..27bcf52
--- /dev/null
+++ b/statsd/tests/e2e/StringReplace_e2e_test.cpp
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <gtest_matchers.h>
+
+#include "src/StatsLogProcessor.h"
+#include "tests/statsd_test_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+const int64_t metricId = 123456;
+const int TEST_ATOM_REPORTED_STRING_FIELD_ID = 5;
+const int SUBSYSTEM_SLEEP_STATE_SUBSYSTEM_NAME_FIELD_ID = 1;
+const int SUBSYSTEM_SLEEP_STATE_SUBNAME_FIELD_ID = 2;
+const int SUBSYSTEM_SLEEP_STATE_TIME_MILLIS_FIELD_ID = 4;
+const int SCHEDULED_JOB_STATE_CHANGED_JOB_NAME_FIELD_ID = 2;
+const int ACTIVITY_FOREGROUND_STATE_CHANGED_UID_FIELD_ID = 1;
+const int ACTIVITY_FOREGROUND_STATE_CHANGED_PKG_NAME_FIELD_ID = 2;
+const int WAKELOCK_STATE_CHANGED_TAG_FIELD_ID = 3;
+const int ATTRIBUTION_CHAIN_FIELD_ID = 1;
+const int ATTRIBUTION_TAG_FIELD_ID = 2;
+
+std::unique_ptr<LogEvent> CreateTestAtomReportedEventStringDim(uint64_t timestampNs,
+ const string& stringField) {
+ return CreateTestAtomReportedEventWithPrimitives(
+ timestampNs, 0 /* intField */, 0l /* longField */, 0.0f /* floatField */, stringField,
+ false /* boolField */, TestAtomReported::OFF /* enumField */);
+}
+
+StatsdConfig CreateStatsdConfig() {
+ StatsdConfig config;
+ config.add_default_pull_packages("AID_ROOT"); // Fake puller is registered with root.
+ config.set_hash_strings_in_metric_report(false);
+
+ return config;
+}
+
+} // namespace
+
+TEST(StringReplaceE2eTest, TestPushedDimension) {
+ StatsdConfig config = CreateStatsdConfig();
+
+ *config.add_atom_matcher() =
+ CreateSimpleAtomMatcher("TestAtomMatcher", util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = config.mutable_atom_matcher(0)
+ ->mutable_simple_atom_matcher()
+ ->add_field_value_matcher();
+ fvm->set_field(TEST_ATOM_REPORTED_STRING_FIELD_ID);
+ StringReplacer* stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ CountMetric* countMetric = config.add_count_metric();
+ *countMetric = createCountMetric("TestCountMetric", config.atom_matcher(0).id() /* what */,
+ nullopt /* condition */, {} /* states */);
+ countMetric->mutable_dimensions_in_what()->set_field(util::TEST_ATOM_REPORTED);
+ countMetric->mutable_dimensions_in_what()->add_child()->set_field(
+ TEST_ATOM_REPORTED_STRING_FIELD_ID);
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ const int uid = 12345;
+ const int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
+ bucketStartTimeNs, bucketStartTimeNs, config, cfgKey, nullptr, 0, new UidMap());
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 20 * NS_PER_SEC,
+ "dimA" /* stringField */)); // 0:30
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 40 * NS_PER_SEC,
+ "dimA123" /* stringField */)); // 0:50
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 60 * NS_PER_SEC,
+ "dimA123B" /* stringField */)); // 1:10
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 80 * NS_PER_SEC,
+ "dimC0" /* stringField */)); // 1:20
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 90 * NS_PER_SEC,
+ "dimC00000" /* stringField */)); // 1:30
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 100 * NS_PER_SEC,
+ "dimC" /* stringField */)); // 1: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 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ ASSERT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ ASSERT_EQ(3, countMetrics.data_size());
+
+ CountMetricData data = countMetrics.data(0);
+ DimensionsValue dimValue = data.dimensions_in_what();
+ EXPECT_EQ(dimValue.field(), util::TEST_ATOM_REPORTED);
+ ASSERT_EQ(dimValue.value_tuple().dimensions_value_size(), 1);
+ EXPECT_EQ(dimValue.value_tuple().dimensions_value(0).field(),
+ TEST_ATOM_REPORTED_STRING_FIELD_ID);
+ EXPECT_EQ(dimValue.value_tuple().dimensions_value(0).value_str(), "dimA");
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+
+ data = countMetrics.data(1);
+ dimValue = data.dimensions_in_what();
+ EXPECT_EQ(dimValue.field(), util::TEST_ATOM_REPORTED);
+ ASSERT_EQ(dimValue.value_tuple().dimensions_value_size(), 1);
+ EXPECT_EQ(dimValue.value_tuple().dimensions_value(0).field(),
+ TEST_ATOM_REPORTED_STRING_FIELD_ID);
+ EXPECT_EQ(dimValue.value_tuple().dimensions_value(0).value_str(), "dimA123B");
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = countMetrics.data(2);
+ dimValue = data.dimensions_in_what();
+ EXPECT_EQ(dimValue.field(), util::TEST_ATOM_REPORTED);
+ ASSERT_EQ(dimValue.value_tuple().dimensions_value_size(), 1);
+ EXPECT_EQ(dimValue.value_tuple().dimensions_value(0).field(),
+ TEST_ATOM_REPORTED_STRING_FIELD_ID);
+ EXPECT_EQ(dimValue.value_tuple().dimensions_value(0).value_str(), "dimC");
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(3, data.bucket_info(0).count());
+}
+
+TEST(StringReplaceE2eTest, TestPushedWhat) {
+ StatsdConfig config = CreateStatsdConfig();
+
+ *config.add_atom_matcher() =
+ CreateSimpleAtomMatcher("TestAtomMatcher", util::TEST_ATOM_REPORTED);
+
+ FieldValueMatcher* fvm = config.mutable_atom_matcher(0)
+ ->mutable_simple_atom_matcher()
+ ->add_field_value_matcher();
+ fvm->set_field(TEST_ATOM_REPORTED_STRING_FIELD_ID);
+ StringReplacer* stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ *config.add_gauge_metric() = createGaugeMetric(
+ "TestAtomGaugeMetric", config.atom_matcher(0).id() /* what */,
+ GaugeMetric::FIRST_N_SAMPLES, nullopt /* condition */, nullopt /* triggerEvent */);
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000LL;
+ const int uid = 12345;
+ const int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
+ bucketStartTimeNs, bucketStartTimeNs, config, cfgKey, nullptr, 0, new UidMap());
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 20 * NS_PER_SEC,
+ "dimA" /* stringField */)); // 0:30
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 40 * NS_PER_SEC,
+ "dimA123" /* stringField */)); // 0:50
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 60 * NS_PER_SEC,
+ "dimA123B" /* stringField */)); // 1:10
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 80 * NS_PER_SEC,
+ "dimC0" /* stringField */)); // 1:20
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 90 * NS_PER_SEC,
+ "dimC00000" /* stringField */)); // 1:30
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 100 * NS_PER_SEC,
+ "dimC" /* stringField */)); // 1: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 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ ASSERT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ backfillAggregatedAtoms(&reports);
+
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_gauge_metrics());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ ASSERT_EQ(gaugeMetrics.data_size(), 1);
+
+ auto data = gaugeMetrics.data(0);
+ ASSERT_EQ(1, data.bucket_info_size());
+
+ ASSERT_EQ(6, data.bucket_info(0).atom_size());
+ EXPECT_EQ(data.bucket_info(0).atom(0).test_atom_reported().string_field(), "dimA");
+ EXPECT_EQ(data.bucket_info(0).atom(1).test_atom_reported().string_field(), "dimA");
+ EXPECT_EQ(data.bucket_info(0).atom(2).test_atom_reported().string_field(), "dimA123B");
+ EXPECT_EQ(data.bucket_info(0).atom(3).test_atom_reported().string_field(), "dimC");
+ EXPECT_EQ(data.bucket_info(0).atom(4).test_atom_reported().string_field(), "dimC");
+ EXPECT_EQ(data.bucket_info(0).atom(5).test_atom_reported().string_field(), "dimC");
+}
+
+TEST(StringReplaceE2eTest, TestPulledDimension) {
+ StatsdConfig config = CreateStatsdConfig();
+
+ *config.add_atom_matcher() =
+ CreateSimpleAtomMatcher("SubsystemMatcher", util::SUBSYSTEM_SLEEP_STATE);
+ FieldValueMatcher* fvm = config.mutable_atom_matcher(0)
+ ->mutable_simple_atom_matcher()
+ ->add_field_value_matcher();
+ fvm->set_field(SUBSYSTEM_SLEEP_STATE_SUBSYSTEM_NAME_FIELD_ID);
+ StringReplacer* stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ stringReplacer->set_replacement("");
+
+ *config.add_gauge_metric() = createGaugeMetric(
+ "SubsystemGaugeMetric", config.atom_matcher(0).id() /* what */,
+ GaugeMetric::RANDOM_ONE_SAMPLE, nullopt /* condition */, nullopt /* triggerEvent */);
+ *config.mutable_gauge_metric(0)->mutable_dimensions_in_what() =
+ CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
+
+ 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>(),
+ util::SUBSYSTEM_SLEEP_STATE);
+ processor->mPullerManager->ForceClearPullerCache();
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ processor->informPullAlarmFired(baseTimeNs + 2 * bucketSizeNs + 1);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 3 * bucketSizeNs + 10, 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);
+ backfillAggregatedAtoms(&reports);
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ ASSERT_EQ(gaugeMetrics.data_size(), 1);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+ ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(SUBSYSTEM_SLEEP_STATE_SUBSYSTEM_NAME_FIELD_ID,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+
+ // Trailing numbers are trimmed from the dimension: subsystem_name_# --> subsystem_name_
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "subsystem_name_");
+}
+
+TEST(StringReplaceE2eTest, TestPulledWhat) {
+ StatsdConfig config = CreateStatsdConfig();
+
+ *config.add_atom_matcher() =
+ CreateSimpleAtomMatcher("SubsystemMatcher", util::SUBSYSTEM_SLEEP_STATE);
+ FieldValueMatcher* fvm = config.mutable_atom_matcher(0)
+ ->mutable_simple_atom_matcher()
+ ->add_field_value_matcher();
+ fvm->set_field(SUBSYSTEM_SLEEP_STATE_SUBNAME_FIELD_ID);
+ StringReplacer* stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"(foo)");
+ stringReplacer->set_replacement("bar");
+
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
+
+ *config.add_predicate() = CreateScreenIsOffPredicate();
+
+ *config.add_gauge_metric() =
+ createGaugeMetric("SubsystemGaugeMetric", config.atom_matcher(0).id() /* what */,
+ GaugeMetric::RANDOM_ONE_SAMPLE,
+ config.predicate(0).id() /* condition */, nullopt /* triggerEvent */);
+
+ 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>(),
+ util::SUBSYSTEM_SLEEP_STATE);
+ processor->mPullerManager->ForceClearPullerCache();
+
+ 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(baseTimeNs + 2 * bucketSizeNs + 1);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 3 * bucketSizeNs + 10, 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);
+ backfillAggregatedAtoms(&reports);
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ ASSERT_EQ(gaugeMetrics.data_size(), 1);
+
+ auto data = gaugeMetrics.data(0);
+ ASSERT_EQ(2, data.bucket_info_size());
+
+ ASSERT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(data.bucket_info(0).atom(0).subsystem_sleep_state().subname(),
+ "subsystem_subname bar");
+
+ ASSERT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(data.bucket_info(1).atom(0).subsystem_sleep_state().subname(),
+ "subsystem_subname bar");
+}
+
+TEST(StringReplaceE2eTest, TestCondition) {
+ StatsdConfig config = CreateStatsdConfig();
+
+ AtomMatcher matcher = CreateStartScheduledJobAtomMatcher();
+ FieldValueMatcher* fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(SCHEDULED_JOB_STATE_CHANGED_JOB_NAME_FIELD_ID);
+ fvm->set_eq_string("foo");
+ StringReplacer* stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"(com.google.)");
+ stringReplacer->set_replacement("");
+ *config.add_atom_matcher() = matcher;
+ matcher = CreateFinishScheduledJobAtomMatcher();
+ fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(SCHEDULED_JOB_STATE_CHANGED_JOB_NAME_FIELD_ID);
+ fvm->set_eq_string("foo");
+ stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"(com.google.)");
+ stringReplacer->set_replacement("");
+ *config.add_atom_matcher() = matcher;
+
+ Predicate predicate = CreateScheduledJobPredicate();
+ *config.add_predicate() = predicate;
+
+ matcher = CreateSimpleAtomMatcher("TestAtomMatcher", util::TEST_ATOM_REPORTED);
+ *config.add_atom_matcher() = matcher;
+
+ CountMetric* countMetric = config.add_count_metric();
+ *countMetric = createCountMetric("TestCountMetric", matcher.id() /* what */,
+ predicate.id() /* condition */, {} /* states */);
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(countMetric->bucket()) * 1000000LL;
+ const int uid = 12345;
+ const int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
+ bucketStartTimeNs, bucketStartTimeNs, config, cfgKey, nullptr, 0, new UidMap());
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 20 * NS_PER_SEC,
+ {1001} /* uids */, {"App1"},
+ "com.google.job1")); // 0:30
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 30 * NS_PER_SEC,
+ "str" /* stringField */)); // 0:40
+ events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 40 * NS_PER_SEC,
+ {1002} /* uids */, {"App1"},
+ "com.google.foo")); // 0:50
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 50 * NS_PER_SEC,
+ "str" /* stringField */)); // 1:00
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 60 * NS_PER_SEC,
+ "str" /* stringField */)); // 1:10
+ events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 70 * NS_PER_SEC,
+ {1001} /* uids */, {"App1"},
+ "com.google.job1")); // 1:20
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 80 * NS_PER_SEC,
+ "str" /* stringField */)); // 1:30
+ events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 90 * NS_PER_SEC,
+ {1002} /* uids */, {"App1"},
+ "com.google.foo")); // 1:40
+ events.push_back(CreateTestAtomReportedEventStringDim(bucketStartTimeNs + 100 * NS_PER_SEC,
+ "str" /* stringField */)); // 1: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 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ ASSERT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ ASSERT_EQ(1, countMetrics.data_size());
+
+ CountMetricData data = countMetrics.data(0);
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(3, data.bucket_info(0).count());
+}
+
+TEST(StringReplaceE2eTest, TestDurationMetric) {
+ StatsdConfig config = CreateStatsdConfig();
+
+ AtomMatcher matcher = CreateAcquireWakelockAtomMatcher();
+ FieldValueMatcher* fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(ATTRIBUTION_CHAIN_FIELD_ID);
+ fvm->set_position(Position::FIRST);
+ fvm->mutable_matches_tuple()->add_field_value_matcher()->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ StringReplacer* stringReplacer =
+ fvm->mutable_matches_tuple()->mutable_field_value_matcher(0)->mutable_replace_string();
+ stringReplacer->set_regex(R"([0-9]+)");
+ stringReplacer->set_replacement("#");
+ *config.add_atom_matcher() = matcher;
+
+ matcher = CreateReleaseWakelockAtomMatcher();
+ fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(ATTRIBUTION_CHAIN_FIELD_ID);
+ fvm->set_position(Position::FIRST);
+ fvm->mutable_matches_tuple()->add_field_value_matcher()->set_field(ATTRIBUTION_TAG_FIELD_ID);
+ stringReplacer =
+ fvm->mutable_matches_tuple()->mutable_field_value_matcher(0)->mutable_replace_string();
+ stringReplacer->set_regex(R"([0-9]+)");
+ stringReplacer->set_replacement("#");
+ *config.add_atom_matcher() = matcher;
+
+ matcher = CreateMoveToBackgroundAtomMatcher();
+ fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(ACTIVITY_FOREGROUND_STATE_CHANGED_PKG_NAME_FIELD_ID);
+ stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([0-9]+)");
+ stringReplacer->set_replacement("#");
+ *config.add_atom_matcher() = matcher;
+
+ matcher = CreateMoveToForegroundAtomMatcher();
+ fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(ACTIVITY_FOREGROUND_STATE_CHANGED_PKG_NAME_FIELD_ID);
+ stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"([0-9]+)");
+ stringReplacer->set_replacement("#");
+ *config.add_atom_matcher() = matcher;
+
+ Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ // The predicate is dimensioning by first attribution node by uid and tag.
+ *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateAttributionUidAndTagDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ Predicate isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+ *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED,
+ {ACTIVITY_FOREGROUND_STATE_CHANGED_UID_FIELD_ID,
+ ACTIVITY_FOREGROUND_STATE_CHANGED_PKG_NAME_FIELD_ID});
+ *config.add_predicate() = isInBackgroundPredicate;
+
+ DurationMetric durationMetric =
+ createDurationMetric("WakelockDuration", holdingWakelockPredicate.id() /* what */,
+ isInBackgroundPredicate.id() /* condition */, {} /* states */);
+ *durationMetric.mutable_dimensions_in_what() =
+ CreateAttributionUidAndTagDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ durationMetric.set_bucket(FIVE_MINUTES);
+ *config.add_duration_metric() = durationMetric;
+
+ // Links between wakelock state atom and condition of app is in background.
+ MetricConditionLink* link = durationMetric.add_links();
+ link->set_condition(isInBackgroundPredicate.id());
+ *link->mutable_fields_in_what() =
+ CreateAttributionUidAndTagDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *link->mutable_fields_in_condition() =
+ CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED,
+ {ACTIVITY_FOREGROUND_STATE_CHANGED_UID_FIELD_ID,
+ ACTIVITY_FOREGROUND_STATE_CHANGED_PKG_NAME_FIELD_ID});
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(durationMetric.bucket()) * 1000000LL;
+ const int uid = 12345;
+ const int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
+ bucketStartTimeNs, bucketStartTimeNs, config, cfgKey, nullptr, 0, new UidMap());
+
+ int appUid = 123;
+ std::vector<int> attributionUids1 = {appUid};
+ std::vector<string> attributionTags1 = {"App1"};
+ std::vector<string> attributionTags2 = {"App2"};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
+ attributionUids1, attributionTags1,
+ "wl1")); // 0:10
+ events.push_back(CreateActivityForegroundStateChangedEvent(
+ bucketStartTimeNs + 22 * NS_PER_SEC, appUid, "App1", "class_name",
+ ActivityForegroundStateChanged::BACKGROUND)); // 0:22
+ events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 60 * NS_PER_SEC,
+ attributionUids1, attributionTags1,
+ "wl1")); // 1:00
+ events.push_back(CreateActivityForegroundStateChangedEvent(
+ bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC, appUid, "App1", "class_name",
+ ActivityForegroundStateChanged::FOREGROUND)); // 3:15
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + (3 * 60 + 20) * NS_PER_SEC,
+ attributionUids1, attributionTags2,
+ "wl2")); // 3:20
+ events.push_back(CreateActivityForegroundStateChangedEvent(
+ bucketStartTimeNs + (3 * 60 + 30) * NS_PER_SEC, appUid, "App1", "class_name",
+ ActivityForegroundStateChanged::BACKGROUND)); // 3:30
+ events.push_back(CreateActivityForegroundStateChangedEvent(
+ bucketStartTimeNs + (3 * 60 + 40) * NS_PER_SEC, appUid, "App2", "class_name",
+ ActivityForegroundStateChanged::FOREGROUND)); // 3:40
+ events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + (3 * 60 + 50) * NS_PER_SEC,
+ attributionUids1, attributionTags2,
+ "wl2")); // 3:50
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+
+ ASSERT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(1, reports.reports(0).metrics_size());
+ ASSERT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+ StatsLogReport::DurationMetricDataWrapper durationMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
+ &durationMetrics);
+ ASSERT_EQ(1, durationMetrics.data_size());
+
+ DurationMetricData data = durationMetrics.data(0);
+ // Validate dimension value.
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ appUid, "App#");
+ // Validate bucket info.
+ ASSERT_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(48 * NS_PER_SEC, bucketInfo.duration_nanos());
+}
+
+TEST(StringReplaceE2eTest, TestMultipleMatchersForAtom) {
+ StatsdConfig config = CreateStatsdConfig();
+
+ {
+ AtomMatcher matcher = CreateSimpleAtomMatcher("Matcher1", util::SUBSYSTEM_SLEEP_STATE);
+ FieldValueMatcher* fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(SUBSYSTEM_SLEEP_STATE_SUBSYSTEM_NAME_FIELD_ID);
+ fvm->set_eq_string("subsystem_name_1");
+ fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(SUBSYSTEM_SLEEP_STATE_SUBNAME_FIELD_ID);
+ fvm->set_eq_string("subsystem_subname bar");
+ StringReplacer* stringReplacer = fvm->mutable_replace_string();
+ stringReplacer->set_regex(R"(foo)");
+ stringReplacer->set_replacement("bar");
+ *config.add_atom_matcher() = matcher;
+
+ *config.add_value_metric() =
+ createValueMetric("Value1", matcher, SUBSYSTEM_SLEEP_STATE_TIME_MILLIS_FIELD_ID,
+ nullopt /* condition */, {} /* states */);
+ }
+ {
+ AtomMatcher matcher = CreateSimpleAtomMatcher("Matcher2", util::SUBSYSTEM_SLEEP_STATE);
+ FieldValueMatcher* fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(SUBSYSTEM_SLEEP_STATE_SUBSYSTEM_NAME_FIELD_ID);
+ fvm->set_eq_string("subsystem_name_2");
+ fvm = matcher.mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(SUBSYSTEM_SLEEP_STATE_SUBNAME_FIELD_ID);
+ fvm->set_eq_string("subsystem_subname foo");
+ *config.add_atom_matcher() = matcher;
+
+ *config.add_value_metric() =
+ createValueMetric("Value2", matcher, SUBSYSTEM_SLEEP_STATE_TIME_MILLIS_FIELD_ID,
+ nullopt /* condition */, {} /* states */);
+ }
+
+ 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>(),
+ util::SUBSYSTEM_SLEEP_STATE);
+ processor->mPullerManager->ForceClearPullerCache();
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ processor->informPullAlarmFired(baseTimeNs + 2 * bucketSizeNs + 1);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 3 * bucketSizeNs + 10, 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);
+ backfillAggregatedAtoms(&reports);
+ ASSERT_EQ(1, reports.reports_size());
+ ASSERT_EQ(2, reports.reports(0).metrics_size());
+
+ {
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(),
+ &valueMetrics);
+ ASSERT_EQ(valueMetrics.data_size(), 1);
+
+ ValueMetricData data = valueMetrics.data(0);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ ASSERT_EQ(data.bucket_info(0).values_size(), 1);
+ }
+ {
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(1).value_metrics(),
+ &valueMetrics);
+ ASSERT_EQ(valueMetrics.data_size(), 1);
+
+ ValueMetricData data = valueMetrics.data(0);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ ASSERT_EQ(data.bucket_info(0).values_size(), 1);
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp b/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
index 7b12a36..21ddb26 100644
--- a/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
+++ b/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
@@ -1985,6 +1985,313 @@
EXPECT_EQ(kllProducer->mDimensionHardLimit, actualLimit);
}
+TEST_F(MetricsManagerUtilTest, TestMissingValueMatcherAndStringReplacer) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(SCREEN_STATE_ATOM_ID);
+ matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_NE(actualInvalidConfigReason, nullopt);
+ EXPECT_EQ(actualInvalidConfigReason->reason,
+ INVALID_CONFIG_REASON_MATCHER_NO_VALUE_MATCHER_NOR_STRING_REPLACER);
+ EXPECT_THAT(actualInvalidConfigReason->matcherIds, ElementsAre(111));
+}
+
+TEST_F(MetricsManagerUtilTest, TestMatcherWithValueMatcherOnly) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(SCREEN_STATE_ATOM_ID);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(2 /*int_field*/);
+ fvm->set_eq_int(1);
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_EQ(actualInvalidConfigReason, nullopt);
+}
+
+TEST_F(MetricsManagerUtilTest, TestMatcherWithStringReplacerOnly) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(SCREEN_STATE_ATOM_ID);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(5 /*string_field*/);
+ fvm->mutable_replace_string()->set_regex(R"([\d]+$)");
+ fvm->mutable_replace_string()->set_replacement("#");
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_EQ(actualInvalidConfigReason, nullopt);
+}
+
+TEST_F(MetricsManagerUtilTest, TestValueMatcherWithPositionAll) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(9 /*repeated_int_field*/);
+ fvm->set_position(Position::ALL);
+ fvm->set_eq_int(1);
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_NE(actualInvalidConfigReason, nullopt);
+ EXPECT_EQ(actualInvalidConfigReason->reason,
+ INVALID_CONFIG_REASON_MATCHER_VALUE_MATCHER_WITH_POSITION_ALL);
+ EXPECT_THAT(actualInvalidConfigReason->matcherIds, ElementsAre(111));
+}
+
+TEST_F(MetricsManagerUtilTest, TestValueMatcherAndStringReplaceWithPositionAll) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(12 /*repeated_string_field*/);
+ fvm->set_position(Position::ALL);
+ fvm->set_eq_string("foo");
+ fvm->mutable_replace_string()->set_regex(R"([\d]+$)");
+ fvm->mutable_replace_string()->set_replacement("");
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_NE(actualInvalidConfigReason, nullopt);
+ EXPECT_EQ(actualInvalidConfigReason->reason,
+ INVALID_CONFIG_REASON_MATCHER_VALUE_MATCHER_WITH_POSITION_ALL);
+ EXPECT_THAT(actualInvalidConfigReason->matcherIds, ElementsAre(111));
+}
+
+TEST_F(MetricsManagerUtilTest, TestValueMatcherWithPositionAllNested) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ // Match on attribution_node[ALL].uid = 1
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(1 /*attribution_node*/);
+ fvm->set_position(Position::ALL);
+ fvm->mutable_matches_tuple()->add_field_value_matcher()->set_field(1 /* uid */);
+ fvm->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_int(1);
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_NE(actualInvalidConfigReason, nullopt);
+ EXPECT_EQ(actualInvalidConfigReason->reason,
+ INVALID_CONFIG_REASON_MATCHER_VALUE_MATCHER_WITH_POSITION_ALL);
+ EXPECT_THAT(actualInvalidConfigReason->matcherIds, ElementsAre(111));
+}
+
+TEST_F(MetricsManagerUtilTest, TestValueMatcherAndStringReplaceWithPositionAllNested) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ // Match on attribution_node[ALL].uid = 1
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(1 /*attribution_node*/);
+ fvm->set_position(Position::ALL);
+ fvm->mutable_matches_tuple()->add_field_value_matcher()->set_field(2 /* tag */);
+ fvm->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string("foo");
+ fvm->mutable_matches_tuple()
+ ->mutable_field_value_matcher(0)
+ ->mutable_replace_string()
+ ->set_regex(R"([\d]+$)");
+ fvm->mutable_matches_tuple()
+ ->mutable_field_value_matcher(0)
+ ->mutable_replace_string()
+ ->set_replacement("");
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_NE(actualInvalidConfigReason, nullopt);
+ EXPECT_EQ(actualInvalidConfigReason->reason,
+ INVALID_CONFIG_REASON_MATCHER_VALUE_MATCHER_WITH_POSITION_ALL);
+ EXPECT_THAT(actualInvalidConfigReason->matcherIds, ElementsAre(111));
+}
+
+TEST_F(MetricsManagerUtilTest, TestStringReplaceWithNoValueMatcherWithPositionAny) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(12 /*repeated_string_field*/);
+ fvm->set_position(Position::ANY);
+ fvm->mutable_replace_string()->set_regex(R"([\d]+$)");
+ fvm->mutable_replace_string()->set_replacement("");
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_NE(actualInvalidConfigReason, nullopt);
+ EXPECT_EQ(actualInvalidConfigReason->reason,
+ INVALID_CONFIG_REASON_MATCHER_STRING_REPLACE_WITH_NO_VALUE_MATCHER_WITH_POSITION_ANY);
+ EXPECT_THAT(actualInvalidConfigReason->matcherIds, ElementsAre(111));
+}
+
+TEST_F(MetricsManagerUtilTest, TestStringReplaceWithNoValueMatcherWithPositionAnyNested) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ // Match on attribution_node[ALL].uid = 1
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(1 /*attribution_node*/);
+ fvm->set_position(Position::ANY);
+ fvm->mutable_matches_tuple()->add_field_value_matcher()->set_field(2 /* tag */);
+ fvm->mutable_matches_tuple()
+ ->mutable_field_value_matcher(0)
+ ->mutable_replace_string()
+ ->set_regex(R"([\d]+$)");
+ fvm->mutable_matches_tuple()
+ ->mutable_field_value_matcher(0)
+ ->mutable_replace_string()
+ ->set_replacement("");
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_NE(actualInvalidConfigReason, nullopt);
+ EXPECT_EQ(actualInvalidConfigReason->reason,
+ INVALID_CONFIG_REASON_MATCHER_STRING_REPLACE_WITH_NO_VALUE_MATCHER_WITH_POSITION_ANY);
+ EXPECT_THAT(actualInvalidConfigReason->matcherIds, ElementsAre(111));
+}
+
+TEST_F(MetricsManagerUtilTest, TestStringReplaceWithValueMatcherWithPositionAny) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(12 /*repeated_string_field*/);
+ fvm->set_position(Position::ANY);
+ fvm->set_eq_string("bar");
+ fvm->mutable_replace_string()->set_regex(R"([\d]+$)");
+ fvm->mutable_replace_string()->set_replacement("");
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_EQ(actualInvalidConfigReason, nullopt);
+}
+
+TEST_F(MetricsManagerUtilTest, TestStringReplaceWithValueMatcherWithPositionAnyNested) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ // Match on attribution_node[ALL].uid = 1
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(1 /*attribution_node*/);
+ fvm->set_position(Position::ANY);
+ fvm->mutable_matches_tuple()->add_field_value_matcher()->set_field(2 /* tag */);
+ fvm->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string("bar");
+ fvm->mutable_matches_tuple()
+ ->mutable_field_value_matcher(0)
+ ->mutable_replace_string()
+ ->set_regex(R"([\d]+$)");
+ fvm->mutable_matches_tuple()
+ ->mutable_field_value_matcher(0)
+ ->mutable_replace_string()
+ ->set_replacement("");
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_EQ(actualInvalidConfigReason, nullopt);
+}
+
+TEST_F(MetricsManagerUtilTest, TestStringReplaceWithPositionAllNested) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ // Replace attribution_node[ALL].tag using "[\d]+$" -> "".
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(1 /*attribution_node*/);
+ fvm->set_position(Position::ALL);
+ fvm = fvm->mutable_matches_tuple()->add_field_value_matcher();
+ fvm->set_field(2 /* tag */);
+ fvm->mutable_replace_string()->set_regex(R"([\d]+$)");
+ fvm->mutable_replace_string()->set_replacement("");
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_EQ(actualInvalidConfigReason, nullopt);
+}
+
+TEST_F(MetricsManagerUtilTest, TestMatcherWithStringReplaceAndNonStringValueMatcher) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(2 /*int_field*/);
+ fvm->set_eq_int(1);
+ fvm->mutable_replace_string()->set_regex(R"([\d]+$)");
+ fvm->mutable_replace_string()->set_replacement("#");
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_NE(actualInvalidConfigReason, nullopt);
+ EXPECT_EQ(actualInvalidConfigReason->reason,
+ INVALID_CONFIG_REASON_MATCHER_INVALID_VALUE_MATCHER_WITH_STRING_REPLACE);
+ EXPECT_THAT(actualInvalidConfigReason->matcherIds, ElementsAre(111));
+}
+
+TEST_F(MetricsManagerUtilTest, TestCombinationMatcherWithStringReplace) {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* matcher = config.add_atom_matcher();
+ matcher->set_id(111);
+ matcher->mutable_simple_atom_matcher()->set_atom_id(util::TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = matcher->mutable_simple_atom_matcher()->add_field_value_matcher();
+ fvm->set_field(5 /*string_field*/);
+ fvm->mutable_replace_string()->set_regex(R"([\d]+$)");
+ fvm->mutable_replace_string()->set_replacement("#");
+
+ matcher = config.add_atom_matcher();
+ matcher->set_id(222);
+ matcher->mutable_combination()->set_operation(LogicalOperation::NOT);
+ matcher->mutable_combination()->add_matcher(111);
+
+ optional<InvalidConfigReason> actualInvalidConfigReason = initConfig(config);
+
+ ASSERT_NE(actualInvalidConfigReason, nullopt);
+ EXPECT_EQ(actualInvalidConfigReason->reason,
+ INVALID_CONFIG_REASON_MATCHER_COMBINATION_WITH_STRING_REPLACE);
+ EXPECT_THAT(actualInvalidConfigReason->matcherIds, ElementsAre(222));
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/statsd/tests/shell/ShellSubscriber_test.cpp b/statsd/tests/shell/ShellSubscriber_test.cpp
index a06f76f..4bd032e 100644
--- a/statsd/tests/shell/ShellSubscriber_test.cpp
+++ b/statsd/tests/shell/ShellSubscriber_test.cpp
@@ -222,7 +222,7 @@
TestAtomReported t;
auto* attributionNode = t.add_attribution_node();
attributionNode->set_uid(1001);
- attributionNode->set_tag("app1");
+ attributionNode->set_tag("app"); // String transformation removes trailing digits.
t.set_int_field(intFieldValue);
t.set_long_field(0);
t.set_float_field(0.0f);
@@ -252,6 +252,15 @@
ShellSubscription config;
config.add_pushed()->set_atom_id(TEST_ATOM_REPORTED);
+ FieldValueMatcher* fvm = config.mutable_pushed(0)->add_field_value_matcher();
+ fvm->set_field(1); // attribution_chain
+ fvm->set_position(Position::FIRST);
+ fvm = fvm->mutable_matches_tuple()->add_field_value_matcher();
+ fvm->set_field(2); // tag field
+ fvm->mutable_replace_string()->set_regex(
+ R"([\d]+$)"); // match trailing digits, example "42" in "foo42".
+ fvm->mutable_replace_string()->set_replacement("");
+
config.add_pushed()->set_atom_id(SCREEN_STATE_CHANGED);
config.add_pushed()->set_atom_id(PHONE_SIGNAL_STRENGTH_CHANGED);
configBytes = protoToBytes(config);
diff --git a/statsd/tests/statsd_test_util.cpp b/statsd/tests/statsd_test_util.cpp
index 084fb2f..8e80a20 100644
--- a/statsd/tests/statsd_test_util.cpp
+++ b/statsd/tests/statsd_test_util.cpp
@@ -1079,6 +1079,18 @@
repeatedBoolFieldLength, repeatedEnumField);
}
+std::unique_ptr<LogEvent> CreateTestAtomReportedEventWithPrimitives(
+ uint64_t timestampNs, int intField, long longField, float floatField,
+ const string& stringField, bool boolField, TestAtomReported::State enumField) {
+ return CreateTestAtomReportedEvent(
+ timestampNs, /* attributionUids */ {1001},
+ /* attributionTags */ {"app1"}, intField, longField, floatField, stringField, boolField,
+ enumField, /* bytesField */ {},
+ /* repeatedIntField */ {}, /* repeatedLongField */ {}, /* repeatedFloatField */ {},
+ /* repeatedStringField */ {}, /* repeatedBoolField */ {},
+ /* repeatedBoolFieldLength */ 0, /* repeatedEnumField */ {});
+}
+
std::unique_ptr<LogEvent> CreateTestAtomReportedEvent(
uint64_t timestampNs, const vector<int>& attributionUids,
const vector<string>& attributionTags, const int intField, const long longField,
@@ -1160,14 +1172,15 @@
}
std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
- uint64_t timestampNs, const int uid, const ActivityForegroundStateChanged::State state) {
+ uint64_t timestampNs, const int uid, const string& pkgName, const string& className,
+ const ActivityForegroundStateChanged::State state) {
AStatsEvent* statsEvent = AStatsEvent_obtain();
AStatsEvent_setAtomId(statsEvent, util::ACTIVITY_FOREGROUND_STATE_CHANGED);
AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
AStatsEvent_writeInt32(statsEvent, uid);
- AStatsEvent_writeString(statsEvent, "pkg_name");
- AStatsEvent_writeString(statsEvent, "class_name");
+ AStatsEvent_writeString(statsEvent, pkgName.c_str());
+ AStatsEvent_writeString(statsEvent, className.c_str());
AStatsEvent_writeInt32(statsEvent, state);
std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
@@ -1176,12 +1189,12 @@
}
std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid) {
- return CreateActivityForegroundStateChangedEvent(timestampNs, uid,
+ return CreateActivityForegroundStateChangedEvent(timestampNs, uid, "pkg_name", "class_name",
ActivityForegroundStateChanged::BACKGROUND);
}
std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid) {
- return CreateActivityForegroundStateChangedEvent(timestampNs, uid,
+ return CreateActivityForegroundStateChangedEvent(timestampNs, uid, "pkg_name", "class_name",
ActivityForegroundStateChanged::FOREGROUND);
}
diff --git a/statsd/tests/statsd_test_util.h b/statsd/tests/statsd_test_util.h
index ca38944..43d9c7d 100644
--- a/statsd/tests/statsd_test_util.h
+++ b/statsd/tests/statsd_test_util.h
@@ -477,6 +477,10 @@
// Create malformed log event for battery state change.
std::unique_ptr<LogEvent> CreateMalformedBatteryStateChangedEvent(const uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
+ uint64_t timestampNs, const int uid, const string& pkgName, const string& className,
+ const ActivityForegroundStateChanged::State state);
+
// Create log event for app moving to background.
std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid);
@@ -543,6 +547,10 @@
const vector<string>& repeatedStringField, const bool* repeatedBoolField,
const size_t repeatedBoolFieldLength, const vector<int>& repeatedEnumField);
+std::unique_ptr<LogEvent> CreateTestAtomReportedEventWithPrimitives(
+ uint64_t timestampNs, int intField, long longField, float floatField,
+ const string& stringField, bool boolField, TestAtomReported::State enumField);
+
std::unique_ptr<LogEvent> CreateRestrictedLogEvent(int atomTag, int64_t timestampNs = 0);
std::unique_ptr<LogEvent> CreateNonRestrictedLogEvent(int atomTag, int64_t timestampNs = 0);