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