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 class AtomDimensionKey { 144 public: AtomDimensionKey(const int32_t atomTag,const HashableDimensionKey & atomFieldValues)145 explicit AtomDimensionKey(const int32_t atomTag, const HashableDimensionKey& atomFieldValues) 146 : mAtomTag(atomTag), mAtomFieldValues(atomFieldValues){}; 147 AtomDimensionKey()148 AtomDimensionKey(){}; 149 getAtomTag()150 inline int32_t getAtomTag() const { 151 return mAtomTag; 152 } 153 getAtomFieldValues()154 inline const HashableDimensionKey& getAtomFieldValues() const { 155 return mAtomFieldValues; 156 } 157 158 bool operator==(const AtomDimensionKey& that) const; 159 160 private: 161 int32_t mAtomTag; 162 HashableDimensionKey mAtomFieldValues; 163 }; 164 165 android::hash_t hashDimension(const HashableDimensionKey& key); 166 167 /** 168 * Returns true if a FieldValue field matches the matcher field. 169 * The value of the FieldValue is output. 170 */ 171 bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& values, 172 FieldValue* output); 173 174 /** 175 * Creating HashableDimensionKeys from FieldValues using matcher. 176 * 177 * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL 178 * in it. This is because: for example, when we create dimension from last uid in attribution chain, 179 * In one event, uid 1000 is at position 5 and it's the last 180 * In another event, uid 1000 is at position 6, and it's the last 181 * these 2 events should be mapped to the same dimension. So we will remove the original position 182 * from the dimension key for the uid field (by applying 0x80 bit mask). 183 */ 184 bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values, 185 HashableDimensionKey* output); 186 187 /** 188 * Filters FieldValues to create HashableDimensionKey using dimensions matcher fields and create 189 * vector of value indices using values matcher fields. 190 * 191 * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL 192 * in it. This is because: for example, when we create dimension from last uid in attribution chain, 193 * In one event, uid 1000 is at position 5 and it's the last 194 * In another event, uid 1000 is at position 6, and it's the last 195 * these 2 events should be mapped to the same dimension. So we will remove the original position 196 * from the dimension key for the uid field (by applying 0x80 bit mask). 197 * 198 * dimKeyMatcherFields: the matchers for each dimension field 199 * valueMatcherFields: the matchers for each value field 200 * values: FieldValues being filtered by the matchers 201 * key: HashableDimensionKey containing the values filtered by the dimKeyMatcherFields 202 * valueIndices: index position of each matched FieldValue corresponding to the valueMatcherFields 203 */ 204 bool filterValues(const std::vector<Matcher>& dimKeyMatcherFields, 205 const std::vector<Matcher>& valueMatcherFields, 206 const std::vector<FieldValue>& values, HashableDimensionKey& key, 207 std::vector<int>& valueIndices); 208 209 /** 210 * Creating HashableDimensionKeys from State Primary Keys in FieldValues. 211 * 212 * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL 213 * in it. This is because: for example, when we create dimension from last uid in attribution chain, 214 * In one event, uid 1000 is at position 5 and it's the last 215 * In another event, uid 1000 is at position 6, and it's the last 216 * these 2 events should be mapped to the same dimension. So we will remove the original position 217 * from the dimension key for the uid field (by applying 0x80 bit mask). 218 */ 219 bool filterPrimaryKey(const std::vector<FieldValue>& values, HashableDimensionKey* output); 220 221 /** 222 * Filter the values from FieldValues using the matchers. 223 * 224 * In contrast to the above function, this function will not do any modification to the original 225 * data. Considering it as taking a snapshot on the atom event. 226 */ 227 void filterGaugeValues(const std::vector<Matcher>& matchers, const std::vector<FieldValue>& values, 228 std::vector<FieldValue>* output); 229 230 void getDimensionForCondition(const std::vector<FieldValue>& eventValues, 231 const Metric2Condition& links, 232 HashableDimensionKey* conditionDimension); 233 234 /** 235 * Get dimension values using metric's "what" fields and fill statePrimaryKey's 236 * mField information using "state" fields. 237 */ 238 void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link, 239 HashableDimensionKey* statePrimaryKey); 240 241 /** 242 * Returns true if the primaryKey values are a subset of the whatKey values. 243 * The values from the primaryKey come from the state atom, so we need to 244 * check that a link exists between the state atom field and what atom field. 245 * 246 * Example: 247 * whatKey = [Atom: 10, {uid: 1005, wakelock_name: "compose"}] 248 * statePrimaryKey = [Atom: 27, {uid: 1005}] 249 * Returns true IF one of the Metric2State links Atom 10's uid to Atom 27's uid 250 * 251 * Example: 252 * whatKey = [Atom: 10, {uid: 1005, wakelock_name: "compose"}] 253 * statePrimaryKey = [Atom: 59, {uid: 1005, package_name: "system"}] 254 * Returns false 255 */ 256 bool containsLinkedStateValues(const HashableDimensionKey& whatKey, 257 const HashableDimensionKey& primaryKey, 258 const std::vector<Metric2State>& stateLinks, 259 const int32_t stateAtomId); 260 261 /** 262 * Returns true if there is a Metric2State link that links the stateField and 263 * the metricField (they are equal fields from different atoms). 264 */ 265 bool linked(const std::vector<Metric2State>& stateLinks, const int32_t stateAtomId, 266 const Field& stateField, const Field& metricField); 267 } // namespace statsd 268 } // namespace os 269 } // namespace android 270 271 namespace std { 272 273 using android::os::statsd::AtomDimensionKey; 274 using android::os::statsd::HashableDimensionKey; 275 using android::os::statsd::MetricDimensionKey; 276 277 template <> 278 struct hash<HashableDimensionKey> { 279 std::size_t operator()(const HashableDimensionKey& key) const { 280 return hashDimension(key); 281 } 282 }; 283 284 template <> 285 struct hash<MetricDimensionKey> { 286 std::size_t operator()(const MetricDimensionKey& key) const { 287 android::hash_t hash = hashDimension(key.getDimensionKeyInWhat()); 288 hash = android::JenkinsHashMix(hash, hashDimension(key.getStateValuesKey())); 289 return android::JenkinsHashWhiten(hash); 290 } 291 }; 292 293 template <> 294 struct hash<AtomDimensionKey> { 295 std::size_t operator()(const AtomDimensionKey& key) const { 296 android::hash_t hash = hashDimension(key.getAtomFieldValues()); 297 hash = android::JenkinsHashMix(hash, key.getAtomTag()); 298 return android::JenkinsHashWhiten(hash); 299 } 300 }; 301 } // namespace std 302