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 #define DEBUG false // STOPSHIP if true 18 #include "Log.h" 19 #include "CombinationConditionTracker.h" 20 21 #include <log/logprint.h> 22 23 namespace android { 24 namespace os { 25 namespace statsd { 26 27 using std::map; 28 using std::string; 29 using std::unique_ptr; 30 using std::unordered_map; 31 using std::vector; 32 33 CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index) 34 : ConditionTracker(id, index) { 35 VLOG("creating CombinationConditionTracker %lld", (long long)mConditionId); 36 } 37 38 CombinationConditionTracker::~CombinationConditionTracker() { 39 VLOG("~CombinationConditionTracker() %lld", (long long)mConditionId); 40 } 41 42 bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConfig, 43 const vector<sp<ConditionTracker>>& allConditionTrackers, 44 const unordered_map<int64_t, int>& conditionIdIndexMap, 45 vector<bool>& stack) { 46 VLOG("Combination predicate init() %lld", (long long)mConditionId); 47 if (mInitialized) { 48 return true; 49 } 50 51 // mark this node as visited in the recursion stack. 52 stack[mIndex] = true; 53 54 Predicate_Combination combinationCondition = allConditionConfig[mIndex].combination(); 55 56 if (!combinationCondition.has_operation()) { 57 return false; 58 } 59 mLogicalOperation = combinationCondition.operation(); 60 61 if (mLogicalOperation == LogicalOperation::NOT && combinationCondition.predicate_size() != 1) { 62 return false; 63 } 64 65 for (auto child : combinationCondition.predicate()) { 66 auto it = conditionIdIndexMap.find(child); 67 68 if (it == conditionIdIndexMap.end()) { 69 ALOGW("Predicate %lld not found in the config", (long long)child); 70 return false; 71 } 72 73 int childIndex = it->second; 74 const auto& childTracker = allConditionTrackers[childIndex]; 75 // if the child is a visited node in the recursion -> circle detected. 76 if (stack[childIndex]) { 77 ALOGW("Circle detected!!!"); 78 return false; 79 } 80 81 82 bool initChildSucceeded = childTracker->init(allConditionConfig, allConditionTrackers, 83 conditionIdIndexMap, stack); 84 85 if (!initChildSucceeded) { 86 ALOGW("Child initialization failed %lld ", (long long)child); 87 return false; 88 } else { 89 ALOGW("Child initialization success %lld ", (long long)child); 90 } 91 92 if (allConditionTrackers[childIndex]->isSliced()) { 93 setSliced(true); 94 mSlicedChildren.push_back(childIndex); 95 } else { 96 mUnSlicedChildren.push_back(childIndex); 97 } 98 mChildren.push_back(childIndex); 99 mTrackerIndex.insert(childTracker->getLogTrackerIndex().begin(), 100 childTracker->getLogTrackerIndex().end()); 101 } 102 103 // unmark this node in the recursion stack. 104 stack[mIndex] = false; 105 106 mInitialized = true; 107 108 return true; 109 } 110 111 void CombinationConditionTracker::isConditionMet( 112 const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions, 113 const std::vector<Matcher>& dimensionFields, 114 const bool isSubOutputDimensionFields, 115 const bool isPartialLink, 116 vector<ConditionState>& conditionCache, 117 std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const { 118 // So far, this is fine as there is at most one child having sliced output. 119 for (const int childIndex : mChildren) { 120 if (conditionCache[childIndex] == ConditionState::kNotEvaluated) { 121 allConditions[childIndex]->isConditionMet(conditionParameters, allConditions, 122 dimensionFields, 123 isSubOutputDimensionFields, 124 isPartialLink, 125 conditionCache, 126 dimensionsKeySet); 127 } 128 } 129 conditionCache[mIndex] = 130 evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache); 131 } 132 133 void CombinationConditionTracker::evaluateCondition( 134 const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues, 135 const std::vector<sp<ConditionTracker>>& mAllConditions, 136 std::vector<ConditionState>& nonSlicedConditionCache, 137 std::vector<bool>& conditionChangedCache) { 138 // value is up to date. 139 if (nonSlicedConditionCache[mIndex] != ConditionState::kNotEvaluated) { 140 return; 141 } 142 143 for (const int childIndex : mChildren) { 144 // So far, this is fine as there is at most one child having sliced output. 145 if (nonSlicedConditionCache[childIndex] == ConditionState::kNotEvaluated) { 146 const sp<ConditionTracker>& child = mAllConditions[childIndex]; 147 child->evaluateCondition(event, eventMatcherValues, mAllConditions, 148 nonSlicedConditionCache, conditionChangedCache); 149 } 150 } 151 152 ConditionState newCondition = 153 evaluateCombinationCondition(mChildren, mLogicalOperation, nonSlicedConditionCache); 154 if (!mSliced) { 155 156 bool nonSlicedChanged = (mNonSlicedConditionState != newCondition); 157 mNonSlicedConditionState = newCondition; 158 159 nonSlicedConditionCache[mIndex] = mNonSlicedConditionState; 160 161 conditionChangedCache[mIndex] = nonSlicedChanged; 162 mUnSlicedPart = newCondition; 163 } else { 164 mUnSlicedPart = evaluateCombinationCondition( 165 mUnSlicedChildren, mLogicalOperation, nonSlicedConditionCache); 166 167 for (const int childIndex : mChildren) { 168 // If any of the sliced condition in children condition changes, the combination 169 // condition may be changed too. 170 if (conditionChangedCache[childIndex]) { 171 conditionChangedCache[mIndex] = true; 172 break; 173 } 174 } 175 nonSlicedConditionCache[mIndex] = newCondition; 176 VLOG("CombinationPredicate %lld sliced may changed? %d", (long long)mConditionId, 177 conditionChangedCache[mIndex] == true); 178 } 179 } 180 181 ConditionState CombinationConditionTracker::getMetConditionDimension( 182 const std::vector<sp<ConditionTracker>>& allConditions, 183 const std::vector<Matcher>& dimensionFields, 184 const bool isSubOutputDimensionFields, 185 std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const { 186 vector<ConditionState> conditionCache(allConditions.size(), ConditionState::kNotEvaluated); 187 // So far, this is fine as there is at most one child having sliced output. 188 for (const int childIndex : mChildren) { 189 conditionCache[childIndex] = conditionCache[childIndex] | 190 allConditions[childIndex]->getMetConditionDimension( 191 allConditions, dimensionFields, isSubOutputDimensionFields, dimensionsKeySet); 192 } 193 evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache); 194 if (conditionCache[mIndex] == ConditionState::kTrue && dimensionsKeySet.empty()) { 195 dimensionsKeySet.insert(DEFAULT_DIMENSION_KEY); 196 } 197 return conditionCache[mIndex]; 198 } 199 200 bool CombinationConditionTracker::equalOutputDimensions( 201 const std::vector<sp<ConditionTracker>>& allConditions, 202 const vector<Matcher>& dimensions) const { 203 if (mSlicedChildren.size() != 1 || 204 mSlicedChildren.front() >= (int)allConditions.size() || 205 mLogicalOperation != LogicalOperation::AND) { 206 return false; 207 } 208 const sp<ConditionTracker>& slicedChild = allConditions.at(mSlicedChildren.front()); 209 return slicedChild->equalOutputDimensions(allConditions, dimensions); 210 } 211 212 } // namespace statsd 213 } // namespace os 214 } // namespace android 215