| /* |
| * 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 DEBUG false |
| #include "Log.h" |
| #include "FieldValue.h" |
| #include "HashableDimensionKey.h" |
| #include "math.h" |
| #include "statslog.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; |
| } |
| |
| void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int* pos, int* mask, |
| std::vector<Matcher>* 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<Matcher>* 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) { |
| int field = value.mField.getField() & 0xff007f; |
| if (field == 0x10001 && value.mValue.getType() == INT) { |
| return true; |
| } |
| return false; |
| } |
| |
| int32_t getUidIfExists(const FieldValue& value) { |
| bool isUid = false; |
| // the field is uid field if the field is the uid field in attribution node or marked as |
| // is_uid in atoms.proto |
| if (isAttributionUidField(value)) { |
| isUid = true; |
| } else { |
| auto it = android::util::AtomsInfo::kAtomsWithUidField.find(value.mField.getTag()); |
| if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) { |
| int uidField = it->second; // uidField is the field number in proto |
| isUid = value.mField.getDepth() == 0 && value.mField.getPosAtDepth(0) == uidField && |
| value.mValue.getType() == INT; |
| } |
| } |
| |
| 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; |
| } |
| |
| 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<float>::epsilon(); |
| case DOUBLE: |
| return fabs(double_value) <= std::numeric_limits<double>::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) { |
| 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; |
| } |
| } |
| |
| bool equalDimensions(const std::vector<Matcher>& dimension_a, |
| const std::vector<Matcher>& 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; |
| } |
| |
| 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; |
| } |
| |
| } // namespace statsd |
| } // namespace os |
| } // namespace android |