1 /*
2 * Copyright 2019 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 #define LOG_TAG "bt_gd_shim"
17
18 #include <future>
19 #include <string>
20
21 #include "dumpsys/filter.h"
22 #include "generated_dumpsys_bundled_schema.h"
23 #include "module.h"
24 #include "os/log.h"
25 #include "os/system_properties.h"
26 #include "shim/dumpsys.h"
27 #include "shim/dumpsys_args.h"
28
29 namespace bluetooth {
30 namespace shim {
31
32 static const std::string kReadOnlyDebuggableProperty = "ro.debuggable";
33
34 namespace {
35 constexpr char kModuleName[] = "shim::Dumpsys";
36 constexpr char kDumpsysTitle[] = "----- Gd Dumpsys ------";
37 } // namespace
38
39 struct Dumpsys::impl {
40 public:
41 void DumpWithArgsSync(int fd, const char** args, std::promise<void> promise);
42 int GetNumberOfBundledSchemas() const;
43
44 impl(const Dumpsys& dumpsys_module, const dumpsys::ReflectionSchema& reflection_schema);
45 ~impl() = default;
46
47 protected:
48 void FilterAsUser(std::string* dumpsys_data);
49 void FilterAsDeveloper(std::string* dumpsys_data);
50 std::string PrintAsJson(std::string* dumpsys_data) const;
51
52 bool IsDebuggable() const;
53
54 private:
55 void DumpWithArgsAsync(int fd, const char** args);
56
57 const Dumpsys& dumpsys_module_;
58 const dumpsys::ReflectionSchema reflection_schema_;
59 };
60
61 const ModuleFactory Dumpsys::Factory =
__anon8446019b0202() 62 ModuleFactory([]() { return new Dumpsys(bluetooth::dumpsys::GetBundledSchemaData()); });
63
impl(const Dumpsys & dumpsys_module,const dumpsys::ReflectionSchema & reflection_schema)64 Dumpsys::impl::impl(const Dumpsys& dumpsys_module, const dumpsys::ReflectionSchema& reflection_schema)
65 : dumpsys_module_(dumpsys_module), reflection_schema_(std::move(reflection_schema)) {}
66
GetNumberOfBundledSchemas() const67 int Dumpsys::impl::GetNumberOfBundledSchemas() const {
68 return reflection_schema_.GetNumberOfBundledSchemas();
69 }
70
IsDebuggable() const71 bool Dumpsys::impl::IsDebuggable() const {
72 return (os::GetSystemProperty(kReadOnlyDebuggableProperty) == "1");
73 }
74
FilterAsDeveloper(std::string * dumpsys_data)75 void Dumpsys::impl::FilterAsDeveloper(std::string* dumpsys_data) {
76 ASSERT(dumpsys_data != nullptr);
77 dumpsys::FilterInPlace(dumpsys::FilterType::AS_DEVELOPER, reflection_schema_, dumpsys_data);
78 }
79
FilterAsUser(std::string * dumpsys_data)80 void Dumpsys::impl::FilterAsUser(std::string* dumpsys_data) {
81 ASSERT(dumpsys_data != nullptr);
82 dumpsys::FilterInPlace(dumpsys::FilterType::AS_USER, reflection_schema_, dumpsys_data);
83 }
84
PrintAsJson(std::string * dumpsys_data) const85 std::string Dumpsys::impl::PrintAsJson(std::string* dumpsys_data) const {
86 ASSERT(dumpsys_data != nullptr);
87
88 const std::string root_name = reflection_schema_.GetRootName();
89 if (root_name.empty()) {
90 char buf[255];
91 snprintf(buf, sizeof(buf), "ERROR: Unable to find root name in prebundled reflection schema\n");
92 LOG_WARN("%s", buf);
93 return std::string(buf);
94 }
95
96 const reflection::Schema* schema = reflection_schema_.FindInReflectionSchema(root_name);
97 if (schema == nullptr) {
98 char buf[255];
99 snprintf(buf, sizeof(buf), "ERROR: Unable to find schema root name:%s\n", root_name.c_str());
100 LOG_WARN("%s", buf);
101 return std::string(buf);
102 }
103
104 flatbuffers::Parser parser;
105 if (!parser.Deserialize(schema)) {
106 char buf[255];
107 snprintf(buf, sizeof(buf), "ERROR: Unable to deserialize bundle root name:%s\n", root_name.c_str());
108 LOG_WARN("%s", buf);
109 return std::string(buf);
110 }
111
112 std::string jsongen;
113 flatbuffers::GenerateText(parser, dumpsys_data->data(), &jsongen);
114 return jsongen;
115 }
116
DumpWithArgsAsync(int fd,const char ** args)117 void Dumpsys::impl::DumpWithArgsAsync(int fd, const char** args) {
118 ParsedDumpsysArgs parsed_dumpsys_args(args);
119 const auto registry = dumpsys_module_.GetModuleRegistry();
120
121 ModuleDumper dumper(*registry, kDumpsysTitle);
122 std::string dumpsys_data;
123 dumper.DumpState(&dumpsys_data);
124
125 if (parsed_dumpsys_args.IsDeveloper() || IsDebuggable()) {
126 dprintf(fd, " ----- Filtering as Developer -----\n");
127 FilterAsDeveloper(&dumpsys_data);
128 } else {
129 dprintf(fd, " ----- Filtering as User -----\n");
130 FilterAsUser(&dumpsys_data);
131 }
132
133 dprintf(fd, "%s", PrintAsJson(&dumpsys_data).c_str());
134 }
135
DumpWithArgsSync(int fd,const char ** args,std::promise<void> promise)136 void Dumpsys::impl::DumpWithArgsSync(int fd, const char** args, std::promise<void> promise) {
137 DumpWithArgsAsync(fd, args);
138 promise.set_value();
139 }
140
Dumpsys(const std::string & pre_bundled_schema)141 Dumpsys::Dumpsys(const std::string& pre_bundled_schema)
142 : reflection_schema_(dumpsys::ReflectionSchema(pre_bundled_schema)) {}
143
Dump(int fd,const char ** args)144 void Dumpsys::Dump(int fd, const char** args) {
145 std::promise<void> promise;
146 auto future = promise.get_future();
147 CallOn(pimpl_.get(), &Dumpsys::impl::DumpWithArgsSync, fd, args, std::move(promise));
148 future.get();
149 }
150
Dump(int fd,const char ** args,std::promise<void> promise)151 void Dumpsys::Dump(int fd, const char** args, std::promise<void> promise) {
152 CallOn(pimpl_.get(), &Dumpsys::impl::DumpWithArgsSync, fd, args, std::move(promise));
153 }
154
GetGdShimHandler()155 os::Handler* Dumpsys::GetGdShimHandler() {
156 return GetHandler();
157 }
158
159 /**
160 * Module methods
161 */
ListDependencies(ModuleList * list)162 void Dumpsys::ListDependencies(ModuleList* list) {}
163
Start()164 void Dumpsys::Start() {
165 pimpl_ = std::make_unique<impl>(*this, reflection_schema_);
166 }
167
Stop()168 void Dumpsys::Stop() {
169 pimpl_.reset();
170 }
171
GetDumpsysData(flatbuffers::FlatBufferBuilder * fb_builder) const172 DumpsysDataFinisher Dumpsys::GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) const {
173 auto name = fb_builder->CreateString("----- Shim Dumpsys -----");
174 auto example_piecemeal_string = fb_builder->CreateString("Example Piecemeal String");
175 auto example_instant_string = fb_builder->CreateString("Example Instant String");
176
177 ExamplePiecemealTableBuilder example_piecemeal_table_builder(*fb_builder);
178 example_piecemeal_table_builder.add_example_string(example_piecemeal_string);
179 example_piecemeal_table_builder.add_example_int(123);
180 example_piecemeal_table_builder.add_example_float(1.23);
181 auto example_piecemeal_table = example_piecemeal_table_builder.Finish();
182
183 auto example_instant_table = CreateExampleInstantTable(*fb_builder, example_instant_string, 246, 2.46);
184
185 DumpsysModuleDataBuilder builder(*fb_builder);
186 builder.add_title(name);
187 builder.add_number_of_bundled_schemas(pimpl_->GetNumberOfBundledSchemas());
188 builder.add_example_piecemeal_table(example_piecemeal_table);
189 builder.add_example_instant_table(example_instant_table);
190 auto dumpsys_data = builder.Finish();
191
192 return [dumpsys_data](DumpsysDataBuilder* builder) { builder->add_shim_dumpsys_data(dumpsys_data); };
193 }
194
ToString() const195 std::string Dumpsys::ToString() const {
196 return kModuleName;
197 }
198
199 } // namespace shim
200 } // namespace bluetooth
201