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 "dumpsys/dumpsys.h"
19
20 #include <bluetooth/log.h>
21 #include <com_android_bluetooth_flags.h>
22 #include <unistd.h>
23
24 #include <future>
25 #include <sstream>
26 #include <string>
27
28 #include "dumpsys/filter.h"
29 #include "dumpsys_data_generated.h"
30 #include "main/shim/stack.h"
31 #include "module.h"
32 #include "module_dumper.h"
33 #include "os/log.h"
34 #include "os/system_properties.h"
35 #include "shim/dumpsys.h"
36 #include "shim/dumpsys_args.h"
37
38 namespace bluetooth {
39 namespace shim {
40
41 static const std::string kReadOnlyDebuggableProperty = "ro.debuggable";
42
43 namespace {
44 constexpr char kModuleName[] = "shim::Dumpsys";
45 constexpr char kDumpsysTitle[] = "----- Gd Dumpsys ------";
46 } // namespace
47
48 struct Dumpsys::impl {
49 public:
50 void DumpWithArgsSync(int fd, const char** args, std::promise<void> promise);
51 int GetNumberOfBundledSchemas() const;
52
53 impl(const Dumpsys& dumpsys_module, const dumpsys::ReflectionSchema& reflection_schema);
54 ~impl() = default;
55
56 protected:
57 void FilterSchema(std::string* dumpsys_data) const;
58 std::string PrintAsJson(std::string* dumpsys_data) const;
59
60 bool IsDebuggable() const;
61
62 private:
63 void DumpWithArgsAsync(int fd, const char** args) const;
64
65 const Dumpsys& dumpsys_module_;
66 const dumpsys::ReflectionSchema reflection_schema_;
67 };
68
69 const ModuleFactory Dumpsys::Factory =
__anon36633cb10202() 70 ModuleFactory([]() { return new Dumpsys(bluetooth::dumpsys::GetBundledSchemaData()); });
71
impl(const Dumpsys & dumpsys_module,const dumpsys::ReflectionSchema & reflection_schema)72 Dumpsys::impl::impl(const Dumpsys& dumpsys_module, const dumpsys::ReflectionSchema& reflection_schema)
73 : dumpsys_module_(dumpsys_module), reflection_schema_(std::move(reflection_schema)) {}
74
GetNumberOfBundledSchemas() const75 int Dumpsys::impl::GetNumberOfBundledSchemas() const {
76 return reflection_schema_.GetNumberOfBundledSchemas();
77 }
78
IsDebuggable() const79 bool Dumpsys::impl::IsDebuggable() const {
80 return (os::GetSystemProperty(kReadOnlyDebuggableProperty) == "1");
81 }
82
FilterSchema(std::string * dumpsys_data) const83 void Dumpsys::impl::FilterSchema(std::string* dumpsys_data) const {
84 log::assert_that(dumpsys_data != nullptr, "assert failed: dumpsys_data != nullptr");
85 dumpsys::FilterSchema(reflection_schema_, dumpsys_data);
86 }
87
PrintAsJson(std::string * dumpsys_data) const88 std::string Dumpsys::impl::PrintAsJson(std::string* dumpsys_data) const {
89 log::assert_that(dumpsys_data != nullptr, "assert failed: dumpsys_data != nullptr");
90
91 const std::string root_name = reflection_schema_.GetRootName();
92 if (root_name.empty()) {
93 char buf[255];
94 snprintf(buf, sizeof(buf), "ERROR: Unable to find root name in prebundled reflection schema\n");
95 log::warn("{}", buf);
96 return std::string(buf);
97 }
98
99 const reflection::Schema* schema = reflection_schema_.FindInReflectionSchema(root_name);
100 if (schema == nullptr) {
101 char buf[255];
102 snprintf(buf, sizeof(buf), "ERROR: Unable to find schema root name:%s\n", root_name.c_str());
103 log::warn("{}", buf);
104 return std::string(buf);
105 }
106
107 flatbuffers::IDLOptions options{};
108 options.output_default_scalars_in_json = true;
109 flatbuffers::Parser parser{options};
110 if (!parser.Deserialize(schema)) {
111 char buf[255];
112 snprintf(buf, sizeof(buf), "ERROR: Unable to deserialize bundle root name:%s\n", root_name.c_str());
113 log::warn("{}", buf);
114 return std::string(buf);
115 }
116
117 std::string jsongen;
118 // GenerateText was renamed to GenText in 23.5.26 because the return behavior was changed.
119 // https://github.com/google/flatbuffers/commit/950a71ab893e96147c30dd91735af6db73f72ae0
120 #if FLATBUFFERS_VERSION_MAJOR < 23 || \
121 (FLATBUFFERS_VERSION_MAJOR == 23 && \
122 (FLATBUFFERS_VERSION_MINOR < 5 || \
123 (FLATBUFFERS_VERSION_MINOR == 5 && FLATBUFFERS_VERSION_REVISION < 26)))
124 flatbuffers::GenerateText(parser, dumpsys_data->data(), &jsongen);
125 #else
126 const char* error = flatbuffers::GenText(parser, dumpsys_data->data(), &jsongen);
127 if (error != nullptr) {
128 log::warn("{}", error);
129 }
130 #endif
131 return jsongen;
132 }
133
DumpWithArgsAsync(int fd,const char ** args) const134 void Dumpsys::impl::DumpWithArgsAsync(int fd, const char** args) const {
135 ParsedDumpsysArgs parsed_dumpsys_args(args);
136 const auto registry = dumpsys_module_.GetModuleRegistry();
137
138 ModuleDumper dumper(fd, *registry, kDumpsysTitle);
139 std::string dumpsys_data;
140 std::ostringstream oss;
141 dumper.DumpState(&dumpsys_data, oss);
142
143 dprintf(fd, " ----- Filtering as Developer -----\n");
144 FilterSchema(&dumpsys_data);
145
146 dprintf(fd, "%s", PrintAsJson(&dumpsys_data).c_str());
147 }
148
DumpWithArgsSync(int fd,const char ** args,std::promise<void> promise)149 void Dumpsys::impl::DumpWithArgsSync(int fd, const char** args, std::promise<void> promise) {
150 if (com::android::bluetooth::flags::dumpsys_acquire_stack_when_executing()) {
151 if (bluetooth::shim::Stack::GetInstance()->LockForDumpsys([=, *this]() {
152 log::info("Started dumpsys procedure");
153 this->DumpWithArgsAsync(fd, args);
154 })) {
155 log::info("Successful dumpsys procedure");
156 } else {
157 log::info("Failed dumpsys procedure as stack was not longer active");
158 }
159 } else {
160 DumpWithArgsAsync(fd, args);
161 }
162 promise.set_value();
163 }
164
Dumpsys(const std::string & pre_bundled_schema)165 Dumpsys::Dumpsys(const std::string& pre_bundled_schema)
166 : reflection_schema_(dumpsys::ReflectionSchema(pre_bundled_schema)) {}
167
168 // DEPRECATED Flag: dumpsys_acquire_stack_when_executing
Dump(int fd,const char ** args)169 void Dumpsys::Dump(int fd, const char** args) {
170 if (fd <= 0) {
171 return;
172 }
173 std::promise<void> promise;
174 auto future = promise.get_future();
175 CallOn(pimpl_.get(), &Dumpsys::impl::DumpWithArgsSync, fd, args, std::move(promise));
176 future.get();
177 }
178 // !DEPRECATED Flag: dumpsys_acquire_stack_when_executing
179
Dump(int fd,const char ** args,std::promise<void> promise)180 void Dumpsys::Dump(int fd, const char** args, std::promise<void> promise) {
181 if (fd <= 0) {
182 promise.set_value();
183 return;
184 }
185 CallOn(pimpl_.get(), &Dumpsys::impl::DumpWithArgsSync, fd, args, std::move(promise));
186 }
187
GetGdShimHandler()188 os::Handler* Dumpsys::GetGdShimHandler() {
189 return GetHandler();
190 }
191
192 /**
193 * Module methods
194 */
ListDependencies(ModuleList *) const195 void Dumpsys::ListDependencies(ModuleList* /* list */) const {}
196
Start()197 void Dumpsys::Start() {
198 pimpl_ = std::make_unique<impl>(*this, reflection_schema_);
199 }
200
Stop()201 void Dumpsys::Stop() {
202 pimpl_.reset();
203 }
204
GetDumpsysData(flatbuffers::FlatBufferBuilder * fb_builder) const205 DumpsysDataFinisher Dumpsys::GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) const {
206 auto name = fb_builder->CreateString("----- Shim Dumpsys -----");
207
208 DumpsysModuleDataBuilder builder(*fb_builder);
209 builder.add_title(name);
210 builder.add_number_of_bundled_schemas(pimpl_->GetNumberOfBundledSchemas());
211 auto dumpsys_data = builder.Finish();
212
213 return [dumpsys_data](DumpsysDataBuilder* builder) { builder->add_shim_dumpsys_data(dumpsys_data); };
214 }
215
ToString() const216 std::string Dumpsys::ToString() const {
217 return kModuleName;
218 }
219
220 } // namespace shim
221 } // namespace bluetooth
222