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