/* * Copyright 2020 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 #include "dumpsys/filter.h" #include "dumpsys/internal/filter_internal.h" #include "os/log.h" using namespace bluetooth; using namespace dumpsys; class Filter { public: Filter(const dumpsys::ReflectionSchema& reflection_schema) : reflection_schema_(reflection_schema) {} virtual ~Filter() = default; virtual void FilterInPlace(char* dumpsys_data) = 0; static std::unique_ptr Factory( dumpsys::FilterType filter_type, const dumpsys::ReflectionSchema& reflection_schema); protected: /** * Given both reflection field data and the populated flatbuffer table data, if any, * filter the contents of the field based upon the filtering privacy level. * * Primitives and composite strings may be successfully processed at this point. * Other composite types (e.g. structs or tables) must be expanded into the * respective grouping of subfields. * * @param field The reflection field information from the bundled schema * @param table The populated field data, if any * * @return true if field was filtered successfully, false otherwise. */ virtual bool FilterField(const reflection::Field* field, flatbuffers::Table* table) { return false; } /** * Given both reflection object data and the populated flatbuffer table data, if any, * filter the object fields based upon the filtering privacy level. * * @param object The reflection object information from the bundled schema * @param table The populated field data, if any * */ virtual void FilterObject(const reflection::Object* object, flatbuffers::Table* table){}; /** * Given both reflection field data and the populated table data, if any, * filter the contents of the table based upon the filtering privacy level. * * @param schema The reflection schema information from the bundled schema * @param table The populated field data, if any * */ virtual void FilterTable(const reflection::Schema* schema, flatbuffers::Table* table){}; const dumpsys::ReflectionSchema& reflection_schema_; }; class DeveloperPrivacyFilter : public Filter { public: DeveloperPrivacyFilter(const dumpsys::ReflectionSchema& reflection_schema) : Filter(reflection_schema) {} void FilterInPlace(char* dumpsys_data) override {} }; class UserPrivacyFilter : public Filter { public: UserPrivacyFilter(const dumpsys::ReflectionSchema& reflection_schema) : Filter(reflection_schema) {} void FilterInPlace(char* dumpsys_data) override; protected: bool FilterField(const reflection::Field* field, flatbuffers::Table* table) override; void FilterObject(const reflection::Object* object, flatbuffers::Table* table) override; void FilterTable(const reflection::Schema* schema, flatbuffers::Table* table) override; }; bool UserPrivacyFilter::FilterField(const reflection::Field* field, flatbuffers::Table* table) { ASSERT(field != nullptr); ASSERT(table != nullptr); internal::PrivacyLevel privacy_level = internal::FindFieldPrivacyLevel(*field); switch (field->type()->base_type()) { case flatbuffers::BASE_TYPE_INT: return internal::FilterTypeInteger(*field, table, privacy_level); break; case flatbuffers::BASE_TYPE_FLOAT: return internal::FilterTypeFloat(*field, table, privacy_level); break; case flatbuffers::BASE_TYPE_STRING: return internal::FilterTypeString(*field, table, privacy_level); break; case flatbuffers::BASE_TYPE_STRUCT: return internal::FilterTypeStruct(*field, table, privacy_level); break; case flatbuffers::BASE_TYPE_BOOL: return internal::FilterTypeBool(*field, table, privacy_level); break; default: LOG_WARN("%s WARN Unsupported base type\n", __func__); break; } return false; } void UserPrivacyFilter::FilterObject(const reflection::Object* object, flatbuffers::Table* table) { ASSERT(object != nullptr); if (table == nullptr) { return; // table data is not populated } for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) { if (!FilterField(*it, table)) { LOG_ERROR("%s Unable to filter field from an object when it's expected it will work", __func__); }; } } void UserPrivacyFilter::FilterTable(const reflection::Schema* schema, flatbuffers::Table* table) { if (schema == nullptr) { LOG_WARN("%s schema is nullptr...probably ok", __func__); return; } const reflection::Object* object = schema->root_table(); if (object == nullptr) { LOG_WARN("%s reflection object is nullptr...is ok ?", __func__); return; } if (table == nullptr) { return; // table not populated } for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) { if (FilterField(*it, table)) { continue; // Field successfully filtered } // Get the index of this complex non-string object from the schema which is // also the same index into the data table. int32_t index = it->type()->index(); ASSERT(index != -1); flatbuffers::Table* sub_table = table->GetPointer(it->offset()); const reflection::Schema* sub_schema = reflection_schema_.FindInReflectionSchema(schema->objects()->Get(index)->name()->str()); if (sub_schema != nullptr) { FilterTable(sub_schema, sub_table); // Top level schema } else { // Leaf node schema const flatbuffers::String* name = schema->objects()->Get(index)->name(); const reflection::Object* sub_object = internal::FindReflectionObject(schema->objects(), name); if (sub_object != nullptr) { FilterObject(sub_object, sub_table); } else { LOG_ERROR("Unable to find reflection sub object:%s\n", name->c_str()); } } } } void UserPrivacyFilter::FilterInPlace(char* dumpsys_data) { ASSERT(dumpsys_data != nullptr); const reflection::Schema* root_schema = reflection_schema_.FindInReflectionSchema(reflection_schema_.GetRootName()); flatbuffers::Table* table = const_cast(flatbuffers::GetRoot(dumpsys_data)); FilterTable(root_schema, table); } std::unique_ptr Filter::Factory( dumpsys::FilterType filter_type, const dumpsys::ReflectionSchema& reflection_schema) { switch (filter_type) { case dumpsys::FilterType::AS_DEVELOPER: return std::make_unique(reflection_schema); default: return std::make_unique(reflection_schema); } } void bluetooth::dumpsys::FilterInPlace( FilterType filter_type, const ReflectionSchema& reflection_schema, std::string* dumpsys_data) { auto filter = Filter::Factory(filter_type, reflection_schema); filter->FilterInPlace(dumpsys_data->data()); }