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