Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dd89694f authored by David Chen's avatar David Chen
Browse files

Adds new utility functions for evaluating log entry matching.

Includes matching for both simple and compound matchers.

Change-Id: Id913d2625d205ad9a529019e98ae805f730f4d48
Test: Added new unit-tests and checked on marlin device.
parent 2ffb3081
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ LOCAL_SRC_FILES := \
    src/statsd_config.proto \
    src/stats_constants.proto \
    src/DropboxReader.cpp \
    src/matchers/LogEntryMatcherManager.cpp \


LOCAL_CFLAGS += \
@@ -107,6 +108,9 @@ LOCAL_MODULE := statsd_test
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests

LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \
	STATSD_PROTO_INCLUDES

LOCAL_CFLAGS += \
    -Wall \
    -Werror \
@@ -115,21 +119,24 @@ LOCAL_CFLAGS += \
    -Wno-unused-function \
    -Wno-unused-parameter

LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \
	STATSD_PROTO_INCLUDES

LOCAL_SRC_FILES := \
    src/stats_log.proto \
    src/statsd_config.proto \
    src/stats_constants.proto \
    ../../core/java/android/os/IStatsCompanionService.aidl \
    ../../core/java/android/os/IStatsManager.aidl \
    src/StatsService.cpp \
    tests/indexed_priority_queue_test.cpp \
    src/parse_util.cpp \
    src/LogEntryPrinter.cpp \
    src/LogReader.cpp \
    src/matchers/LogEntryMatcherManager.cpp \
    tests/LogReader_test.cpp \
    tests/LogEntryMatcher_test.cpp \

LOCAL_STATIC_LIBRARIES := \
    libgmock \
    statsd_proto
    statsd_proto \

LOCAL_SHARED_LIBRARIES := \
    libbase \
+182 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "LogEntryMatcherManager.h"
#include <log/event_tag_map.h>
#include <log/logprint.h>
#include <utils/Errors.h>
#include <cutils/log.h>
#include <unordered_map>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>

using std::unordered_map;
using std::string;

namespace android {
namespace os {
namespace statsd {

bool LogEntryMatcherManager::matches(const LogEntryMatcher &matcher, const int tagId,
                                     const unordered_map<int, long> &intMap,
                                     const unordered_map<int, string> &strMap,
                                     const unordered_map<int, float> &floatMap,
                                     const unordered_map<int, bool> &boolMap) {
    if (matcher.has_combination()) { // Need to evaluate composite matching
        switch (matcher.combination().operation()) {
            case LogicalOperation::AND:
                for (auto nestedMatcher : matcher.combination().matcher()) {
                    if (!matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) {
                        return false; // return false if any nested matcher is false;
                    }
                }
                return true; // Otherwise, return true.
            case LogicalOperation::OR:
                for (auto nestedMatcher : matcher.combination().matcher()) {
                    if (matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) {
                        return true; // return true if any nested matcher is true;
                    }
                }
                return false;
            case LogicalOperation::NOT:
                return !matches(matcher.combination().matcher(0),  tagId, intMap, strMap, floatMap,
                                boolMap);

            // Case NAND is just inverting the return statement of AND
            case LogicalOperation::NAND:
                for (auto nestedMatcher : matcher.combination().matcher()) {
                    auto simple = nestedMatcher.simple_log_entry_matcher();
                    if (!matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) {
                        return true; // return false if any nested matcher is false;
                    }
                }
                return false; // Otherwise, return true.
            case LogicalOperation::NOR:
                for (auto nestedMatcher : matcher.combination().matcher()) {
                    if (matches(nestedMatcher, tagId, intMap, strMap, floatMap, boolMap)) {
                        return false; // return true if any nested matcher is true;
                    }
                }
                return true;
        }
        return false;
    } else {
        return matchesSimple(matcher.simple_log_entry_matcher(), tagId, intMap, strMap, floatMap,
                             boolMap);
    }
}

bool LogEntryMatcherManager::matchesSimple(const SimpleLogEntryMatcher &simpleMatcher,
                                           const int tagId,
                                           const unordered_map<int, long> &intMap,
                                           const unordered_map<int, string> &strMap,
                                           const unordered_map<int, float> &floatMap,
                                           const unordered_map<int, bool> &boolMap) {
    for (int i = 0; i < simpleMatcher.tag_size(); i++) {
        if (simpleMatcher.tag(i) != tagId) {
            continue;
        }

        // now see if this event is interesting to us -- matches ALL the matchers
        // defined in the metrics.
        bool allMatched = true;
        for (int j = 0; j < simpleMatcher.key_value_matcher_size(); j++) {
            auto cur = simpleMatcher.key_value_matcher(j);

            // TODO: Check if this key is a magic key (eg package name).
            int key = cur.key_matcher().key();

            switch (cur.value_matcher_case()) {
                case KeyValueMatcher::ValueMatcherCase::kEqString: {
                    auto it = strMap.find(key);
                    if (it == strMap.end() || cur.eq_string().compare(it->second) != 0) {
                        allMatched = false;
                    }
                    break;
                }
                case KeyValueMatcher::ValueMatcherCase::kEqInt: {
                    auto it = intMap.find(key);
                    if (it == intMap.end() || cur.eq_int() != it->second) {
                        allMatched = false;
                    }
                    break;
                }
                case KeyValueMatcher::ValueMatcherCase::kEqBool: {
                    auto it = boolMap.find(key);
                    if (it == boolMap.end() || cur.eq_bool() != it->second) {
                        allMatched = false;
                    }
                    break;
                }
                    // Begin numeric comparisons
                case KeyValueMatcher::ValueMatcherCase::kLtInt: {
                    auto it = intMap.find(key);
                    if (it == intMap.end() || cur.lt_int() <= it->second) {
                        allMatched = false;
                    }
                    break;
                }
                case KeyValueMatcher::ValueMatcherCase::kGtInt: {
                    auto it = intMap.find(key);
                    if (it == intMap.end() || cur.gt_int() >= it->second) {
                        allMatched = false;
                    }
                    break;
                }
                case KeyValueMatcher::ValueMatcherCase::kLtFloat: {
                    auto it = floatMap.find(key);
                    if (it == floatMap.end() || cur.lt_float() <= it->second) {
                        allMatched = false;
                    }
                    break;
                }
                case KeyValueMatcher::ValueMatcherCase::kGtFloat: {
                    auto it = floatMap.find(key);
                    if (it == floatMap.end() || cur.gt_float() >= it->second) {
                        allMatched = false;
                    }
                    break;
                }
                // Begin comparisons with equality
                case KeyValueMatcher::ValueMatcherCase::kLteInt: {
                    auto it = intMap.find(key);
                    if (it == intMap.end() || cur.lte_int() < it->second) {
                        allMatched = false;
                    }
                    break;
                }
                case KeyValueMatcher::ValueMatcherCase::kGteInt: {
                    auto it = intMap.find(key);
                    if (it == intMap.end() || cur.gte_int() > it->second) {
                        allMatched = false;
                    }
                    break;
                }
                case KeyValueMatcher::ValueMatcherCase::VALUE_MATCHER_NOT_SET:
                    // If value matcher is not present, assume that we match.
                    break;
            }
        }

        if (allMatched) {
            return true;
        }
    }
    return false;
}

} // namespace statsd
} // namespace os
} // namespace android
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef LOG_ENTRY_MATCHER_MANAGER_H
#define LOG_ENTRY_MATCHER_MANAGER_H

#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include <log/logprint.h>
#include <log/log_read.h>
#include <set>
#include <vector>
#include <unordered_map>

using std::unordered_map;
using std::string;

namespace android {
namespace os {
namespace statsd {

/**
 * Keeps track per log entry which simple log entry matchers match.
 */
class LogEntryMatcherManager {
public:
    LogEntryMatcherManager();

    ~LogEntryMatcherManager() {};

    static bool matches(const LogEntryMatcher &matcher, const int tagId,
                        const unordered_map<int, long> &intMap,
                        const unordered_map<int, string> &strMap,
                        const unordered_map<int, float> &floatMap,
                        const unordered_map<int, bool> &boolMap);

    static bool matchesSimple(const SimpleLogEntryMatcher &simpleMatcher,
                              const int tagId,
                              const unordered_map<int, long> &intMap,
                              const unordered_map<int, string> &strMap,
                              const unordered_map<int, float> &floatMap,
                              const unordered_map<int, bool> &boolMap);
};

} // namespace statsd
} // namespace os
} // namespace android
#endif //LOG_ENTRY_MATCHER_MANAGER_H
+11 −8
Original line number Diff line number Diff line
@@ -19,14 +19,17 @@ message KeyValueMatcher {
  oneof value_matcher {
    bool eq_bool = 2;
    string eq_string = 3;
    int32 eq_int32 = 4;
    int64 eq_int64 = 5;
    int32 lt_int32 = 6;
    int32 gt_int32 = 7;
    int64 lt_int64 = 8;
    int64 gt_int64 = 9;
    float lt_float = 10;
    float gt_float = 11;
    int32 eq_int = 4;

    // Numeric comparisons. Lt means strictly less than.
    int64 lt_int = 5;
    int64 gt_int = 6;
    float lt_float = 7;
    float gt_float = 8;

    // Numeric comparisons with equality. Lte means less than or equal.
    int64 lte_int = 9;
    int64 gte_int = 10;
  }
}

+366 −0

File added.

Preview size limit exceeded, changes collapsed.