Home | History | Annotate | Download | only in condition
      1 /*
      2  * Copyright 2018, 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 #define DEBUG false  // STOPSHIP if true
     17 #include "Log.h"
     18 
     19 #include "StateTracker.h"
     20 #include "guardrail/StatsdStats.h"
     21 
     22 namespace android {
     23 namespace os {
     24 namespace statsd {
     25 
     26 using std::string;
     27 using std::unordered_set;
     28 using std::vector;
     29 
     30 StateTracker::StateTracker(const ConfigKey& key, const int64_t& id, const int index,
     31                            const SimplePredicate& simplePredicate,
     32                            const unordered_map<int64_t, int>& trackerNameIndexMap,
     33                            const vector<Matcher> primaryKeys)
     34     : ConditionTracker(id, index), mConfigKey(key), mPrimaryKeys(primaryKeys) {
     35     if (simplePredicate.has_start()) {
     36         auto pair = trackerNameIndexMap.find(simplePredicate.start());
     37         if (pair == trackerNameIndexMap.end()) {
     38             ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
     39             return;
     40         }
     41         mStartLogMatcherIndex = pair->second;
     42         mTrackerIndex.insert(mStartLogMatcherIndex);
     43     } else {
     44         ALOGW("Condition %lld must have a start matcher", (long long)id);
     45         return;
     46     }
     47 
     48     if (simplePredicate.has_dimensions()) {
     49         translateFieldMatcher(simplePredicate.dimensions(), &mOutputDimensions);
     50         if (mOutputDimensions.size() > 0) {
     51             mSliced = true;
     52             mDimensionTag = mOutputDimensions[0].mMatcher.getTag();
     53         } else {
     54             ALOGW("Condition %lld has invalid dimensions", (long long)id);
     55             return;
     56         }
     57     } else {
     58         ALOGW("Condition %lld being a state tracker, but has no dimension", (long long)id);
     59         return;
     60     }
     61 
     62     if (simplePredicate.initial_value() == SimplePredicate_InitialValue_FALSE) {
     63         mInitialValue = ConditionState::kFalse;
     64     } else {
     65         mInitialValue = ConditionState::kUnknown;
     66     }
     67 
     68     mNonSlicedConditionState = mInitialValue;
     69     mInitialized = true;
     70 }
     71 
     72 StateTracker::~StateTracker() {
     73     VLOG("~StateTracker()");
     74 }
     75 
     76 bool StateTracker::init(const vector<Predicate>& allConditionConfig,
     77                         const vector<sp<ConditionTracker>>& allConditionTrackers,
     78                         const unordered_map<int64_t, int>& conditionIdIndexMap,
     79                         vector<bool>& stack) {
     80     return mInitialized;
     81 }
     82 
     83 void StateTracker::dumpState() {
     84     VLOG("StateTracker %lld DUMP:", (long long)mConditionId);
     85     for (const auto& value : mSlicedState) {
     86         VLOG("\t%s -> %s", value.first.toString().c_str(), value.second.toString().c_str());
     87     }
     88     VLOG("Last Changed to True: ");
     89     for (const auto& value : mLastChangedToTrueDimensions) {
     90         VLOG("%s", value.toString().c_str());
     91     }
     92     VLOG("Last Changed to False: ");
     93     for (const auto& value : mLastChangedToFalseDimensions) {
     94         VLOG("%s", value.toString().c_str());
     95     }
     96 }
     97 
     98 bool StateTracker::hitGuardRail(const HashableDimensionKey& newKey) {
     99     if (mSlicedState.find(newKey) != mSlicedState.end()) {
    100         // if the condition is not sliced or the key is not new, we are good!
    101         return false;
    102     }
    103     // 1. Report the tuple count if the tuple count > soft limit
    104     if (mSlicedState.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
    105         size_t newTupleCount = mSlicedState.size() + 1;
    106         StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mConditionId, newTupleCount);
    107         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
    108         if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
    109             ALOGE("Predicate %lld dropping data for dimension key %s",
    110                 (long long)mConditionId, newKey.toString().c_str());
    111             return true;
    112         }
    113     }
    114     return false;
    115 }
    116 
    117 void StateTracker::evaluateCondition(const LogEvent& event,
    118                                      const vector<MatchingState>& eventMatcherValues,
    119                                      const vector<sp<ConditionTracker>>& mAllConditions,
    120                                      vector<ConditionState>& conditionCache,
    121                                      vector<bool>& conditionChangedCache) {
    122     mLastChangedToTrueDimensions.clear();
    123     mLastChangedToFalseDimensions.clear();
    124     if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
    125         // it has been evaluated.
    126         VLOG("Yes, already evaluated, %lld %d", (long long)mConditionId, conditionCache[mIndex]);
    127         return;
    128     }
    129 
    130     if (mStartLogMatcherIndex >= 0 &&
    131         eventMatcherValues[mStartLogMatcherIndex] != MatchingState::kMatched) {
    132         conditionCache[mIndex] =
    133                 mSlicedState.size() > 0 ? ConditionState::kTrue : ConditionState::kFalse;
    134         conditionChangedCache[mIndex] = false;
    135         return;
    136     }
    137 
    138     VLOG("StateTracker evaluate event %s", event.ToString().c_str());
    139 
    140     // Primary key can exclusive fields must be simple fields. so there won't be more than
    141     // one keys matched.
    142     HashableDimensionKey primaryKey;
    143     HashableDimensionKey state;
    144     if ((mPrimaryKeys.size() > 0 && !filterValues(mPrimaryKeys, event.getValues(), &primaryKey)) ||
    145         !filterValues(mOutputDimensions, event.getValues(), &state)) {
    146         ALOGE("Failed to filter fields in the event?? panic now!");
    147         conditionCache[mIndex] =
    148                 mSlicedState.size() > 0 ? ConditionState::kTrue : ConditionState::kFalse;
    149         conditionChangedCache[mIndex] = false;
    150         return;
    151     }
    152     hitGuardRail(primaryKey);
    153 
    154     VLOG("StateTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str());
    155 
    156     auto it = mSlicedState.find(primaryKey);
    157     if (it == mSlicedState.end()) {
    158         mSlicedState[primaryKey] = state;
    159         conditionCache[mIndex] = ConditionState::kTrue;
    160         mLastChangedToTrueDimensions.insert(state);
    161         conditionChangedCache[mIndex] = true;
    162     } else if (!(it->second == state)) {
    163         mLastChangedToFalseDimensions.insert(it->second);
    164         mLastChangedToTrueDimensions.insert(state);
    165         mSlicedState[primaryKey] = state;
    166         conditionCache[mIndex] = ConditionState::kTrue;
    167         conditionChangedCache[mIndex] = true;
    168     } else {
    169         conditionCache[mIndex] = ConditionState::kTrue;
    170         conditionChangedCache[mIndex] = false;
    171     }
    172 
    173     if (DEBUG) {
    174         dumpState();
    175     }
    176     return;
    177 }
    178 
    179 void StateTracker::isConditionMet(
    180         const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
    181         const vector<Matcher>& dimensionFields,
    182         const bool isSubOutputDimensionFields,
    183         const bool isPartialLink,
    184         vector<ConditionState>& conditionCache,
    185         std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
    186     if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
    187         // it has been evaluated.
    188         VLOG("Yes, already evaluated, %lld %d", (long long)mConditionId, conditionCache[mIndex]);
    189         return;
    190     }
    191 
    192     const auto pair = conditionParameters.find(mConditionId);
    193     if (pair == conditionParameters.end()) {
    194         if (mSlicedState.size() > 0) {
    195             conditionCache[mIndex] = ConditionState::kTrue;
    196 
    197             for (const auto& state : mSlicedState) {
    198                 dimensionsKeySet.insert(state.second);
    199             }
    200         } else {
    201             conditionCache[mIndex] = ConditionState::kUnknown;
    202         }
    203         return;
    204     }
    205 
    206     const auto& primaryKey = pair->second;
    207     conditionCache[mIndex] = mInitialValue;
    208     auto it = mSlicedState.find(primaryKey);
    209     if (it != mSlicedState.end()) {
    210         conditionCache[mIndex] = ConditionState::kTrue;
    211         dimensionsKeySet.insert(it->second);
    212     }
    213 }
    214 
    215 ConditionState StateTracker::getMetConditionDimension(
    216         const std::vector<sp<ConditionTracker>>& allConditions,
    217         const vector<Matcher>& dimensionFields,
    218         const bool isSubOutputDimensionFields,
    219         std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
    220     if (mSlicedState.size() > 0) {
    221         for (const auto& state : mSlicedState) {
    222             dimensionsKeySet.insert(state.second);
    223         }
    224         return ConditionState::kTrue;
    225     }
    226 
    227     return mInitialValue;
    228 }
    229 
    230 }  // namespace statsd
    231 }  // namespace os
    232 }  // namespace android