• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 private:
139     HashableDimensionKey mDimensionKeyInWhat;
140     HashableDimensionKey mStateValuesKey;
141 };
142 
143 android::hash_t hashDimension(const HashableDimensionKey& key);
144 
145 /**
146  * Returns true if a FieldValue field matches the matcher field.
147  * The value of the FieldValue is output.
148  */
149 bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& values,
150                   FieldValue* output);
151 
152 /**
153  * Creating HashableDimensionKeys from FieldValues using matcher.
154  *
155  * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
156  * in it. This is because: for example, when we create dimension from last uid in attribution chain,
157  * In one event, uid 1000 is at position 5 and it's the last
158  * In another event, uid 1000 is at position 6, and it's the last
159  * these 2 events should be mapped to the same dimension.  So we will remove the original position
160  * from the dimension key for the uid field (by applying 0x80 bit mask).
161  */
162 bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
163                   HashableDimensionKey* output);
164 
165 /**
166  * Creating HashableDimensionKeys from State Primary Keys in FieldValues.
167  *
168  * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
169  * in it. This is because: for example, when we create dimension from last uid in attribution chain,
170  * In one event, uid 1000 is at position 5 and it's the last
171  * In another event, uid 1000 is at position 6, and it's the last
172  * these 2 events should be mapped to the same dimension.  So we will remove the original position
173  * from the dimension key for the uid field (by applying 0x80 bit mask).
174  */
175 bool filterPrimaryKey(const std::vector<FieldValue>& values, HashableDimensionKey* output);
176 
177 /**
178  * Filter the values from FieldValues using the matchers.
179  *
180  * In contrast to the above function, this function will not do any modification to the original
181  * data. Considering it as taking a snapshot on the atom event.
182  */
183 void filterGaugeValues(const std::vector<Matcher>& matchers, const std::vector<FieldValue>& values,
184                        std::vector<FieldValue>* output);
185 
186 void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
187                               const Metric2Condition& links,
188                               HashableDimensionKey* conditionDimension);
189 
190 /**
191  * Get dimension values using metric's "what" fields and fill statePrimaryKey's
192  * mField information using "state" fields.
193  */
194 void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link,
195                           HashableDimensionKey* statePrimaryKey);
196 
197 /**
198  * Returns true if the primaryKey values are a subset of the whatKey values.
199  * The values from the primaryKey come from the state atom, so we need to
200  * check that a link exists between the state atom field and what atom field.
201  *
202  * Example:
203  * whatKey = [Atom: 10, {uid: 1005, wakelock_name: "compose"}]
204  * statePrimaryKey = [Atom: 27, {uid: 1005}]
205  * Returns true IF one of the Metric2State links Atom 10's uid to Atom 27's uid
206  *
207  * Example:
208  * whatKey = [Atom: 10, {uid: 1005, wakelock_name: "compose"}]
209  * statePrimaryKey = [Atom: 59, {uid: 1005, package_name: "system"}]
210  * Returns false
211  */
212 bool containsLinkedStateValues(const HashableDimensionKey& whatKey,
213                                const HashableDimensionKey& primaryKey,
214                                const std::vector<Metric2State>& stateLinks,
215                                const int32_t stateAtomId);
216 
217 /**
218  * Returns true if there is a Metric2State link that links the stateField and
219  * the metricField (they are equal fields from different atoms).
220  */
221 bool linked(const std::vector<Metric2State>& stateLinks, const int32_t stateAtomId,
222             const Field& stateField, const Field& metricField);
223 }  // namespace statsd
224 }  // namespace os
225 }  // namespace android
226 
227 namespace std {
228 
229 using android::os::statsd::HashableDimensionKey;
230 using android::os::statsd::MetricDimensionKey;
231 
232 template <>
233 struct hash<HashableDimensionKey> {
234     std::size_t operator()(const HashableDimensionKey& key) const {
235         return hashDimension(key);
236     }
237 };
238 
239 template <>
240 struct hash<MetricDimensionKey> {
241     std::size_t operator()(const MetricDimensionKey& key) const {
242         android::hash_t hash = hashDimension(key.getDimensionKeyInWhat());
243         hash = android::JenkinsHashMix(hash, hashDimension(key.getStateValuesKey()));
244         return android::JenkinsHashWhiten(hash);
245     }
246 };
247 }  // namespace std
248