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