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