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 <aidl/android/os/StatsDimensionsValueParcel.h>
20 #include <utils/JenkinsHash.h>
21 #include <vector>
22 #include "android-base/stringprintf.h"
23 #include "FieldValue.h"
24 #include "logd/LogEvent.h"
25 
26 namespace android {
27 namespace os {
28 namespace statsd {
29 
30 using ::aidl::android::os::StatsDimensionsValueParcel;
31 
32 // These constants must be kept in sync with those in StatsDimensionsValue.java
33 inline constexpr int STATS_DIMENSIONS_VALUE_STRING_TYPE = 2;
34 inline constexpr int STATS_DIMENSIONS_VALUE_INT_TYPE = 3;
35 inline constexpr int STATS_DIMENSIONS_VALUE_LONG_TYPE = 4;
36 // inline constexpr int STATS_DIMENSIONS_VALUE_BOOL_TYPE = 5; (commented out because
37 // unused -- statsd does not correctly support bool types)
38 inline constexpr int STATS_DIMENSIONS_VALUE_FLOAT_TYPE = 6;
39 inline constexpr int STATS_DIMENSIONS_VALUE_TUPLE_TYPE = 7;
40 
41 struct Metric2Condition {
42     int64_t conditionId;
43     std::vector<Matcher> metricFields;
44     std::vector<Matcher> conditionFields;
45 };
46 
47 struct Metric2State {
48     int32_t stateAtomId;
49     std::vector<Matcher> metricFields;
50     std::vector<Matcher> stateFields;
51 };
52 
53 class HashableDimensionKey {
54 public:
HashableDimensionKey(const std::vector<FieldValue> & values)55     explicit HashableDimensionKey(const std::vector<FieldValue>& values) {
56         mValues = values;
57     }
58 
HashableDimensionKey()59     HashableDimensionKey() {};
60 
HashableDimensionKey(const HashableDimensionKey & that)61     HashableDimensionKey(const HashableDimensionKey& that) : mValues(that.getValues()){};
62 
addValue(const FieldValue & value)63     inline void addValue(const FieldValue& value) {
64         mValues.push_back(value);
65     }
66 
getValues()67     inline const std::vector<FieldValue>& getValues() const {
68         return mValues;
69     }
70 
mutableValues()71     inline std::vector<FieldValue>* mutableValues() {
72         return &mValues;
73     }
74 
mutableValue(size_t i)75     inline FieldValue* mutableValue(size_t i) {
76         if (i >= 0 && i < mValues.size()) {
77             return &(mValues[i]);
78         }
79         return nullptr;
80     }
81 
82     StatsDimensionsValueParcel toStatsDimensionsValueParcel() const;
83 
84     std::string toString() const;
85 
86     bool operator!=(const HashableDimensionKey& that) const;
87 
88     bool operator==(const HashableDimensionKey& that) const;
89 
90     bool operator<(const HashableDimensionKey& that) const;
91 
92     bool contains(const HashableDimensionKey& that) const;
93 
94 private:
95     std::vector<FieldValue> mValues;
96 };
97 
98 class MetricDimensionKey {
99 public:
MetricDimensionKey(const HashableDimensionKey & dimensionKeyInWhat,const HashableDimensionKey & stateValuesKey)100     explicit MetricDimensionKey(const HashableDimensionKey& dimensionKeyInWhat,
101                                 const HashableDimensionKey& stateValuesKey)
102         : mDimensionKeyInWhat(dimensionKeyInWhat), mStateValuesKey(stateValuesKey){};
103 
MetricDimensionKey()104     MetricDimensionKey(){};
105 
MetricDimensionKey(const MetricDimensionKey & that)106     MetricDimensionKey(const MetricDimensionKey& that)
107         : mDimensionKeyInWhat(that.getDimensionKeyInWhat()),
108           mStateValuesKey(that.getStateValuesKey()){};
109 
110     MetricDimensionKey& operator=(const MetricDimensionKey& from) = default;
111 
112     std::string toString() const;
113 
getDimensionKeyInWhat()114     inline const HashableDimensionKey& getDimensionKeyInWhat() const {
115         return mDimensionKeyInWhat;
116     }
117 
getStateValuesKey()118     inline const HashableDimensionKey& getStateValuesKey() const {
119         return mStateValuesKey;
120     }
121 
getMutableStateValuesKey()122     inline HashableDimensionKey* getMutableStateValuesKey() {
123         return &mStateValuesKey;
124     }
125 
setStateValuesKey(const HashableDimensionKey & key)126     inline void setStateValuesKey(const HashableDimensionKey& key) {
127         mStateValuesKey = key;
128     }
129 
hasStateValuesKey()130     bool hasStateValuesKey() const {
131         return mStateValuesKey.getValues().size() > 0;
132     }
133 
134     bool operator==(const MetricDimensionKey& that) const;
135 
136     bool operator<(const MetricDimensionKey& that) const;
137 
138     size_t getSize(const bool usesNestedDimensions) const;
139 
140 private:
141     HashableDimensionKey mDimensionKeyInWhat;
142     HashableDimensionKey mStateValuesKey;
143 };
144 
145 class AtomDimensionKey {
146 public:
AtomDimensionKey(int32_t atomTag,const HashableDimensionKey & atomFieldValues)147     explicit AtomDimensionKey(int32_t atomTag, const HashableDimensionKey& atomFieldValues)
148         : mAtomTag(atomTag), mAtomFieldValues(atomFieldValues){};
149 
AtomDimensionKey()150     AtomDimensionKey(){};
151 
getAtomTag()152     inline int32_t getAtomTag() const {
153         return mAtomTag;
154     }
155 
getAtomFieldValues()156     inline const HashableDimensionKey& getAtomFieldValues() const {
157         return mAtomFieldValues;
158     }
159 
160     bool operator==(const AtomDimensionKey& that) const;
161 
162 private:
163     int32_t mAtomTag;
164     HashableDimensionKey mAtomFieldValues;
165 };
166 
167 android::hash_t hashDimension(const HashableDimensionKey& key);
168 
169 /**
170  * Returns true if a FieldValue field matches the matcher field.
171  * This function can only be used to match one field (i.e. matcher with position ALL will return
172  * false). The value of the FieldValue is output.
173  */
174 bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& values,
175                   FieldValue* output);
176 
177 /**
178  * Creating HashableDimensionKeys from FieldValues using matcher.
179  *
180  * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
181  * in it. This is because: for example, when we create dimension from last uid in attribution chain,
182  * In one event, uid 1000 is at position 5 and it's the last
183  * In another event, uid 1000 is at position 6, and it's the last
184  * these 2 events should be mapped to the same dimension.  So we will remove the original position
185  * from the dimension key for the uid field (by applying 0x80 bit mask).
186  */
187 bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
188                   HashableDimensionKey* output);
189 
190 /**
191  * Filters FieldValues to create HashableDimensionKey using dimensions matcher fields and create
192  *  vector of value indices using values matcher fields.
193  *
194  * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
195  * in it. This is because: for example, when we create dimension from last uid in attribution chain,
196  * In one event, uid 1000 is at position 5 and it's the last
197  * In another event, uid 1000 is at position 6, and it's the last
198  * these 2 events should be mapped to the same dimension.  So we will remove the original position
199  * from the dimension key for the uid field (by applying 0x80 bit mask).
200  *
201  * dimKeyMatcherFields: the matchers for each dimension field
202  * valueMatcherFields: the matchers for each value field
203  * values: FieldValues being filtered by the matchers
204  * key: HashableDimensionKey containing the values filtered by the dimKeyMatcherFields
205  * valueIndices: index position of each matched FieldValue corresponding to the valueMatcherFields
206  */
207 bool filterValues(const std::vector<Matcher>& dimKeyMatcherFields,
208                   const std::vector<Matcher>& valueMatcherFields,
209                   const std::vector<FieldValue>& values, HashableDimensionKey& key,
210                   std::vector<int>& valueIndices);
211 
212 /**
213  * Creating HashableDimensionKeys from State Primary Keys in FieldValues.
214  *
215  * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
216  * in it. This is because: for example, when we create dimension from last uid in attribution chain,
217  * In one event, uid 1000 is at position 5 and it's the last
218  * In another event, uid 1000 is at position 6, and it's the last
219  * these 2 events should be mapped to the same dimension.  So we will remove the original position
220  * from the dimension key for the uid field (by applying 0x80 bit mask).
221  */
222 bool filterPrimaryKey(const std::vector<FieldValue>& values, HashableDimensionKey* output);
223 
224 /**
225  * Filter the values from FieldValues using the matchers.
226  *
227  * In contrast to the above function, this function will not do any modification to the original
228  * data. Considering it as taking a snapshot on the atom event.
229  */
230 void filterGaugeValues(const std::vector<Matcher>& matchers, const std::vector<FieldValue>& values,
231                        std::vector<FieldValue>* output);
232 
233 void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
234                               const Metric2Condition& links,
235                               HashableDimensionKey* conditionDimension);
236 
237 /**
238  * Get dimension values using metric's "what" fields and fill statePrimaryKey's
239  * mField information using "state" fields.
240  */
241 void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link,
242                           HashableDimensionKey* statePrimaryKey);
243 
244 /**
245  * Returns true if the primaryKey values are a subset of the whatKey values.
246  * The values from the primaryKey come from the state atom, so we need to
247  * check that a link exists between the state atom field and what atom field.
248  *
249  * Example:
250  * whatKey = [Atom: 10, {uid: 1005, wakelock_name: "compose"}]
251  * statePrimaryKey = [Atom: 27, {uid: 1005}]
252  * Returns true IF one of the Metric2State links Atom 10's uid to Atom 27's uid
253  *
254  * Example:
255  * whatKey = [Atom: 10, {uid: 1005, wakelock_name: "compose"}]
256  * statePrimaryKey = [Atom: 59, {uid: 1005, package_name: "system"}]
257  * Returns false
258  */
259 bool containsLinkedStateValues(const HashableDimensionKey& whatKey,
260                                const HashableDimensionKey& primaryKey,
261                                const std::vector<Metric2State>& stateLinks,
262                                const int32_t stateAtomId);
263 
264 /**
265  * Returns true if there is a Metric2State link that links the stateField and
266  * the metricField (they are equal fields from different atoms).
267  */
268 bool linked(const std::vector<Metric2State>& stateLinks, const int32_t stateAtomId,
269             const Field& stateField, const Field& metricField);
270 }  // namespace statsd
271 }  // namespace os
272 }  // namespace android
273 
274 template <>
275 struct std::hash<android::os::statsd::HashableDimensionKey> {
276     std::size_t operator()(const android::os::statsd::HashableDimensionKey& key) const {
277         return hashDimension(key);
278     }
279 };
280 
281 template <>
282 struct std::hash<android::os::statsd::MetricDimensionKey> {
283     std::size_t operator()(const android::os::statsd::MetricDimensionKey& key) const {
284         android::hash_t hash = hashDimension(key.getDimensionKeyInWhat());
285         hash = android::JenkinsHashMix(hash, hashDimension(key.getStateValuesKey()));
286         return android::JenkinsHashWhiten(hash);
287     }
288 };
289 
290 template <>
291 struct std::hash<android::os::statsd::AtomDimensionKey> {
292     std::size_t operator()(const android::os::statsd::AtomDimensionKey& key) const {
293         android::hash_t hash = hashDimension(key.getAtomFieldValues());
294         hash = android::JenkinsHashMix(hash, key.getAtomTag());
295         return android::JenkinsHashWhiten(hash);
296     }
297 };
298