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 <map>
21 #include <memory>
22 #include <queue>
23 #include <set>
24 #include <vector>
25
26 #include "android-base/logging.h"
27 #include "android-base/stringprintf.h"
28
29 #include "ResourceTable.h"
30 #include "ResourceValues.h"
31 #include "ValueVisitor.h"
32 #include "text/Printer.h"
33 #include "util/Util.h"
34
35 using ::aapt::text::Printer;
36 using ::android::StringPiece;
37 using ::android::base::StringPrintf;
38
39 namespace aapt {
40
41 namespace {
42
43 class ValueHeadlinePrinter : public ConstValueVisitor {
44 public:
45 using ConstValueVisitor::Visit;
46
ValueHeadlinePrinter(const std::string & package,Printer * printer)47 explicit ValueHeadlinePrinter(const std::string& package, Printer* printer)
48 : package_(package), printer_(printer) {
49 }
50
Visit(const Attribute * attr)51 void Visit(const Attribute* attr) override {
52 printer_->Print("(attr) type=");
53 printer_->Print(attr->MaskString());
54 if (!attr->symbols.empty()) {
55 printer_->Print(StringPrintf(" size=%zd", attr->symbols.size()));
56 }
57 }
58
Visit(const Style * style)59 void Visit(const Style* style) override {
60 printer_->Print(StringPrintf("(style) size=%zd", style->entries.size()));
61 if (style->parent) {
62 printer_->Print(" parent=");
63
64 const Reference& parent_ref = style->parent.value();
65 if (parent_ref.name) {
66 if (parent_ref.private_reference) {
67 printer_->Print("*");
68 }
69
70 const ResourceName& parent_name = parent_ref.name.value();
71 if (package_ != parent_name.package) {
72 printer_->Print(parent_name.package);
73 printer_->Print(":");
74 }
75 printer_->Print(to_string(parent_name.type));
76 printer_->Print("/");
77 printer_->Print(parent_name.entry);
78 if (parent_ref.id) {
79 printer_->Print(" (");
80 printer_->Print(parent_ref.id.value().to_string());
81 printer_->Print(")");
82 }
83 } else if (parent_ref.id) {
84 printer_->Print(parent_ref.id.value().to_string());
85 } else {
86 printer_->Print("???");
87 }
88 }
89 }
90
Visit(const Array * array)91 void Visit(const Array* array) override {
92 printer_->Print(StringPrintf("(array) size=%zd", array->elements.size()));
93 }
94
Visit(const Plural * plural)95 void Visit(const Plural* plural) override {
96 size_t count = std::count_if(plural->values.begin(), plural->values.end(),
97 [](const std::unique_ptr<Item>& v) { return v != nullptr; });
98 printer_->Print(StringPrintf("(plurals) size=%zd", count));
99 }
100
Visit(const Styleable * styleable)101 void Visit(const Styleable* styleable) override {
102 printer_->Println(StringPrintf("(styleable) size=%zd", styleable->entries.size()));
103 }
104
VisitItem(const Item * item)105 void VisitItem(const Item* item) override {
106 // Pretty much guaranteed to be one line.
107 if (const Reference* ref = ValueCast<Reference>(item)) {
108 // Special case Reference so that we can print local resources without a package name.
109 ref->PrettyPrint(package_, printer_);
110 } else {
111 item->PrettyPrint(printer_);
112 }
113 }
114
115 private:
116 std::string package_;
117 Printer* printer_;
118 };
119
120 class ValueBodyPrinter : public ConstValueVisitor {
121 public:
122 using ConstValueVisitor::Visit;
123
ValueBodyPrinter(const std::string & package,Printer * printer)124 explicit ValueBodyPrinter(const std::string& package, Printer* printer)
125 : package_(package), printer_(printer) {
126 }
127
Visit(const Attribute * attr)128 void Visit(const Attribute* attr) override {
129 constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
130 if (attr->type_mask & kMask) {
131 for (const auto& symbol : attr->symbols) {
132 if (symbol.symbol.name) {
133 printer_->Print(symbol.symbol.name.value().entry);
134
135 if (symbol.symbol.id) {
136 printer_->Print("(");
137 printer_->Print(symbol.symbol.id.value().to_string());
138 printer_->Print(")");
139 }
140 } else if (symbol.symbol.id) {
141 printer_->Print(symbol.symbol.id.value().to_string());
142 } else {
143 printer_->Print("???");
144 }
145
146 printer_->Println(StringPrintf("=0x%08x", symbol.value));
147 }
148 }
149 }
150
Visit(const Style * style)151 void Visit(const Style* style) override {
152 for (const auto& entry : style->entries) {
153 if (entry.key.name) {
154 const ResourceName& name = entry.key.name.value();
155 if (!name.package.empty() && name.package != package_) {
156 printer_->Print(name.package);
157 printer_->Print(":");
158 }
159 printer_->Print(name.entry);
160
161 if (entry.key.id) {
162 printer_->Print("(");
163 printer_->Print(entry.key.id.value().to_string());
164 printer_->Print(")");
165 }
166 } else if (entry.key.id) {
167 printer_->Print(entry.key.id.value().to_string());
168 } else {
169 printer_->Print("???");
170 }
171
172 printer_->Print("=");
173 PrintItem(*entry.value);
174 printer_->Println();
175 }
176 }
177
Visit(const Array * array)178 void Visit(const Array* array) override {
179 const size_t count = array->elements.size();
180 printer_->Print("[");
181 if (count > 0) {
182 for (size_t i = 0u; i < count; i++) {
183 if (i != 0u && i % 4u == 0u) {
184 printer_->Println();
185 printer_->Print(" ");
186 }
187 PrintItem(*array->elements[i]);
188 if (i != count - 1) {
189 printer_->Print(", ");
190 }
191 }
192 printer_->Println("]");
193 }
194 }
195
Visit(const Plural * plural)196 void Visit(const Plural* plural) override {
197 constexpr std::array<const char*, Plural::Count> kPluralNames = {
198 {"zero", "one", "two", "few", "many", "other"}};
199
200 for (size_t i = 0; i < Plural::Count; i++) {
201 if (plural->values[i] != nullptr) {
202 printer_->Print(StringPrintf("%s=", kPluralNames[i]));
203 PrintItem(*plural->values[i]);
204 printer_->Println();
205 }
206 }
207 }
208
Visit(const Styleable * styleable)209 void Visit(const Styleable* styleable) override {
210 for (const auto& attr : styleable->entries) {
211 if (attr.name) {
212 const ResourceName& name = attr.name.value();
213 if (!name.package.empty() && name.package != package_) {
214 printer_->Print(name.package);
215 printer_->Print(":");
216 }
217 printer_->Print(name.entry);
218
219 if (attr.id) {
220 printer_->Print("(");
221 printer_->Print(attr.id.value().to_string());
222 printer_->Print(")");
223 }
224 }
225
226 if (attr.id) {
227 printer_->Print(attr.id.value().to_string());
228 }
229 printer_->Println();
230 }
231 }
232
VisitItem(const Item * item)233 void VisitItem(const Item* item) override {
234 // Intentionally left empty, we already printed the Items.
235 }
236
237 private:
PrintItem(const Item & item)238 void PrintItem(const Item& item) {
239 if (const Reference* ref = ValueCast<Reference>(&item)) {
240 // Special case Reference so that we can print local resources without a package name.
241 ref->PrettyPrint(package_, printer_);
242 } else {
243 item.PrettyPrint(printer_);
244 }
245 }
246
247 std::string package_;
248 Printer* printer_;
249 };
250
251 } // namespace
252
PrintTable(const ResourceTable & table,const DebugPrintTableOptions & options,Printer * printer)253 void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
254 Printer* printer) {
255 for (const auto& package : table.packages) {
256 ValueHeadlinePrinter headline_printer(package->name, printer);
257 ValueBodyPrinter body_printer(package->name, printer);
258
259 printer->Print("Package name=");
260 printer->Print(package->name);
261 if (package->id) {
262 printer->Print(StringPrintf(" id=%02x", package->id.value()));
263 }
264 printer->Println();
265
266 printer->Indent();
267 for (const auto& type : package->types) {
268 printer->Print("type ");
269 printer->Print(to_string(type->type));
270 if (type->id) {
271 printer->Print(StringPrintf(" id=%02x", type->id.value()));
272 }
273 printer->Println(StringPrintf(" entryCount=%zd", type->entries.size()));
274
275 std::vector<const ResourceEntry*> sorted_entries;
276 for (const auto& entry : type->entries) {
277 auto iter = std::lower_bound(
278 sorted_entries.begin(), sorted_entries.end(), entry.get(),
279 [](const ResourceEntry* a, const ResourceEntry* b) -> bool {
280 if (a->id && b->id) {
281 return a->id.value() < b->id.value();
282 } else if (a->id) {
283 return true;
284 } else {
285 return false;
286 }
287 });
288 sorted_entries.insert(iter, entry.get());
289 }
290
291 printer->Indent();
292 for (const ResourceEntry* entry : sorted_entries) {
293 const ResourceId id(package->id.value_or_default(0), type->id.value_or_default(0),
294 entry->id.value_or_default(0));
295
296 printer->Print("resource ");
297 printer->Print(id.to_string());
298 printer->Print(" ");
299
300 // Write the name without the package (this is obvious and too verbose).
301 printer->Print(to_string(type->type));
302 printer->Print("/");
303 printer->Print(entry->name);
304
305 switch (entry->visibility.level) {
306 case Visibility::Level::kPublic:
307 printer->Print(" PUBLIC");
308 break;
309 case Visibility::Level::kPrivate:
310 printer->Print(" _PRIVATE_");
311 break;
312 case Visibility::Level::kUndefined:
313 // Print nothing.
314 break;
315 }
316
317 printer->Println();
318
319 if (options.show_values) {
320 printer->Indent();
321 for (const auto& value : entry->values) {
322 printer->Print("(");
323 printer->Print(value->config.to_string());
324 printer->Print(") ");
325 value->value->Accept(&headline_printer);
326 if (options.show_sources && !value->value->GetSource().path.empty()) {
327 printer->Print(" src=");
328 printer->Print(value->value->GetSource().to_string());
329 }
330 printer->Println();
331 printer->Indent();
332 value->value->Accept(&body_printer);
333 printer->Undent();
334 }
335 printer->Undent();
336 }
337 }
338 printer->Undent();
339 }
340 printer->Undent();
341 }
342 }
343
GetNodeIndex(const std::vector<ResourceName> & names,const ResourceName & name)344 static size_t GetNodeIndex(const std::vector<ResourceName>& names, const ResourceName& name) {
345 auto iter = std::lower_bound(names.begin(), names.end(), name);
346 CHECK(iter != names.end());
347 CHECK(*iter == name);
348 return std::distance(names.begin(), iter);
349 }
350
PrintStyleGraph(ResourceTable * table,const ResourceName & target_style)351 void Debug::PrintStyleGraph(ResourceTable* table, const ResourceName& target_style) {
352 std::map<ResourceName, std::set<ResourceName>> graph;
353
354 std::queue<ResourceName> styles_to_visit;
355 styles_to_visit.push(target_style);
356 for (; !styles_to_visit.empty(); styles_to_visit.pop()) {
357 const ResourceName& style_name = styles_to_visit.front();
358 std::set<ResourceName>& parents = graph[style_name];
359 if (!parents.empty()) {
360 // We've already visited this style.
361 continue;
362 }
363
364 Maybe<ResourceTable::SearchResult> result = table->FindResource(style_name);
365 if (result) {
366 ResourceEntry* entry = result.value().entry;
367 for (const auto& value : entry->values) {
368 if (Style* style = ValueCast<Style>(value->value.get())) {
369 if (style->parent && style->parent.value().name) {
370 parents.insert(style->parent.value().name.value());
371 styles_to_visit.push(style->parent.value().name.value());
372 }
373 }
374 }
375 }
376 }
377
378 std::vector<ResourceName> names;
379 for (const auto& entry : graph) {
380 names.push_back(entry.first);
381 }
382
383 std::cout << "digraph styles {\n";
384 for (const auto& name : names) {
385 std::cout << " node_" << GetNodeIndex(names, name) << " [label=\"" << name << "\"];\n";
386 }
387
388 for (const auto& entry : graph) {
389 const ResourceName& style_name = entry.first;
390 size_t style_node_index = GetNodeIndex(names, style_name);
391
392 for (const auto& parent_name : entry.second) {
393 std::cout << " node_" << style_node_index << " -> "
394 << "node_" << GetNodeIndex(names, parent_name) << ";\n";
395 }
396 }
397
398 std::cout << "}" << std::endl;
399 }
400
DumpHex(const void * data,size_t len)401 void Debug::DumpHex(const void* data, size_t len) {
402 const uint8_t* d = (const uint8_t*)data;
403 for (size_t i = 0; i < len; i++) {
404 std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)d[i] << " ";
405 if (i % 8 == 7) {
406 std::cerr << "\n";
407 }
408 }
409
410 if (len - 1 % 8 != 7) {
411 std::cerr << std::endl;
412 }
413 }
414
DumpResStringPool(const android::ResStringPool * pool,text::Printer * printer)415 void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer) {
416 using namespace android;
417
418 if (pool->getError() == NO_INIT) {
419 printer->Print("String pool is unitialized.\n");
420 return;
421 } else if (pool->getError() != NO_ERROR) {
422 printer->Print("String pool is corrupt/invalid.\n");
423 return;
424 }
425
426 SortedVector<const void*> uniqueStrings;
427 const size_t N = pool->size();
428 for (size_t i=0; i<N; i++) {
429 size_t len;
430 if (pool->isUTF8()) {
431 uniqueStrings.add(pool->string8At(i, &len));
432 } else {
433 uniqueStrings.add(pool->stringAt(i, &len));
434 }
435 }
436
437 printer->Print(StringPrintf("String pool of %zd unique %s %s strings, %zd entries and %zd styles "
438 "using %zd bytes:\n", uniqueStrings.size(),
439 pool->isUTF8() ? "UTF-8" : "UTF-16",
440 pool->isSorted() ? "sorted" : "non-sorted", N, pool->styleCount(),
441 pool->bytes()));
442
443 const size_t NS = pool->size();
444 for (size_t s=0; s<NS; s++) {
445 String8 str = pool->string8ObjectAt(s);
446 printer->Print(StringPrintf("String #%zd : %s\n", s, str.string()));
447 }
448 }
449
450 namespace {
451
452 class XmlPrinter : public xml::ConstVisitor {
453 public:
454 using xml::ConstVisitor::Visit;
455
XmlPrinter(Printer * printer)456 explicit XmlPrinter(Printer* printer) : printer_(printer) {
457 }
458
Visit(const xml::Element * el)459 void Visit(const xml::Element* el) override {
460 for (const xml::NamespaceDecl& decl : el->namespace_decls) {
461 printer_->Println(StringPrintf("N: %s=%s (line=%zu)", decl.prefix.c_str(), decl.uri.c_str(),
462 decl.line_number));
463 printer_->Indent();
464 }
465
466 printer_->Print("E: ");
467 if (!el->namespace_uri.empty()) {
468 printer_->Print(el->namespace_uri);
469 printer_->Print(":");
470 }
471 printer_->Println(StringPrintf("%s (line=%zu)", el->name.c_str(), el->line_number));
472 printer_->Indent();
473
474 for (const xml::Attribute& attr : el->attributes) {
475 printer_->Print("A: ");
476 if (!attr.namespace_uri.empty()) {
477 printer_->Print(attr.namespace_uri);
478 printer_->Print(":");
479 }
480 printer_->Print(attr.name);
481
482 if (attr.compiled_attribute) {
483 printer_->Print("(");
484 printer_->Print(
485 attr.compiled_attribute.value().id.value_or_default(ResourceId(0)).to_string());
486 printer_->Print(")");
487 }
488 printer_->Print("=");
489 if (attr.compiled_value != nullptr) {
490 attr.compiled_value->PrettyPrint(printer_);
491 } else {
492 printer_->Print("\"");
493 printer_->Print(attr.value);
494 printer_->Print("\"");
495 }
496
497 if (!attr.value.empty()) {
498 printer_->Print(" (Raw: \"");
499 printer_->Print(attr.value);
500 printer_->Print("\")");
501 }
502 printer_->Println();
503 }
504
505 printer_->Indent();
506 xml::ConstVisitor::Visit(el);
507 printer_->Undent();
508 printer_->Undent();
509
510 for (size_t i = 0; i < el->namespace_decls.size(); i++) {
511 printer_->Undent();
512 }
513 }
514
Visit(const xml::Text * text)515 void Visit(const xml::Text* text) override {
516 printer_->Println(StringPrintf("T: '%s'", text->text.c_str()));
517 }
518
519 private:
520 Printer* printer_;
521 };
522
523 } // namespace
524
DumpXml(const xml::XmlResource & doc,Printer * printer)525 void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) {
526 XmlPrinter xml_visitor(printer);
527 doc.root->Accept(&xml_visitor);
528 }
529
530 } // namespace aapt
531