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