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
visit(Attribute * attr)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
visit(Style * style)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
visit(Array * array)88 void visit(Array* array) override {
89 array->print(&std::cout);
90 }
91
visit(Plural * plural)92 void visit(Plural* plural) override {
93 plural->print(&std::cout);
94 }
95
visit(Styleable * styleable)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
visitItem(Item * item)114 void visitItem(Item* item) override {
115 item->print(&std::cout);
116 }
117 };
118
printTable(ResourceTable * table,const DebugPrintTableOptions & options)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
getNodeIndex(const std::vector<ResourceName> & names,const ResourceName & name)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
printStyleGraph(ResourceTable * table,const ResourceName & targetStyle)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
dumpHex(const void * data,size_t len)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