/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define STATSD_DEBUG false #include "Log.h" #include "FieldValue.h" #include "HashableDimensionKey.h" #include "hash.h" #include "math.h" namespace android { namespace os { namespace statsd { int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth) { int32_t field = 0; for (int32_t i = 0; i <= depth; i++) { int32_t shiftBits = 8 * (kMaxLogDepth - i); field |= (pos[i] << shiftBits); } if (includeDepth) { field |= (depth << 24); } return field; } int32_t encodeMatcherMask(int32_t mask[], int32_t depth) { return getEncodedField(mask, depth, false) | 0xff000000; } bool Field::matches(const Matcher& matcher) const { if (mTag != matcher.mMatcher.getTag()) { return false; } if ((mField & matcher.mMask) == matcher.mMatcher.getField()) { return true; } if (matcher.hasAllPositionMatcher() && (mField & (matcher.mMask & kClearAllPositionMatcherMask)) == matcher.mMatcher.getField()) { return true; } return false; } std::vector dedupFieldMatchers(const std::vector& fieldMatchers) { std::vector dedupedFieldMatchers; for (size_t i = 0; i < fieldMatchers.size(); i++) { if (std::find(dedupedFieldMatchers.begin(), dedupedFieldMatchers.end(), fieldMatchers[i]) == dedupedFieldMatchers.end()) { dedupedFieldMatchers.push_back(fieldMatchers[i]); } } return dedupedFieldMatchers; } void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int* pos, int* mask, std::vector* output) { if (depth > kMaxLogDepth) { ALOGE("depth > 2"); return; } pos[depth] = matcher.field(); mask[depth] = 0x7f; if (matcher.has_position()) { depth++; if (depth > 2) { return; } switch (matcher.position()) { case Position::ALL: pos[depth] = 0x00; mask[depth] = 0x7f; break; case Position::ANY: pos[depth] = 0; mask[depth] = 0; break; case Position::FIRST: pos[depth] = 1; mask[depth] = 0x7f; break; case Position::LAST: pos[depth] = 0x80; mask[depth] = 0x80; break; case Position::POSITION_UNKNOWN: pos[depth] = 0; mask[depth] = 0; break; } } if (matcher.child_size() == 0) { output->push_back(Matcher(Field(tag, pos, depth), encodeMatcherMask(mask, depth))); } else { for (const auto& child : matcher.child()) { translateFieldMatcher(tag, child, depth + 1, pos, mask, output); } } } void translateFieldMatcher(const FieldMatcher& matcher, std::vector* output) { int pos[] = {1, 1, 1}; int mask[] = {0x7f, 0x7f, 0x7f}; int tag = matcher.field(); for (const auto& child : matcher.child()) { translateFieldMatcher(tag, child, 0, pos, mask, output); } } bool isAttributionUidField(const FieldValue& value) { return isAttributionUidField(value.mField, value.mValue); } int32_t getUidIfExists(const FieldValue& value) { // the field is uid field if the field is the uid field in attribution node // or annotated as such in the atom bool isUid = isAttributionUidField(value) || isUidField(value); return isUid ? value.mValue.int_value : -1; } bool isAttributionUidField(const Field& field, const Value& value) { int f = field.getField() & 0xff007f; if (f == 0x10001 && value.getType() == INT) { return true; } return false; } bool isUidField(const FieldValue& fieldValue) { return fieldValue.mAnnotations.isUidField(); } bool isPrimitiveRepeatedField(const Field& field) { return field.getDepth() == 1; } Value::Value(const Value& from) { type = from.getType(); switch (type) { case INT: int_value = from.int_value; break; case LONG: long_value = from.long_value; break; case FLOAT: float_value = from.float_value; break; case DOUBLE: double_value = from.double_value; break; case STRING: str_value = from.str_value; break; case STORAGE: storage_value = from.storage_value; break; default: break; } } std::string Value::toString() const { switch (type) { case INT: return std::to_string(int_value) + "[I]"; case LONG: return std::to_string(long_value) + "[L]"; case FLOAT: return std::to_string(float_value) + "[F]"; case DOUBLE: return std::to_string(double_value) + "[D]"; case STRING: return str_value + "[S]"; case STORAGE: return "bytes of size " + std::to_string(storage_value.size()) + "[ST]"; default: return "[UNKNOWN]"; } } bool Value::isZero() const { switch (type) { case INT: return int_value == 0; case LONG: return long_value == 0; case FLOAT: return fabs(float_value) <= std::numeric_limits::epsilon(); case DOUBLE: return fabs(double_value) <= std::numeric_limits::epsilon(); case STRING: return str_value.size() == 0; case STORAGE: return storage_value.size() == 0; default: return false; } } bool Value::operator==(const Value& that) const { if (type != that.getType()) return false; switch (type) { case INT: return int_value == that.int_value; case LONG: return long_value == that.long_value; case FLOAT: return float_value == that.float_value; case DOUBLE: return double_value == that.double_value; case STRING: return str_value == that.str_value; case STORAGE: return storage_value == that.storage_value; default: return false; } } bool Value::operator!=(const Value& that) const { if (type != that.getType()) return true; switch (type) { case INT: return int_value != that.int_value; case LONG: return long_value != that.long_value; case FLOAT: return float_value != that.float_value; case DOUBLE: return double_value != that.double_value; case STRING: return str_value != that.str_value; case STORAGE: return storage_value != that.storage_value; default: return false; } } bool Value::operator<(const Value& that) const { if (type != that.getType()) return type < that.getType(); switch (type) { case INT: return int_value < that.int_value; case LONG: return long_value < that.long_value; case FLOAT: return float_value < that.float_value; case DOUBLE: return double_value < that.double_value; case STRING: return str_value < that.str_value; case STORAGE: return storage_value < that.storage_value; default: return false; } } bool Value::operator>(const Value& that) const { if (type != that.getType()) return type > that.getType(); switch (type) { case INT: return int_value > that.int_value; case LONG: return long_value > that.long_value; case FLOAT: return float_value > that.float_value; case DOUBLE: return double_value > that.double_value; case STRING: return str_value > that.str_value; case STORAGE: return storage_value > that.storage_value; default: return false; } } bool Value::operator>=(const Value& that) const { if (type != that.getType()) return type >= that.getType(); switch (type) { case INT: return int_value >= that.int_value; case LONG: return long_value >= that.long_value; case FLOAT: return float_value >= that.float_value; case DOUBLE: return double_value >= that.double_value; case STRING: return str_value >= that.str_value; case STORAGE: return storage_value >= that.storage_value; default: return false; } } Value Value::operator-(const Value& that) const { Value v; if (type != that.type) { ALOGE("Can't operate on different value types, %d, %d", type, that.type); return v; } if (type == STRING) { ALOGE("Can't operate on string value type"); return v; } if (type == STORAGE) { ALOGE("Can't operate on storage value type"); return v; } switch (type) { case INT: v.setInt(int_value - that.int_value); break; case LONG: v.setLong(long_value - that.long_value); break; case FLOAT: v.setFloat(float_value - that.float_value); break; case DOUBLE: v.setDouble(double_value - that.double_value); break; default: break; } return v; } Value& Value::operator=(const Value& that) { if (this != &that) { type = that.type; switch (type) { case INT: int_value = that.int_value; break; case LONG: long_value = that.long_value; break; case FLOAT: float_value = that.float_value; break; case DOUBLE: double_value = that.double_value; break; case STRING: str_value = that.str_value; break; case STORAGE: storage_value = that.storage_value; break; default: break; } } return *this; } Value& Value::operator+=(const Value& that) { if (type != that.type) { ALOGE("Can't operate on different value types, %d, %d", type, that.type); return *this; } if (type == STRING) { ALOGE("Can't operate on string value type"); return *this; } if (type == STORAGE) { ALOGE("Can't operate on storage value type"); return *this; } switch (type) { case INT: int_value += that.int_value; break; case LONG: long_value += that.long_value; break; case FLOAT: float_value += that.float_value; break; case DOUBLE: double_value += that.double_value; break; default: break; } return *this; } double Value::getDouble() const { switch (type) { case INT: return int_value; case LONG: return long_value; case FLOAT: return float_value; case DOUBLE: return double_value; default: return 0; } } size_t Value::getSize() const { size_t size = 0; switch (type) { case INT: size = sizeof(int32_t); break; case LONG: size = sizeof(int64_t); break; case FLOAT: size = sizeof(float); break; case DOUBLE: size = sizeof(double); break; case STRING: size = sizeof(char) * str_value.length(); break; case STORAGE: size = sizeof(uint8_t) * storage_value.size(); break; default: break; } return size; } std::string Annotations::toString() const { std::string annotations; if (isUidField()) { annotations += "UID"; } if (isPrimaryField()) { annotations += annotations.size() > 0 ? ",PRIMARY" : "PRIMARY"; } if (isExclusiveState()) { annotations += annotations.size() > 0 ? ",EXCLUSIVE" : "EXCLUSIVE"; } if (isNested()) { annotations += annotations.size() > 0 ? ",NESTED" : "NESTED"; } if (annotations.size()) { annotations = "[" + annotations + "]"; } return annotations; } bool equalDimensions(const std::vector& dimension_a, const std::vector& dimension_b) { bool eq = dimension_a.size() == dimension_b.size(); for (size_t i = 0; eq && i < dimension_a.size(); ++i) { if (dimension_b[i] != dimension_a[i]) { eq = false; } } return eq; } /* Is dimension_a a subset of dimension_b. */ bool subsetDimensions(const std::vector& dimension_a, const std::vector& dimension_b) { if (dimension_a.size() > dimension_b.size()) { return false; } for (size_t i = 0; i < dimension_a.size(); ++i) { bool found = false; for (size_t j = 0; j < dimension_b.size(); ++j) { if (dimension_a[i] == dimension_b[j]) { found = true; break; } // Check equality of repeated fields with different positions. // Only position FIRST and LAST are considered subsets of position ALL. if (dimension_b[j].hasAllPositionMatcher() && (dimension_a[i].hasFirstPositionMatcher() || dimension_a[i].hasLastPositionMatcher())) { if (dimension_a[i].isEqualWithoutPositionBits(dimension_b[j])) { found = true; break; } } } if (!found) { return false; } } return true; } bool HasPositionANY(const FieldMatcher& matcher) { if (matcher.has_position() && matcher.position() == Position::ANY) { return true; } for (const auto& child : matcher.child()) { if (HasPositionANY(child)) { return true; } } return false; } bool HasPositionALL(const FieldMatcher& matcher) { if (matcher.has_position() && matcher.position() == Position::ALL) { return true; } for (const auto& child : matcher.child()) { if (HasPositionALL(child)) { return true; } } return false; } bool HasPrimitiveRepeatedField(const FieldMatcher& matcher) { for (const auto& child : matcher.child()) { if (child.has_position() && child.child_size() == 0) { return true; } } return false; } bool ShouldUseNestedDimensions(const FieldMatcher& matcher) { return HasPositionALL(matcher) || HasPrimitiveRepeatedField(matcher); } size_t getSize(const std::vector& fieldValues) { size_t totalSize = 0; for (const FieldValue& fieldValue : fieldValues) { totalSize += fieldValue.getSize(); } return totalSize; } size_t getFieldValuesSizeV2(const std::vector& fieldValues) { size_t totalSize = 0; for (const FieldValue& fieldValue : fieldValues) { totalSize += fieldValue.getSizeV2(); } return totalSize; } bool shouldKeepSample(const FieldValue& sampleFieldValue, int shardOffset, int shardCount) { int hashValue = 0; switch (sampleFieldValue.mValue.type) { case INT: hashValue = Hash32(reinterpret_cast(&sampleFieldValue.mValue.int_value), sizeof(sampleFieldValue.mValue.int_value)); break; case LONG: hashValue = Hash32(reinterpret_cast(&sampleFieldValue.mValue.long_value), sizeof(sampleFieldValue.mValue.long_value)); break; case FLOAT: hashValue = Hash32(reinterpret_cast(&sampleFieldValue.mValue.float_value), sizeof(sampleFieldValue.mValue.float_value)); break; case DOUBLE: hashValue = Hash32(reinterpret_cast(&sampleFieldValue.mValue.double_value), sizeof(sampleFieldValue.mValue.double_value)); break; case STRING: hashValue = Hash32(sampleFieldValue.mValue.str_value); break; case STORAGE: hashValue = Hash32((const char*)sampleFieldValue.mValue.storage_value.data(), sampleFieldValue.mValue.storage_value.size()); break; default: return true; } return (hashValue + shardOffset) % shardCount == 0; } } // namespace statsd } // namespace os } // namespace android