1 /*
2 * Copyright 2020 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 #include <memory>
18
19 #include "dumpsys/filter.h"
20 #include "dumpsys/internal/filter_internal.h"
21 #include "os/log.h"
22
23 using namespace bluetooth;
24 using namespace dumpsys;
25
26 class Filter {
27 public:
Filter(const dumpsys::ReflectionSchema & reflection_schema)28 Filter(const dumpsys::ReflectionSchema& reflection_schema) : reflection_schema_(reflection_schema) {}
29
30 virtual ~Filter() = default;
31
32 virtual void FilterInPlace(char* dumpsys_data) = 0;
33
34 static std::unique_ptr<Filter> Factory(
35 dumpsys::FilterType filter_type, const dumpsys::ReflectionSchema& reflection_schema);
36
37 protected:
38 /**
39 * Given both reflection field data and the populated flatbuffer table data, if any,
40 * filter the contents of the field based upon the filtering privacy level.
41 *
42 * Primitives and composite strings may be successfully processed at this point.
43 * Other composite types (e.g. structs or tables) must be expanded into the
44 * respective grouping of subfields.
45 *
46 * @param field The reflection field information from the bundled schema
47 * @param table The populated field data, if any
48 *
49 * @return true if field was filtered successfully, false otherwise.
50 */
FilterField(const reflection::Field * field,flatbuffers::Table * table)51 virtual bool FilterField(const reflection::Field* field, flatbuffers::Table* table) {
52 return false;
53 }
54
55 /**
56 * Given both reflection object data and the populated flatbuffer table data, if any,
57 * filter the object fields based upon the filtering privacy level.
58 *
59 * @param object The reflection object information from the bundled schema
60 * @param table The populated field data, if any
61 *
62 */
FilterObject(const reflection::Object * object,flatbuffers::Table * table)63 virtual void FilterObject(const reflection::Object* object, flatbuffers::Table* table){};
64
65 /**
66 * Given both reflection field data and the populated table data, if any,
67 * filter the contents of the table based upon the filtering privacy level.
68 *
69 * @param schema The reflection schema information from the bundled schema
70 * @param table The populated field data, if any
71 *
72 */
FilterTable(const reflection::Schema * schema,flatbuffers::Table * table)73 virtual void FilterTable(const reflection::Schema* schema, flatbuffers::Table* table){};
74
75 const dumpsys::ReflectionSchema& reflection_schema_;
76 };
77
78 class DeveloperPrivacyFilter : public Filter {
79 public:
DeveloperPrivacyFilter(const dumpsys::ReflectionSchema & reflection_schema)80 DeveloperPrivacyFilter(const dumpsys::ReflectionSchema& reflection_schema) : Filter(reflection_schema) {}
FilterInPlace(char * dumpsys_data)81 void FilterInPlace(char* dumpsys_data) override {}
82 };
83
84 class UserPrivacyFilter : public Filter {
85 public:
UserPrivacyFilter(const dumpsys::ReflectionSchema & reflection_schema)86 UserPrivacyFilter(const dumpsys::ReflectionSchema& reflection_schema) : Filter(reflection_schema) {}
87 void FilterInPlace(char* dumpsys_data) override;
88
89 protected:
90 bool FilterField(const reflection::Field* field, flatbuffers::Table* table) override;
91 void FilterObject(const reflection::Object* object, flatbuffers::Table* table) override;
92 void FilterTable(const reflection::Schema* schema, flatbuffers::Table* table) override;
93 };
94
FilterField(const reflection::Field * field,flatbuffers::Table * table)95 bool UserPrivacyFilter::FilterField(const reflection::Field* field, flatbuffers::Table* table) {
96 ASSERT(field != nullptr);
97 ASSERT(table != nullptr);
98 internal::PrivacyLevel privacy_level = internal::FindFieldPrivacyLevel(*field);
99
100 switch (field->type()->base_type()) {
101 case flatbuffers::BASE_TYPE_INT:
102 return internal::FilterTypeInteger(*field, table, privacy_level);
103 break;
104 case flatbuffers::BASE_TYPE_FLOAT:
105 return internal::FilterTypeFloat(*field, table, privacy_level);
106 break;
107 case flatbuffers::BASE_TYPE_STRING:
108 return internal::FilterTypeString(*field, table, privacy_level);
109 break;
110 case flatbuffers::BASE_TYPE_STRUCT:
111 return internal::FilterTypeStruct(*field, table, privacy_level);
112 break;
113 case flatbuffers::BASE_TYPE_BOOL:
114 return internal::FilterTypeBool(*field, table, privacy_level);
115 break;
116 default:
117 LOG_WARN("%s WARN Unsupported base type\n", __func__);
118 break;
119 }
120 return false;
121 }
122
FilterObject(const reflection::Object * object,flatbuffers::Table * table)123 void UserPrivacyFilter::FilterObject(const reflection::Object* object, flatbuffers::Table* table) {
124 ASSERT(object != nullptr);
125 if (table == nullptr) {
126 return; // table data is not populated
127 }
128 for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
129 if (!FilterField(*it, table)) {
130 LOG_ERROR("%s Unable to filter field from an object when it's expected it will work", __func__);
131 };
132 }
133 }
134
FilterTable(const reflection::Schema * schema,flatbuffers::Table * table)135 void UserPrivacyFilter::FilterTable(const reflection::Schema* schema, flatbuffers::Table* table) {
136 if (schema == nullptr) {
137 LOG_WARN("%s schema is nullptr...probably ok", __func__);
138 return;
139 }
140
141 const reflection::Object* object = schema->root_table();
142 if (object == nullptr) {
143 LOG_WARN("%s reflection object is nullptr...is ok ?", __func__);
144 return;
145 }
146
147 if (table == nullptr) {
148 return; // table not populated
149 }
150
151 for (auto it = object->fields()->cbegin(); it != object->fields()->cend(); ++it) {
152 if (FilterField(*it, table)) {
153 continue; // Field successfully filtered
154 }
155 // Get the index of this complex non-string object from the schema which is
156 // also the same index into the data table.
157 int32_t index = it->type()->index();
158 ASSERT(index != -1);
159
160 flatbuffers::Table* sub_table = table->GetPointer<flatbuffers::Table*>(it->offset());
161 const reflection::Schema* sub_schema =
162 reflection_schema_.FindInReflectionSchema(schema->objects()->Get(index)->name()->str());
163
164 if (sub_schema != nullptr) {
165 FilterTable(sub_schema, sub_table); // Top level schema
166 } else {
167 // Leaf node schema
168 const flatbuffers::String* name = schema->objects()->Get(index)->name();
169 const reflection::Object* sub_object = internal::FindReflectionObject(schema->objects(), name);
170 if (sub_object != nullptr) {
171 FilterObject(sub_object, sub_table);
172 } else {
173 LOG_ERROR("Unable to find reflection sub object:%s\n", name->c_str());
174 }
175 }
176 }
177 }
178
FilterInPlace(char * dumpsys_data)179 void UserPrivacyFilter::FilterInPlace(char* dumpsys_data) {
180 ASSERT(dumpsys_data != nullptr);
181 const reflection::Schema* root_schema = reflection_schema_.FindInReflectionSchema(reflection_schema_.GetRootName());
182 flatbuffers::Table* table = const_cast<flatbuffers::Table*>(flatbuffers::GetRoot<flatbuffers::Table>(dumpsys_data));
183 FilterTable(root_schema, table);
184 }
185
Factory(dumpsys::FilterType filter_type,const dumpsys::ReflectionSchema & reflection_schema)186 std::unique_ptr<Filter> Filter::Factory(
187 dumpsys::FilterType filter_type, const dumpsys::ReflectionSchema& reflection_schema) {
188 switch (filter_type) {
189 case dumpsys::FilterType::AS_DEVELOPER:
190 return std::make_unique<DeveloperPrivacyFilter>(reflection_schema);
191 default:
192 return std::make_unique<UserPrivacyFilter>(reflection_schema);
193 }
194 }
195
FilterInPlace(FilterType filter_type,const ReflectionSchema & reflection_schema,std::string * dumpsys_data)196 void bluetooth::dumpsys::FilterInPlace(
197 FilterType filter_type, const ReflectionSchema& reflection_schema, std::string* dumpsys_data) {
198 auto filter = Filter::Factory(filter_type, reflection_schema);
199 filter->FilterInPlace(dumpsys_data->data());
200 }
201