Debug.cpp revision ce5e56e243d262a9b65459c3bd0bb9eaadd40628
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
34namespace aapt {
35
36class PrintVisitor : public ValueVisitor {
37 public:
38  using ValueVisitor::Visit;
39
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
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
91  void Visit(Array* array) override { array->Print(&std::cout); }
92
93  void Visit(Plural* plural) override { plural->Print(&std::cout); }
94
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
113  void VisitItem(Item* item) override { item->Print(&std::cout); }
114};
115
116void 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
183static 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
191void 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
243void 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
258namespace {
259
260class XmlPrinter : public xml::Visitor {
261 public:
262  using xml::Visitor::Visit;
263
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 << "=" << attr.value << "\n";
278    }
279
280    const size_t previous_size = prefix_.size();
281    prefix_ += "  ";
282    xml::Visitor::Visit(el);
283    prefix_.resize(previous_size);
284  }
285
286  void Visit(xml::Namespace* ns) override {
287    std::cerr << prefix_;
288    std::cerr << "N: " << ns->namespace_prefix << "=" << ns->namespace_uri
289              << " (line=" << ns->line_number << ")\n";
290
291    const size_t previous_size = prefix_.size();
292    prefix_ += "  ";
293    xml::Visitor::Visit(ns);
294    prefix_.resize(previous_size);
295  }
296
297  void Visit(xml::Text* text) override {
298    std::cerr << prefix_;
299    std::cerr << "T: '" << text->text << "'\n";
300  }
301
302 private:
303  std::string prefix_;
304};
305
306}  // namespace
307
308void Debug::DumpXml(xml::XmlResource* doc) {
309  XmlPrinter printer;
310  doc->root->Accept(&printer);
311}
312
313}  // namespace aapt
314