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