blob: 4ff4f74f7979311200cd36a357a4044cbe160f4f [file] [log] [blame]
/*
* Copyright (C) 2017 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.
*/
#include "Log.h"
#include "field_util.h"
#include <set>
#include <vector>
namespace android {
namespace os {
namespace statsd {
// This function is to compare two Field trees where each node has at most one child.
bool CompareField(const Field& a, const Field& b) {
if (a.field() < b.field()) {
return true;
}
if (a.field() > b.field()) {
return false;
}
if (a.position_index() < b.position_index()) {
return true;
}
if (a.position_index() > b.position_index()) {
return false;
}
if (a.child_size() < b.child_size()) {
return true;
}
if (a.child_size() > b.child_size()) {
return false;
}
if (a.child_size() == 0 && b.child_size() == 0) {
return false;
}
return CompareField(a.child(0), b.child(0));
}
const Field* getSingleLeaf(const Field* field) {
if (field->child_size() <= 0) {
return field;
} else {
return getSingleLeaf(&field->child(0));
}
}
Field* getSingleLeaf(Field* field) {
if (field->child_size() <= 0) {
return field;
} else {
return getSingleLeaf(field->mutable_child(0));
}
}
void FieldToString(const Field& field, std::string *flattened) {
*flattened += std::to_string(field.field());
if (field.has_position_index()) {
*flattened += "[";
*flattened += std::to_string(field.position_index());
*flattened += "]";
}
if (field.child_size() <= 0) {
return;
}
*flattened += ".";
*flattened += "{";
for (int i = 0 ; i < field.child_size(); ++i) {
*flattened += FieldToString(field.child(i));
}
*flattened += "},";
}
std::string FieldToString(const Field& field) {
std::string flatten;
FieldToString(field, &flatten);
return flatten;
}
bool setFieldInLeafValueProto(const Field &field, DimensionsValue* leafValue) {
if (field.child_size() <= 0) {
leafValue->set_field(field.field());
return true;
} else if (field.child_size() == 1) {
return setFieldInLeafValueProto(field.child(0), leafValue);
} else {
ALOGE("Not able to set the 'field' in leaf value for multiple children.");
return false;
}
}
Field buildAtomField(const int tagId, const Field &atomField) {
Field field;
*field.add_child() = atomField;
field.set_field(tagId);
return field;
}
Field buildSimpleAtomField(const int tagId, const int atomFieldNum) {
Field field;
field.set_field(tagId);
field.add_child()->set_field(atomFieldNum);
return field;
}
Field buildSimpleAtomField(const int tagId) {
Field field;
field.set_field(tagId);
return field;
}
void appendLeaf(Field *parent, int node_field_num) {
if (!parent->has_field()) {
parent->set_field(node_field_num);
} else if (parent->child_size() <= 0) {
parent->add_child()->set_field(node_field_num);
} else {
appendLeaf(parent->mutable_child(0), node_field_num);
}
}
void appendLeaf(Field *parent, int node_field_num, int position) {
if (!parent->has_field()) {
parent->set_field(node_field_num);
parent->set_position_index(position);
} else if (parent->child_size() <= 0) {
auto child = parent->add_child();
child->set_field(node_field_num);
child->set_position_index(position);
} else {
appendLeaf(parent->mutable_child(0), node_field_num, position);
}
}
void getNextField(Field* field) {
if (field->child_size() <= 0) {
field->set_field(field->field() + 1);
return;
}
if (field->child_size() != 1) {
return;
}
getNextField(field->mutable_child(0));
}
void increasePosition(Field *field) {
if (!field->has_position_index()) {
field->set_position_index(0);
} else {
field->set_position_index(field->position_index() + 1);
}
}
int getPositionByReferenceField(const Field& ref, const Field& field_with_index) {
if (ref.child_size() <= 0) {
return field_with_index.position_index();
}
if (ref.child_size() != 1 ||
field_with_index.child_size() != 1) {
return -1;
}
return getPositionByReferenceField(ref.child(0), field_with_index.child(0));
}
void setPositionForLeaf(Field *field, int index) {
if (field->child_size() <= 0) {
field->set_position_index(index);
} else {
setPositionForLeaf(field->mutable_child(0), index);
}
}
namespace {
void findFields(
const FieldValueMap& fieldValueMap,
const FieldMatcher& matcher,
const Field& field,
std::vector<Field>* rootFields);
void findNonRepeatedFields(
const FieldValueMap& fieldValueMap,
const FieldMatcher& matcher,
const Field& field,
std::vector<Field>* rootFields) {
if (matcher.child_size() > 0) {
for (const auto& childMatcher : matcher.child()) {
Field childField = field;
appendLeaf(&childField, childMatcher.field());
findFields(fieldValueMap, childMatcher, childField, rootFields);
}
} else {
auto ret = fieldValueMap.equal_range(field);
int found = 0;
for (auto it = ret.first; it != ret.second; ++it) {
found++;
}
// Not found.
if (found <= 0) {
return;
}
if (found > 1) {
ALOGE("Found multiple values for optional field.");
return;
}
rootFields->push_back(ret.first->first);
}
}
void findRepeatedFields(const FieldValueMap& fieldValueMap, const FieldMatcher& matcher,
const Field& field, std::vector<Field>* rootFields) {
if (matcher.position() == Position::FIRST) {
Field first_field = field;
setPositionForLeaf(&first_field, 0);
findNonRepeatedFields(fieldValueMap, matcher, first_field, rootFields);
} else {
auto itLower = fieldValueMap.lower_bound(field);
if (itLower == fieldValueMap.end()) {
return;
}
Field next_field = field;
getNextField(&next_field);
auto itUpper = fieldValueMap.lower_bound(next_field);
switch (matcher.position()) {
case Position::LAST:
{
itUpper--;
if (itUpper != fieldValueMap.end()) {
Field last_field = field;
int last_index = getPositionByReferenceField(field, itUpper->first);
if (last_index < 0) {
return;
}
setPositionForLeaf(&last_field, last_index);
findNonRepeatedFields(
fieldValueMap, matcher, last_field, rootFields);
}
}
break;
case Position::ANY:
{
std::set<int> indexes;
for (auto it = itLower; it != itUpper; ++it) {
int index = getPositionByReferenceField(field, it->first);
if (index >= 0) {
indexes.insert(index);
}
}
if (!indexes.empty()) {
Field any_field = field;
for (const int index : indexes) {
setPositionForLeaf(&any_field, index);
findNonRepeatedFields(
fieldValueMap, matcher, any_field, rootFields);
}
}
}
break;
default:
break;
}
}
}
void findFields(
const FieldValueMap& fieldValueMap,
const FieldMatcher& matcher,
const Field& field,
std::vector<Field>* rootFields) {
if (!matcher.has_position()) {
findNonRepeatedFields(fieldValueMap, matcher, field, rootFields);
} else {
findRepeatedFields(fieldValueMap, matcher, field, rootFields);
}
}
} // namespace
void findFields(
const FieldValueMap& fieldValueMap,
const FieldMatcher& matcher,
std::vector<Field>* rootFields) {
return findFields(fieldValueMap, matcher, buildSimpleAtomField(matcher.field()), rootFields);
}
void filterFields(const FieldMatcher& matcher, FieldValueMap* fieldValueMap) {
std::vector<Field> rootFields;
findFields(*fieldValueMap, matcher, &rootFields);
std::set<Field, FieldCmp> rootFieldSet(rootFields.begin(), rootFields.end());
auto it = fieldValueMap->begin();
while (it != fieldValueMap->end()) {
if (rootFieldSet.find(it->first) == rootFieldSet.end()) {
it = fieldValueMap->erase(it);
} else {
it++;
}
}
}
bool hasLeafNode(const FieldMatcher& matcher) {
if (!matcher.has_field()) {
return false;
}
for (int i = 0; i < matcher.child_size(); ++i) {
if (hasLeafNode(matcher.child(i))) {
return true;
}
}
return true;
}
bool IsAttributionUidField(const Field& field) {
return field.child_size() == 1 && field.child(0).field() == 1
&& field.child(0).child_size() == 1 && field.child(0).child(0).field() == 1;
}
} // namespace statsd
} // namespace os
} // namespace android