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 "CombinationAtomMatchingTracker.h" 20 21 #include "matchers/matcher_util.h" 22 23 namespace android { 24 namespace os { 25 namespace statsd { 26 27 using std::set; 28 using std::unordered_map; 29 using std::vector; 30 31 CombinationAtomMatchingTracker::CombinationAtomMatchingTracker(const int64_t& id, const int index, 32 const uint64_t protoHash) 33 : AtomMatchingTracker(id, index, protoHash) { 34 } 35 36 CombinationAtomMatchingTracker::~CombinationAtomMatchingTracker() { 37 } 38 39 bool CombinationAtomMatchingTracker::init( 40 const vector<AtomMatcher>& allAtomMatchers, 41 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, 42 const unordered_map<int64_t, int>& matcherMap, 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 = allAtomMatchers[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 (!allAtomMatchingTrackers[childIndex]->init(allAtomMatchers, allAtomMatchingTrackers, 79 matcherMap, stack)) { 80 ALOGW("child matcher init failed %lld", (long long)child); 81 return false; 82 } 83 84 mChildren.push_back(childIndex); 85 86 const set<int>& childTagIds = allAtomMatchingTrackers[childIndex]->getAtomIds(); 87 mAtomIds.insert(childTagIds.begin(), childTagIds.end()); 88 } 89 90 mInitialized = true; 91 // unmark this node in the recursion stack. 92 stack[mIndex] = false; 93 return true; 94 } 95 96 bool CombinationAtomMatchingTracker::onConfigUpdated( 97 const AtomMatcher& matcher, const int index, 98 const unordered_map<int64_t, int>& atomMatchingTrackerMap) { 99 mIndex = index; 100 mChildren.clear(); 101 AtomMatcher_Combination combinationMatcher = matcher.combination(); 102 for (const int64_t child : combinationMatcher.matcher()) { 103 const auto& pair = atomMatchingTrackerMap.find(child); 104 if (pair == atomMatchingTrackerMap.end()) { 105 ALOGW("Matcher %lld not found in the config", (long long)child); 106 return false; 107 } 108 mChildren.push_back(pair->second); 109 } 110 return true; 111 } 112 113 void CombinationAtomMatchingTracker::onLogEvent( 114 const LogEvent& event, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, 115 vector<MatchingState>& matcherResults) { 116 // this event has been processed. 117 if (matcherResults[mIndex] != MatchingState::kNotComputed) { 118 return; 119 } 120 121 if (mAtomIds.find(event.GetTagId()) == mAtomIds.end()) { 122 matcherResults[mIndex] = MatchingState::kNotMatched; 123 return; 124 } 125 126 // evaluate children matchers if they haven't been evaluated. 127 for (const int childIndex : mChildren) { 128 if (matcherResults[childIndex] == MatchingState::kNotComputed) { 129 const sp<AtomMatchingTracker>& child = allAtomMatchingTrackers[childIndex]; 130 child->onLogEvent(event, allAtomMatchingTrackers, matcherResults); 131 } 132 } 133 134 bool matched = combinationMatch(mChildren, mLogicalOperation, matcherResults); 135 matcherResults[mIndex] = matched ? MatchingState::kMatched : MatchingState::kNotMatched; 136 } 137 138 } // namespace statsd 139 } // namespace os 140 } // namespace android 141