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 #include "ResourceTable.h" 19 #include "ResourceValues.h" 20 #include "util/Util.h" 21 #include "ValueVisitor.h" 22 23 #include <algorithm> 24 #include <iostream> 25 #include <map> 26 #include <memory> 27 #include <queue> 28 #include <set> 29 #include <vector> 30 31 namespace aapt { 32 33 class PrintVisitor : public ValueVisitor { 34 public: 35 using ValueVisitor::visit; 36 37 void visit(Attribute* attr) override { 38 std::cout << "(attr) type="; 39 attr->printMask(&std::cout); 40 static constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | 41 android::ResTable_map::TYPE_FLAGS; 42 if (attr->typeMask & kMask) { 43 for (const auto& symbol : attr->symbols) { 44 std::cout << "\n " << symbol.symbol.name.value().entry; 45 if (symbol.symbol.id) { 46 std::cout << " (" << symbol.symbol.id.value() << ")"; 47 } 48 std::cout << " = " << symbol.value; 49 } 50 } 51 } 52 53 void visit(Style* style) override { 54 std::cout << "(style)"; 55 if (style->parent) { 56 const Reference& parentRef = style->parent.value(); 57 std::cout << " parent="; 58 if (parentRef.name) { 59 if (parentRef.privateReference) { 60 std::cout << "*"; 61 } 62 std::cout << parentRef.name.value() << " "; 63 } 64 65 if (parentRef.id) { 66 std::cout << parentRef.id.value(); 67 } 68 } 69 70 for (const auto& entry : style->entries) { 71 std::cout << "\n "; 72 if (entry.key.name) { 73 const ResourceName& name = entry.key.name.value(); 74 if (!name.package.empty()) { 75 std::cout << name.package << ":"; 76 } 77 std::cout << name.entry; 78 } 79 80 if (entry.key.id) { 81 std::cout << "(" << entry.key.id.value() << ")"; 82 } 83 84 std::cout << "=" << *entry.value; 85 } 86 } 87 88 void visit(Array* array) override { 89 array->print(&std::cout); 90 } 91 92 void visit(Plural* plural) override { 93 plural->print(&std::cout); 94 } 95 96 void visit(Styleable* styleable) override { 97 std::cout << "(styleable)"; 98 for (const auto& attr : styleable->entries) { 99 std::cout << "\n "; 100 if (attr.name) { 101 const ResourceName& name = attr.name.value(); 102 if (!name.package.empty()) { 103 std::cout << name.package << ":"; 104 } 105 std::cout << name.entry; 106 } 107 108 if (attr.id) { 109 std::cout << "(" << attr.id.value() << ")"; 110 } 111 } 112 } 113 114 void visitItem(Item* item) override { 115 item->print(&std::cout); 116 } 117 }; 118 119 void Debug::printTable(ResourceTable* table, const DebugPrintTableOptions& options) { 120 PrintVisitor visitor; 121 122 for (auto& package : table->packages) { 123 std::cout << "Package name=" << package->name; 124 if (package->id) { 125 std::cout << " id=" << std::hex << (int) package->id.value() << std::dec; 126 } 127 std::cout << std::endl; 128 129 for (const auto& type : package->types) { 130 std::cout << "\n type " << type->type; 131 if (type->id) { 132 std::cout << " id=" << std::hex << (int) type->id.value() << std::dec; 133 } 134 std::cout << " entryCount=" << type->entries.size() << std::endl; 135 136 std::vector<const ResourceEntry*> sortedEntries; 137 for (const auto& entry : type->entries) { 138 auto iter = std::lower_bound(sortedEntries.begin(), sortedEntries.end(), entry.get(), 139 [](const ResourceEntry* a, const ResourceEntry* b) -> bool { 140 if (a->id && b->id) { 141 return a->id.value() < b->id.value(); 142 } else if (a->id) { 143 return true; 144 } else { 145 return false; 146 } 147 }); 148 sortedEntries.insert(iter, entry.get()); 149 } 150 151 for (const ResourceEntry* entry : sortedEntries) { 152 ResourceId id(package->id ? package->id.value() : uint8_t(0), 153 type->id ? type->id.value() : uint8_t(0), 154 entry->id ? entry->id.value() : uint16_t(0)); 155 ResourceName name(package->name, type->type, entry->name); 156 157 std::cout << " spec resource " << id << " " << name; 158 switch (entry->symbolStatus.state) { 159 case SymbolState::kPublic: std::cout << " PUBLIC"; break; 160 case SymbolState::kPrivate: std::cout << " _PRIVATE_"; break; 161 default: break; 162 } 163 164 std::cout << std::endl; 165 166 for (const auto& value : entry->values) { 167 std::cout << " (" << value->config << ") "; 168 value->value->accept(&visitor); 169 if (options.showSources && !value->value->getSource().path.empty()) { 170 std::cout << " src=" << value->value->getSource(); 171 } 172 std::cout << std::endl; 173 } 174 } 175 } 176 } 177 } 178 179 static size_t getNodeIndex(const std::vector<ResourceName>& names, const ResourceName& name) { 180 auto iter = std::lower_bound(names.begin(), names.end(), name); 181 assert(iter != names.end() && *iter == name); 182 return std::distance(names.begin(), iter); 183 } 184 185 void Debug::printStyleGraph(ResourceTable* table, const ResourceName& targetStyle) { 186 std::map<ResourceName, std::set<ResourceName>> graph; 187 188 std::queue<ResourceName> stylesToVisit; 189 stylesToVisit.push(targetStyle); 190 for (; !stylesToVisit.empty(); stylesToVisit.pop()) { 191 const ResourceName& styleName = stylesToVisit.front(); 192 std::set<ResourceName>& parents = graph[styleName]; 193 if (!parents.empty()) { 194 // We've already visited this style. 195 continue; 196 } 197 198 Maybe<ResourceTable::SearchResult> result = table->findResource(styleName); 199 if (result) { 200 ResourceEntry* entry = result.value().entry; 201 for (const auto& value : entry->values) { 202 if (Style* style = valueCast<Style>(value->value.get())) { 203 if (style->parent && style->parent.value().name) { 204 parents.insert(style->parent.value().name.value()); 205 stylesToVisit.push(style->parent.value().name.value()); 206 } 207 } 208 } 209 } 210 } 211 212 std::vector<ResourceName> names; 213 for (const auto& entry : graph) { 214 names.push_back(entry.first); 215 } 216 217 std::cout << "digraph styles {\n"; 218 for (const auto& name : names) { 219 std::cout << " node_" << getNodeIndex(names, name) 220 << " [label=\"" << name << "\"];\n"; 221 } 222 223 for (const auto& entry : graph) { 224 const ResourceName& styleName = entry.first; 225 size_t styleNodeIndex = getNodeIndex(names, styleName); 226 227 for (const auto& parentName : entry.second) { 228 std::cout << " node_" << styleNodeIndex << " -> " 229 << "node_" << getNodeIndex(names, parentName) << ";\n"; 230 } 231 } 232 233 std::cout << "}" << std::endl; 234 } 235 236 void Debug::dumpHex(const void* data, size_t len) { 237 const uint8_t* d = (const uint8_t*) data; 238 for (size_t i = 0; i < len; i++) { 239 std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t) d[i] << " "; 240 if (i % 8 == 7) { 241 std::cerr << "\n"; 242 } 243 } 244 245 if (len - 1 % 8 != 7) { 246 std::cerr << std::endl; 247 } 248 } 249 250 251 } // namespace aapt 252