Home | History | Annotate | Download | only in condition
      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