Home | History | Annotate | Download | only in aapt2
      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 
     47   explicit ValueHeadlinePrinter(const std::string& package, Printer* printer)
     48       : package_(package), printer_(printer) {
     49   }
     50 
     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 
     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 
     91   void Visit(const Array* array) override {
     92     printer_->Print(StringPrintf("(array) size=%zd", array->elements.size()));
     93   }
     94 
     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 
    101   void Visit(const Styleable* styleable) override {
    102     printer_->Println(StringPrintf("(styleable) size=%zd", styleable->entries.size()));
    103   }
    104 
    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 
    124   explicit ValueBodyPrinter(const std::string& package, Printer* printer)
    125       : package_(package), printer_(printer) {
    126   }
    127 
    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         printer_->Print(symbol.symbol.name.value().entry);
    133         if (symbol.symbol.id) {
    134           printer_->Print("(");
    135           printer_->Print(symbol.symbol.id.value().to_string());
    136           printer_->Print(")");
    137         }
    138         printer_->Println(StringPrintf("=0x%08x", symbol.value));
    139       }
    140     }
    141   }
    142 
    143   void Visit(const Style* style) override {
    144     for (const auto& entry : style->entries) {
    145       if (entry.key.name) {
    146         const ResourceName& name = entry.key.name.value();
    147         if (!name.package.empty() && name.package != package_) {
    148           printer_->Print(name.package);
    149           printer_->Print(":");
    150         }
    151         printer_->Print(name.entry);
    152 
    153         if (entry.key.id) {
    154           printer_->Print("(");
    155           printer_->Print(entry.key.id.value().to_string());
    156           printer_->Print(")");
    157         }
    158       } else if (entry.key.id) {
    159         printer_->Print(entry.key.id.value().to_string());
    160       } else {
    161         printer_->Print("???");
    162       }
    163 
    164       printer_->Print("=");
    165       PrintItem(*entry.value);
    166       printer_->Println();
    167     }
    168   }
    169 
    170   void Visit(const Array* array) override {
    171     const size_t count = array->elements.size();
    172     printer_->Print("[");
    173     if (count > 0) {
    174       for (size_t i = 0u; i < count; i++) {
    175         if (i != 0u && i % 4u == 0u) {
    176           printer_->Println();
    177           printer_->Print(" ");
    178         }
    179         PrintItem(*array->elements[i]);
    180         if (i != count - 1) {
    181           printer_->Print(", ");
    182         }
    183       }
    184       printer_->Println("]");
    185     }
    186   }
    187 
    188   void Visit(const Plural* plural) override {
    189     constexpr std::array<const char*, Plural::Count> kPluralNames = {
    190         {"zero", "one", "two", "few", "many", "other"}};
    191 
    192     for (size_t i = 0; i < Plural::Count; i++) {
    193       if (plural->values[i] != nullptr) {
    194         printer_->Print(StringPrintf("%s=", kPluralNames[i]));
    195         PrintItem(*plural->values[i]);
    196         printer_->Println();
    197       }
    198     }
    199   }
    200 
    201   void Visit(const Styleable* styleable) override {
    202     for (const auto& attr : styleable->entries) {
    203       if (attr.name) {
    204         const ResourceName& name = attr.name.value();
    205         if (!name.package.empty() && name.package != package_) {
    206           printer_->Print(name.package);
    207           printer_->Print(":");
    208         }
    209         printer_->Print(name.entry);
    210 
    211         if (attr.id) {
    212           printer_->Print("(");
    213           printer_->Print(attr.id.value().to_string());
    214           printer_->Print(")");
    215         }
    216       }
    217 
    218       if (attr.id) {
    219         printer_->Print(attr.id.value().to_string());
    220       }
    221       printer_->Println();
    222     }
    223   }
    224 
    225   void VisitItem(const Item* item) override {
    226     // Intentionally left empty, we already printed the Items.
    227   }
    228 
    229  private:
    230   void PrintItem(const Item& item) {
    231     if (const Reference* ref = ValueCast<Reference>(&item)) {
    232       // Special case Reference so that we can print local resources without a package name.
    233       ref->PrettyPrint(package_, printer_);
    234     } else {
    235       item.PrettyPrint(printer_);
    236     }
    237   }
    238 
    239   std::string package_;
    240   Printer* printer_;
    241 };
    242 
    243 }  // namespace
    244 
    245 void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
    246                        Printer* printer) {
    247   for (const auto& package : table.packages) {
    248     ValueHeadlinePrinter headline_printer(package->name, printer);
    249     ValueBodyPrinter body_printer(package->name, printer);
    250 
    251     printer->Print("Package name=");
    252     printer->Print(package->name);
    253     if (package->id) {
    254       printer->Print(StringPrintf(" id=%02x", package->id.value()));
    255     }
    256     printer->Println();
    257 
    258     printer->Indent();
    259     for (const auto& type : package->types) {
    260       printer->Print("type ");
    261       printer->Print(to_string(type->type));
    262       if (type->id) {
    263         printer->Print(StringPrintf(" id=%02x", type->id.value()));
    264       }
    265       printer->Println(StringPrintf(" entryCount=%zd", type->entries.size()));
    266 
    267       std::vector<const ResourceEntry*> sorted_entries;
    268       for (const auto& entry : type->entries) {
    269         auto iter = std::lower_bound(
    270             sorted_entries.begin(), sorted_entries.end(), entry.get(),
    271             [](const ResourceEntry* a, const ResourceEntry* b) -> bool {
    272               if (a->id && b->id) {
    273                 return a->id.value() < b->id.value();
    274               } else if (a->id) {
    275                 return true;
    276               } else {
    277                 return false;
    278               }
    279             });
    280         sorted_entries.insert(iter, entry.get());
    281       }
    282 
    283       printer->Indent();
    284       for (const ResourceEntry* entry : sorted_entries) {
    285         const ResourceId id(package->id.value_or_default(0), type->id.value_or_default(0),
    286                             entry->id.value_or_default(0));
    287 
    288         printer->Print("resource ");
    289         printer->Print(id.to_string());
    290         printer->Print(" ");
    291 
    292         // Write the name without the package (this is obvious and too verbose).
    293         printer->Print(to_string(type->type));
    294         printer->Print("/");
    295         printer->Print(entry->name);
    296 
    297         switch (entry->visibility.level) {
    298           case Visibility::Level::kPublic:
    299             printer->Print(" PUBLIC");
    300             break;
    301           case Visibility::Level::kPrivate:
    302             printer->Print(" _PRIVATE_");
    303             break;
    304           case Visibility::Level::kUndefined:
    305             // Print nothing.
    306             break;
    307         }
    308 
    309         if (entry->overlayable) {
    310           printer->Print(" OVERLAYABLE");
    311         }
    312 
    313         printer->Println();
    314 
    315         if (options.show_values) {
    316           printer->Indent();
    317           for (const auto& value : entry->values) {
    318             printer->Print("(");
    319             printer->Print(value->config.to_string());
    320             printer->Print(") ");
    321             value->value->Accept(&headline_printer);
    322             if (options.show_sources && !value->value->GetSource().path.empty()) {
    323               printer->Print(" src=");
    324               printer->Print(value->value->GetSource().to_string());
    325             }
    326             printer->Println();
    327             printer->Indent();
    328             value->value->Accept(&body_printer);
    329             printer->Undent();
    330           }
    331           printer->Undent();
    332         }
    333       }
    334       printer->Undent();
    335     }
    336     printer->Undent();
    337   }
    338 }
    339 
    340 static size_t GetNodeIndex(const std::vector<ResourceName>& names, const ResourceName& name) {
    341   auto iter = std::lower_bound(names.begin(), names.end(), name);
    342   CHECK(iter != names.end());
    343   CHECK(*iter == name);
    344   return std::distance(names.begin(), iter);
    345 }
    346 
    347 void Debug::PrintStyleGraph(ResourceTable* table, const ResourceName& target_style) {
    348   std::map<ResourceName, std::set<ResourceName>> graph;
    349 
    350   std::queue<ResourceName> styles_to_visit;
    351   styles_to_visit.push(target_style);
    352   for (; !styles_to_visit.empty(); styles_to_visit.pop()) {
    353     const ResourceName& style_name = styles_to_visit.front();
    354     std::set<ResourceName>& parents = graph[style_name];
    355     if (!parents.empty()) {
    356       // We've already visited this style.
    357       continue;
    358     }
    359 
    360     Maybe<ResourceTable::SearchResult> result = table->FindResource(style_name);
    361     if (result) {
    362       ResourceEntry* entry = result.value().entry;
    363       for (const auto& value : entry->values) {
    364         if (Style* style = ValueCast<Style>(value->value.get())) {
    365           if (style->parent && style->parent.value().name) {
    366             parents.insert(style->parent.value().name.value());
    367             styles_to_visit.push(style->parent.value().name.value());
    368           }
    369         }
    370       }
    371     }
    372   }
    373 
    374   std::vector<ResourceName> names;
    375   for (const auto& entry : graph) {
    376     names.push_back(entry.first);
    377   }
    378 
    379   std::cout << "digraph styles {\n";
    380   for (const auto& name : names) {
    381     std::cout << "  node_" << GetNodeIndex(names, name) << " [label=\"" << name << "\"];\n";
    382   }
    383 
    384   for (const auto& entry : graph) {
    385     const ResourceName& style_name = entry.first;
    386     size_t style_node_index = GetNodeIndex(names, style_name);
    387 
    388     for (const auto& parent_name : entry.second) {
    389       std::cout << "  node_" << style_node_index << " -> "
    390                 << "node_" << GetNodeIndex(names, parent_name) << ";\n";
    391     }
    392   }
    393 
    394   std::cout << "}" << std::endl;
    395 }
    396 
    397 void Debug::DumpHex(const void* data, size_t len) {
    398   const uint8_t* d = (const uint8_t*)data;
    399   for (size_t i = 0; i < len; i++) {
    400     std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)d[i] << " ";
    401     if (i % 8 == 7) {
    402       std::cerr << "\n";
    403     }
    404   }
    405 
    406   if (len - 1 % 8 != 7) {
    407     std::cerr << std::endl;
    408   }
    409 }
    410 
    411 namespace {
    412 
    413 class XmlPrinter : public xml::ConstVisitor {
    414  public:
    415   using xml::ConstVisitor::Visit;
    416 
    417   XmlPrinter(Printer* printer) : printer_(printer) {
    418   }
    419 
    420   void Visit(const xml::Element* el) override {
    421     for (const xml::NamespaceDecl& decl : el->namespace_decls) {
    422       printer_->Println(StringPrintf("N: %s=%s (line=%zu)", decl.prefix.c_str(), decl.uri.c_str(),
    423                                      decl.line_number));
    424       printer_->Indent();
    425     }
    426 
    427     printer_->Print("E: ");
    428     if (!el->namespace_uri.empty()) {
    429       printer_->Print(el->namespace_uri);
    430       printer_->Print(":");
    431     }
    432     printer_->Println(StringPrintf("%s (line=%zu)", el->name.c_str(), el->line_number));
    433     printer_->Indent();
    434 
    435     for (const xml::Attribute& attr : el->attributes) {
    436       printer_->Print("A: ");
    437       if (!attr.namespace_uri.empty()) {
    438         printer_->Print(attr.namespace_uri);
    439         printer_->Print(":");
    440       }
    441       printer_->Print(attr.name);
    442 
    443       if (attr.compiled_attribute) {
    444         printer_->Print("(");
    445         printer_->Print(
    446             attr.compiled_attribute.value().id.value_or_default(ResourceId(0)).to_string());
    447         printer_->Print(")");
    448       }
    449       printer_->Print("=");
    450       if (attr.compiled_value != nullptr) {
    451         attr.compiled_value->PrettyPrint(printer_);
    452       } else {
    453         printer_->Print("\"");
    454         printer_->Print(attr.value);
    455         printer_->Print("\"");
    456       }
    457 
    458       if (!attr.value.empty()) {
    459         printer_->Print(" (Raw: \"");
    460         printer_->Print(attr.value);
    461         printer_->Print("\")");
    462       }
    463       printer_->Println();
    464     }
    465 
    466     printer_->Indent();
    467     xml::ConstVisitor::Visit(el);
    468     printer_->Undent();
    469     printer_->Undent();
    470 
    471     for (size_t i = 0; i < el->namespace_decls.size(); i++) {
    472       printer_->Undent();
    473     }
    474   }
    475 
    476   void Visit(const xml::Text* text) override {
    477     printer_->Println(StringPrintf("T: '%s'", text->text.c_str()));
    478   }
    479 
    480  private:
    481   Printer* printer_;
    482 };
    483 
    484 }  // namespace
    485 
    486 void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) {
    487   XmlPrinter xml_visitor(printer);
    488   doc.root->Accept(&xml_visitor);
    489 }
    490 
    491 }  // namespace aapt
    492