1 /*
2  * Copyright (C) 2015 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 "Debug.h"
18 
19 #include <algorithm>
20 #include <iostream>
21 #include <map>
22 #include <memory>
23 #include <queue>
24 #include <set>
25 #include <vector>
26 
27 #include "android-base/logging.h"
28 
29 #include "ResourceTable.h"
30 #include "ResourceValues.h"
31 #include "ValueVisitor.h"
32 #include "util/Util.h"
33 
34 namespace aapt {
35 
36 class PrintVisitor : public ValueVisitor {
37  public:
38   using ValueVisitor::Visit;
39 
Visit(Attribute * attr)40   void Visit(Attribute* attr) override {
41     std::cout << "(attr) type=";
42     attr->PrintMask(&std::cout);
43     static constexpr uint32_t kMask =
44         android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
45     if (attr->type_mask & kMask) {
46       for (const auto& symbol : attr->symbols) {
47         std::cout << "\n        " << symbol.symbol.name.value().entry;
48         if (symbol.symbol.id) {
49           std::cout << " (" << symbol.symbol.id.value() << ")";
50         }
51         std::cout << " = " << symbol.value;
52       }
53     }
54   }
55 
Visit(Style * style)56   void Visit(Style* style) override {
57     std::cout << "(style)";
58     if (style->parent) {
59       const Reference& parent_ref = style->parent.value();
60       std::cout << " parent=";
61       if (parent_ref.name) {
62         if (parent_ref.private_reference) {
63           std::cout << "*";
64         }
65         std::cout << parent_ref.name.value() << " ";
66       }
67 
68       if (parent_ref.id) {
69         std::cout << parent_ref.id.value();
70       }
71     }
72 
73     for (const auto& entry : style->entries) {
74       std::cout << "\n        ";
75       if (entry.key.name) {
76         const ResourceName& name = entry.key.name.value();
77         if (!name.package.empty()) {
78           std::cout << name.package << ":";
79         }
80         std::cout << name.entry;
81       }
82 
83       if (entry.key.id) {
84         std::cout << "(" << entry.key.id.value() << ")";
85       }
86 
87       std::cout << "=" << *entry.value;
88     }
89   }
90 
Visit(Array * array)91   void Visit(Array* array) override { array->Print(&std::cout); }
92 
Visit(Plural * plural)93   void Visit(Plural* plural) override { plural->Print(&std::cout); }
94 
Visit(Styleable * styleable)95   void Visit(Styleable* styleable) override {
96     std::cout << "(styleable)";
97     for (const auto& attr : styleable->entries) {
98       std::cout << "\n        ";
99       if (attr.name) {
100         const ResourceName& name = attr.name.value();
101         if (!name.package.empty()) {
102           std::cout << name.package << ":";
103         }
104         std::cout << name.entry;
105       }
106 
107       if (attr.id) {
108         std::cout << "(" << attr.id.value() << ")";
109       }
110     }
111   }
112 
VisitItem(Item * item)113   void VisitItem(Item* item) override { item->Print(&std::cout); }
114 };
115 
PrintTable(ResourceTable * table,const DebugPrintTableOptions & options)116 void Debug::PrintTable(ResourceTable* table,
117                        const DebugPrintTableOptions& options) {
118   PrintVisitor visitor;
119 
120   for (auto& package : table->packages) {
121     std::cout << "Package name=" << package->name;
122     if (package->id) {
123       std::cout << " id=" << std::hex << (int)package->id.value() << std::dec;
124     }
125     std::cout << std::endl;
126 
127     for (const auto& type : package->types) {
128       std::cout << "\n  type " << type->type;
129       if (type->id) {
130         std::cout << " id=" << std::hex << (int)type->id.value() << std::dec;
131       }
132       std::cout << " entryCount=" << type->entries.size() << std::endl;
133 
134       std::vector<const ResourceEntry*> sorted_entries;
135       for (const auto& entry : type->entries) {
136         auto iter = std::lower_bound(
137             sorted_entries.begin(), sorted_entries.end(), entry.get(),
138             [](const ResourceEntry* a, const ResourceEntry* b) -> bool {
139               if (a->id && b->id) {
140                 return a->id.value() < b->id.value();
141               } else if (a->id) {
142                 return true;
143               } else {
144                 return false;
145               }
146             });
147         sorted_entries.insert(iter, entry.get());
148       }
149 
150       for (const ResourceEntry* entry : sorted_entries) {
151         ResourceId id(package->id ? package->id.value() : uint8_t(0),
152                       type->id ? type->id.value() : uint8_t(0),
153                       entry->id ? entry->id.value() : uint16_t(0));
154         ResourceName name(package->name, type->type, entry->name);
155 
156         std::cout << "    spec resource " << id << " " << name;
157         switch (entry->symbol_status.state) {
158           case SymbolState::kPublic:
159             std::cout << " PUBLIC";
160             break;
161           case SymbolState::kPrivate:
162             std::cout << " _PRIVATE_";
163             break;
164           default:
165             break;
166         }
167 
168         std::cout << std::endl;
169 
170         for (const auto& value : entry->values) {
171           std::cout << "      (" << value->config << ") ";
172           value->value->Accept(&visitor);
173           if (options.show_sources && !value->value->GetSource().path.empty()) {
174             std::cout << " src=" << value->value->GetSource();
175           }
176           std::cout << std::endl;
177         }
178       }
179     }
180   }
181 }
182 
GetNodeIndex(const std::vector<ResourceName> & names,const ResourceName & name)183 static size_t GetNodeIndex(const std::vector<ResourceName>& names,
184                            const ResourceName& name) {
185   auto iter = std::lower_bound(names.begin(), names.end(), name);
186   CHECK(iter != names.end());
187   CHECK(*iter == name);
188   return std::distance(names.begin(), iter);
189 }
190 
PrintStyleGraph(ResourceTable * table,const ResourceName & target_style)191 void Debug::PrintStyleGraph(ResourceTable* table,
192                             const ResourceName& target_style) {
193   std::map<ResourceName, std::set<ResourceName>> graph;
194 
195   std::queue<ResourceName> styles_to_visit;
196   styles_to_visit.push(target_style);
197   for (; !styles_to_visit.empty(); styles_to_visit.pop()) {
198     const ResourceName& style_name = styles_to_visit.front();
199     std::set<ResourceName>& parents = graph[style_name];
200     if (!parents.empty()) {
201       // We've already visited this style.
202       continue;
203     }
204 
205     Maybe<ResourceTable::SearchResult> result = table->FindResource(style_name);
206     if (result) {
207       ResourceEntry* entry = result.value().entry;
208       for (const auto& value : entry->values) {
209         if (Style* style = ValueCast<Style>(value->value.get())) {
210           if (style->parent && style->parent.value().name) {
211             parents.insert(style->parent.value().name.value());
212             styles_to_visit.push(style->parent.value().name.value());
213           }
214         }
215       }
216     }
217   }
218 
219   std::vector<ResourceName> names;
220   for (const auto& entry : graph) {
221     names.push_back(entry.first);
222   }
223 
224   std::cout << "digraph styles {\n";
225   for (const auto& name : names) {
226     std::cout << "  node_" << GetNodeIndex(names, name) << " [label=\"" << name
227               << "\"];\n";
228   }
229 
230   for (const auto& entry : graph) {
231     const ResourceName& style_name = entry.first;
232     size_t style_node_index = GetNodeIndex(names, style_name);
233 
234     for (const auto& parent_name : entry.second) {
235       std::cout << "  node_" << style_node_index << " -> "
236                 << "node_" << GetNodeIndex(names, parent_name) << ";\n";
237     }
238   }
239 
240   std::cout << "}" << std::endl;
241 }
242 
DumpHex(const void * data,size_t len)243 void Debug::DumpHex(const void* data, size_t len) {
244   const uint8_t* d = (const uint8_t*)data;
245   for (size_t i = 0; i < len; i++) {
246     std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)d[i]
247               << " ";
248     if (i % 8 == 7) {
249       std::cerr << "\n";
250     }
251   }
252 
253   if (len - 1 % 8 != 7) {
254     std::cerr << std::endl;
255   }
256 }
257 
258 namespace {
259 
260 class XmlPrinter : public xml::Visitor {
261  public:
262   using xml::Visitor::Visit;
263 
Visit(xml::Element * el)264   void Visit(xml::Element* el) override {
265     std::cerr << prefix_;
266     std::cerr << "E: ";
267     if (!el->namespace_uri.empty()) {
268       std::cerr << el->namespace_uri << ":";
269     }
270     std::cerr << el->name << " (line=" << el->line_number << ")\n";
271 
272     for (const xml::Attribute& attr : el->attributes) {
273       std::cerr << prefix_ << "  A: ";
274       if (!attr.namespace_uri.empty()) {
275         std::cerr << attr.namespace_uri << ":";
276       }
277       std::cerr << attr.name;
278 
279       if (attr.compiled_attribute) {
280         std::cerr << "(" << attr.compiled_attribute.value().id.value_or_default(ResourceId(0x0))
281                   << ")";
282       }
283       std::cerr << "=" << attr.value << "\n";
284     }
285 
286     const size_t previous_size = prefix_.size();
287     prefix_ += "  ";
288     xml::Visitor::Visit(el);
289     prefix_.resize(previous_size);
290   }
291 
Visit(xml::Namespace * ns)292   void Visit(xml::Namespace* ns) override {
293     std::cerr << prefix_;
294     std::cerr << "N: " << ns->namespace_prefix << "=" << ns->namespace_uri
295               << " (line=" << ns->line_number << ")\n";
296 
297     const size_t previous_size = prefix_.size();
298     prefix_ += "  ";
299     xml::Visitor::Visit(ns);
300     prefix_.resize(previous_size);
301   }
302 
Visit(xml::Text * text)303   void Visit(xml::Text* text) override {
304     std::cerr << prefix_;
305     std::cerr << "T: '" << text->text << "'\n";
306   }
307 
308  private:
309   std::string prefix_;
310 };
311 
312 }  // namespace
313 
DumpXml(xml::XmlResource * doc)314 void Debug::DumpXml(xml::XmlResource* doc) {
315   XmlPrinter printer;
316   doc->root->Accept(&printer);
317 }
318 
319 }  // namespace aapt
320