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 #pragma once
18 
19 #include "condition/condition_util.h"
20 #include "src/statsd_config.pb.h"
21 #include "matchers/AtomMatchingTracker.h"
22 #include "matchers/matcher_util.h"
23 
24 #include <utils/RefBase.h>
25 
26 #include <unordered_map>
27 
28 namespace android {
29 namespace os {
30 namespace statsd {
31 
32 class ConditionTracker : public virtual RefBase {
33 public:
ConditionTracker(int64_t id,int index,const uint64_t protoHash)34     ConditionTracker(int64_t id, int index, const uint64_t protoHash)
35         : mConditionId(id),
36           mIndex(index),
37           mInitialized(false),
38           mTrackerIndex(),
39           mUnSlicedPartCondition(ConditionState::kUnknown),
40           mSliced(false),
41           mProtoHash(protoHash){};
42 
~ConditionTracker()43     virtual ~ConditionTracker(){};
44 
45     // Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
46     // be done in the constructor, but we do it separately because (1) easy to return a bool to
47     // indicate whether the initialization is successful. (2) makes unit test easier.
48     // This function can also be called on config updates, in which case it does nothing other than
49     // fill the condition cache with the current condition.
50     // allConditionConfig: the list of all Predicate config from statsd_config.
51     // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
52     //                       need to call init() on child conditions)
53     // conditionIdIndexMap: the mapping from condition id to its index.
54     // stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
55     // conditionCache: tracks initial conditions of all ConditionTrackers. returns the
56     //                        current condition if called on a config update.
57     virtual optional<InvalidConfigReason> init(
58             const std::vector<Predicate>& allConditionConfig,
59             const std::vector<sp<ConditionTracker>>& allConditionTrackers,
60             const std::unordered_map<int64_t, int>& conditionIdIndexMap,
61             std::vector<uint8_t>& stack, std::vector<ConditionState>& conditionCache) = 0;
62 
63     // Update appropriate state on config updates. Primarily, all indices need to be updated.
64     // This predicate and all of its children are guaranteed to be preserved across the update.
65     // This function is recursive and will call onConfigUpdated on child conditions. It does not
66     // manage cycle detection since all preserved conditions should not have any cycles.
67     //
68     // allConditionProtos: the new predicates.
69     // index: the new index of this tracker in allConditionProtos and allConditionTrackers.
70     // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
71     //                       need to call onConfigUpdated() on child conditions)
72     // atomMatchingTrackerMap: map of atom matcher id to index after the config update.
73     // conditionTrackerMap: map of condition tracker id to index after the config update.
74     // returns whether or not the update is successful.
onConfigUpdated(const std::vector<Predicate> & allConditionProtos,int index,const std::vector<sp<ConditionTracker>> & allConditionTrackers,const std::unordered_map<int64_t,int> & atomMatchingTrackerMap,const std::unordered_map<int64_t,int> & conditionTrackerMap)75     virtual optional<InvalidConfigReason> onConfigUpdated(
76             const std::vector<Predicate>& allConditionProtos, int index,
77             const std::vector<sp<ConditionTracker>>& allConditionTrackers,
78             const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
79             const std::unordered_map<int64_t, int>& conditionTrackerMap) {
80         mIndex = index;
81         return nullopt;
82     }
83 
84     // evaluate current condition given the new event.
85     // event: the new log event
86     // eventMatcherValues: the results of the AtomMatchingTrackers. AtomMatchingTrackers always
87     //                     process event before ConditionTrackers, because ConditionTracker depends
88     //                     on AtomMatchingTrackers.
89     // mAllConditions: the list of all ConditionTracker
90     // conditionCache: the cached non-sliced condition of the ConditionTrackers for this new event.
91     // conditionChanged: the bit map to record whether the condition has changed.
92     //                   If the condition has dimension, then any sub condition changes will report
93     //                   conditionChanged.
94     virtual void evaluateCondition(const LogEvent& event,
95                                    const std::vector<MatchingState>& eventMatcherValues,
96                                    const std::vector<sp<ConditionTracker>>& mAllConditions,
97                                    std::vector<ConditionState>& conditionCache,
98                                    std::vector<uint8_t>& conditionChanged) = 0;
99 
100     // Query the condition with parameters.
101     // [conditionParameters]: a map from condition name to the HashableDimensionKey to query the
102     //                       condition.
103     // [allConditions]: all condition trackers. This is needed because the condition evaluation is
104     //                  done recursively
105     // [isPartialLink]: true if the link specified by 'conditionParameters' contains all the fields
106     //                  in the condition tracker output dimension.
107     // [conditionCache]: the cache holding the condition evaluation values.
108     virtual void isConditionMet(
109             const ConditionKey& conditionParameters,
110             const std::vector<sp<ConditionTracker>>& allConditions,
111             const bool isPartialLink,
112             std::vector<ConditionState>& conditionCache) const = 0;
113 
114     // return the list of AtomMatchingTracker index that this ConditionTracker uses.
getAtomMatchingTrackerIndex()115     virtual const std::set<int>& getAtomMatchingTrackerIndex() const {
116         return mTrackerIndex;
117     }
118 
setSliced(bool sliced)119     virtual void setSliced(bool sliced) {
120         mSliced = mSliced | sliced;
121     }
122 
isSliced()123     inline bool isSliced() const {
124         return mSliced;
125     }
126 
127     virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
128             const std::vector<sp<ConditionTracker>>& allConditions) const = 0;
129     virtual const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
130             const std::vector<sp<ConditionTracker>>& allConditions) const = 0;
131 
getConditionId()132     inline int64_t getConditionId() const {
133         return mConditionId;
134     }
135 
getProtoHash()136     inline uint64_t getProtoHash() const {
137         return mProtoHash;
138     }
139 
140     virtual const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(
141             const std::vector<sp<ConditionTracker>>& allConditions) const = 0;
142 
143     virtual bool IsChangedDimensionTrackable() const = 0;
144 
145     virtual bool IsSimpleCondition() const = 0;
146 
147     virtual bool equalOutputDimensions(
148         const std::vector<sp<ConditionTracker>>& allConditions,
149         const vector<Matcher>& dimensions) const = 0;
150 
151     // Return the current condition state of the unsliced part of the condition.
getUnSlicedPartConditionState()152     inline ConditionState getUnSlicedPartConditionState() const  {
153         return mUnSlicedPartCondition;
154     }
155 
156 protected:
157     const int64_t mConditionId;
158 
159     // the index of this condition in the manager's condition list.
160     int mIndex;
161 
162     // if it's properly initialized.
163     bool mInitialized;
164 
165     // the list of AtomMatchingTracker index that this ConditionTracker uses.
166     std::set<int> mTrackerIndex;
167 
168     // This variable is only used for CombinationConditionTrackers.
169     // SimpleConditionTrackers technically don't have an unsliced part because
170     // they are either sliced or unsliced.
171     //
172     // CombinationConditionTrackers have multiple children ConditionTrackers
173     // that can be a mixture of sliced or unsliced. This tracks the
174     // condition of the unsliced part of the combination condition.
175     ConditionState mUnSlicedPartCondition;
176 
177     bool mSliced;
178 
179     // Hash of the Predicate's proto bytes from StatsdConfig.
180     // Used to determine if the definition of this condition has changed across a config update.
181     const uint64_t mProtoHash;
182 
183     FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions);
184 };
185 
186 }  // namespace statsd
187 }  // namespace os
188 }  // namespace android
189