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 struct Metric2Condition {
33     int64_t conditionId;
34     std::vector<Matcher> metricFields;
35     std::vector<Matcher> conditionFields;
36 };
37 
38 struct Metric2State {
39     int32_t stateAtomId;
40     std::vector<Matcher> metricFields;
41     std::vector<Matcher> stateFields;
42 };
43 
44 class HashableDimensionKey {
45 public:
HashableDimensionKey(const std::vector<FieldValue> & values)46     explicit HashableDimensionKey(const std::vector<FieldValue>& values) {
47         mValues = values;
48     }
49 
HashableDimensionKey()50     HashableDimensionKey() {};
51 
HashableDimensionKey(const HashableDimensionKey & that)52     HashableDimensionKey(const HashableDimensionKey& that) : mValues(that.getValues()){};
53 
addValue(const FieldValue & value)54     inline void addValue(const FieldValue& value) {
55         mValues.push_back(value);
56     }
57 
getValues()58     inline const std::vector<FieldValue>& getValues() const {
59         return mValues;
60     }
61 
mutableValues()62     inline std::vector<FieldValue>* mutableValues() {
63         return &mValues;
64     }
65 
mutableValue(size_t i)66     inline FieldValue* mutableValue(size_t i) {
67         if (i >= 0 && i < mValues.size()) {
68             return &(mValues[i]);
69         }
70         return nullptr;
71     }
72 
73     StatsDimensionsValueParcel toStatsDimensionsValueParcel() const;
74 
75     std::string toString() const;
76 
77     bool operator!=(const HashableDimensionKey& that) const;
78 
79     bool operator==(const HashableDimensionKey& that) const;
80 
81     bool operator<(const HashableDimensionKey& that) const;
82 
83     bool contains(const HashableDimensionKey& that) const;
84 
85 private:
86     std::vector<FieldValue> mValues;
87 };
88 
89 class MetricDimensionKey {
90 public:
MetricDimensionKey(const HashableDimensionKey & dimensionKeyInWhat,const HashableDimensionKey & stateValuesKey)91     explicit MetricDimensionKey(const HashableDimensionKey& dimensionKeyInWhat,
92                                 const HashableDimensionKey& stateValuesKey)
93         : mDimensionKeyInWhat(dimensionKeyInWhat), mStateValuesKey(stateValuesKey){};
94 
MetricDimensionKey()95     MetricDimensionKey(){};
96 
MetricDimensionKey(const MetricDimensionKey & that)97     MetricDimensionKey(const MetricDimensionKey& that)
98         : mDimensionKeyInWhat(that.getDimensionKeyInWhat()),
99           mStateValuesKey(that.getStateValuesKey()){};
100 
101     MetricDimensionKey& operator=(const MetricDimensionKey& from) = default;
102 
103     std::string toString() const;
104 
getDimensionKeyInWhat()105     inline const HashableDimensionKey& getDimensionKeyInWhat() const {
106         return mDimensionKeyInWhat;
107     }
108 
getStateValuesKey()109     inline const HashableDimensionKey& getStateValuesKey() const {
110         return mStateValuesKey;
111     }
112 
getMutableStateValuesKey()113     inline HashableDimensionKey* getMutableStateValuesKey() {
114         return &mStateValuesKey;
115     }
116 
setStateValuesKey(const HashableDimensionKey & key)117     inline void setStateValuesKey(const HashableDimensionKey& key) {
118         mStateValuesKey = key;
119     }
120 
hasStateValuesKey()121     bool hasStateValuesKey() const {
122         return mStateValuesKey.getValues().size() > 0;
123     }
124 
125     bool operator==(const MetricDimensionKey& that) const;
126 
127     bool operator<(const MetricDimensionKey& that) const;
128 
129 private:
130     HashableDimensionKey mDimensionKeyInWhat;
131     HashableDimensionKey mStateValuesKey;
132 };
133 
134 android::hash_t hashDimension(const HashableDimensionKey& key);
135 
136 /**
137  * Returns true if a FieldValue field matches the matcher field.
138  * The value of the FieldValue is output.
139  */
140 bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& values,
141                   FieldValue* output);
142 
143 /**
144  * Creating HashableDimensionKeys from FieldValues using matcher.
145  *
146  * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
147  * in it. This is because: for example, when we create dimension from last uid in attribution chain,
148  * In one event, uid 1000 is at position 5 and it's the last
149  * In another event, uid 1000 is at position 6, and it's the last
150  * these 2 events should be mapped to the same dimension.  So we will remove the original position
151  * from the dimension key for the uid field (by applying 0x80 bit mask).
152  */
153 bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
154                   HashableDimensionKey* output);
155 
156 /**
157  * Creating HashableDimensionKeys from State Primary Keys in FieldValues.
158  *
159  * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
160  * in it. This is because: for example, when we create dimension from last uid in attribution chain,
161  * In one event, uid 1000 is at position 5 and it's the last
162  * In another event, uid 1000 is at position 6, and it's the last
163  * these 2 events should be mapped to the same dimension.  So we will remove the original position
164  * from the dimension key for the uid field (by applying 0x80 bit mask).
165  */
166 bool filterPrimaryKey(const std::vector<FieldValue>& values, HashableDimensionKey* output);
167 
168 /**
169  * Filter the values from FieldValues using the matchers.
170  *
171  * In contrast to the above function, this function will not do any modification to the original
172  * data. Considering it as taking a snapshot on the atom event.
173  */
174 void filterGaugeValues(const std::vector<Matcher>& matchers, const std::vector<FieldValue>& values,
175                        std::vector<FieldValue>* output);
176 
177 void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
178                               const Metric2Condition& links,
179                               HashableDimensionKey* conditionDimension);
180 
181 /**
182  * Get dimension values using metric's "what" fields and fill statePrimaryKey's
183  * mField information using "state" fields.
184  */
185 void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link,
186                           HashableDimensionKey* statePrimaryKey);
187 
188 /**
189  * Returns true if the primaryKey values are a subset of the whatKey values.
190  * The values from the primaryKey come from the state atom, so we need to
191  * check that a link exists between the state atom field and what atom field.
192  *
193  * Example:
194  * whatKey = [Atom: 10, {uid: 1005, wakelock_name: "compose"}]
195  * statePrimaryKey = [Atom: 27, {uid: 1005}]
196  * Returns true IF one of the Metric2State links Atom 10's uid to Atom 27's uid
197  *
198  * Example:
199  * whatKey = [Atom: 10, {uid: 1005, wakelock_name: "compose"}]
200  * statePrimaryKey = [Atom: 59, {uid: 1005, package_name: "system"}]
201  * Returns false
202  */
203 bool containsLinkedStateValues(const HashableDimensionKey& whatKey,
204                                const HashableDimensionKey& primaryKey,
205                                const std::vector<Metric2State>& stateLinks,
206                                const int32_t stateAtomId);
207 
208 /**
209  * Returns true if there is a Metric2State link that links the stateField and
210  * the metricField (they are equal fields from different atoms).
211  */
212 bool linked(const std::vector<Metric2State>& stateLinks, const int32_t stateAtomId,
213             const Field& stateField, const Field& metricField);
214 }  // namespace statsd
215 }  // namespace os
216 }  // namespace android
217 
218 namespace std {
219 
220 using android::os::statsd::HashableDimensionKey;
221 using android::os::statsd::MetricDimensionKey;
222 
223 template <>
224 struct hash<HashableDimensionKey> {
225     std::size_t operator()(const HashableDimensionKey& key) const {
226         return hashDimension(key);
227     }
228 };
229 
230 template <>
231 struct hash<MetricDimensionKey> {
232     std::size_t operator()(const MetricDimensionKey& key) const {
233         android::hash_t hash = hashDimension(key.getDimensionKeyInWhat());
234         hash = android::JenkinsHashMix(hash, hashDimension(key.getStateValuesKey()));
235         return android::JenkinsHashWhiten(hash);
236     }
237 };
238 }  // namespace std
239