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