1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Log.h"
18
19#include "CombinationLogMatchingTracker.h"
20#include "matchers/matcher_util.h"
21
22namespace android {
23namespace os {
24namespace statsd {
25
26using std::set;
27using std::string;
28using std::unique_ptr;
29using std::unordered_map;
30using std::vector;
31
32CombinationLogMatchingTracker::CombinationLogMatchingTracker(const int64_t& id, const int index)
33    : LogMatchingTracker(id, index) {
34}
35
36CombinationLogMatchingTracker::~CombinationLogMatchingTracker() {
37}
38
39bool CombinationLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatchers,
40                                         const vector<sp<LogMatchingTracker>>& allTrackers,
41                                         const unordered_map<int64_t, int>& matcherMap,
42                                         vector<bool>& stack) {
43    if (mInitialized) {
44        return true;
45    }
46
47    // mark this node as visited in the recursion stack.
48    stack[mIndex] = true;
49
50    AtomMatcher_Combination matcher = allLogMatchers[mIndex].combination();
51
52    // LogicalOperation is missing in the config
53    if (!matcher.has_operation()) {
54        return false;
55    }
56
57    mLogicalOperation = matcher.operation();
58
59    if (mLogicalOperation == LogicalOperation::NOT && matcher.matcher_size() != 1) {
60        return false;
61    }
62
63    for (const auto& child : matcher.matcher()) {
64        auto pair = matcherMap.find(child);
65        if (pair == matcherMap.end()) {
66            ALOGW("Matcher %lld not found in the config", (long long)child);
67            return false;
68        }
69
70        int childIndex = pair->second;
71
72        // if the child is a visited node in the recursion -> circle detected.
73        if (stack[childIndex]) {
74            ALOGE("Circle detected in matcher config");
75            return false;
76        }
77
78        if (!allTrackers[childIndex]->init(allLogMatchers, allTrackers, matcherMap, stack)) {
79            ALOGW("child matcher init failed %lld", (long long)child);
80            return false;
81        }
82
83        mChildren.push_back(childIndex);
84
85        const set<int>& childTagIds = allTrackers[childIndex]->getAtomIds();
86        mAtomIds.insert(childTagIds.begin(), childTagIds.end());
87    }
88
89    mInitialized = true;
90    // unmark this node in the recursion stack.
91    stack[mIndex] = false;
92    return true;
93}
94
95void CombinationLogMatchingTracker::onLogEvent(const LogEvent& event,
96                                               const vector<sp<LogMatchingTracker>>& allTrackers,
97                                               vector<MatchingState>& matcherResults) {
98    // this event has been processed.
99    if (matcherResults[mIndex] != MatchingState::kNotComputed) {
100        return;
101    }
102
103    if (mAtomIds.find(event.GetTagId()) == mAtomIds.end()) {
104        matcherResults[mIndex] = MatchingState::kNotMatched;
105        return;
106    }
107
108    // evaluate children matchers if they haven't been evaluated.
109    for (const int childIndex : mChildren) {
110        if (matcherResults[childIndex] == MatchingState::kNotComputed) {
111            const sp<LogMatchingTracker>& child = allTrackers[childIndex];
112            child->onLogEvent(event, allTrackers, matcherResults);
113        }
114    }
115
116    bool matched = combinationMatch(mChildren, mLogicalOperation, matcherResults);
117    matcherResults[mIndex] = matched ? MatchingState::kMatched : MatchingState::kNotMatched;
118}
119
120}  // namespace statsd
121}  // namespace os
122}  // namespace android
123