blob: 9ef8b7dc99478897af38ea3771fc5e564d4ead32 [file] [log] [blame]
Adam Lesinski330edcd2015-05-04 17:40:56 -07001/*
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"
Adam Lesinski330edcd2015-05-04 17:40:56 -070018
Ryan Mitchell19b27092018-08-13 11:36:27 -070019#include <androidfw/TypeWrappers.h>
Jeremy Meyer56f36e82022-05-20 20:35:42 +000020#include <androidfw/Util.h>
Ryan Mitchell19b27092018-08-13 11:36:27 -070021#include <format/binary/ResChunkPullParser.h>
22
Adam Lesinski330edcd2015-05-04 17:40:56 -070023#include <algorithm>
Yurii Zubrytskyi7e1b1242024-07-24 15:50:05 -070024#include <array>
Adam Lesinski330edcd2015-05-04 17:40:56 -070025#include <map>
26#include <memory>
Adam Lesinskid13fb242015-05-12 20:40:48 -070027#include <queue>
Adam Lesinski330edcd2015-05-04 17:40:56 -070028#include <set>
Yurii Zubrytskyi7e1b1242024-07-24 15:50:05 -070029#include <span>
30#include <utility>
Adam Lesinski330edcd2015-05-04 17:40:56 -070031#include <vector>
32
Adam Lesinskice5e56e2016-10-21 17:56:45 -070033#include "ResourceTable.h"
Ryan Mitchell19b27092018-08-13 11:36:27 -070034#include "ResourceUtils.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070035#include "ResourceValues.h"
36#include "ValueVisitor.h"
Ryan Mitchell19b27092018-08-13 11:36:27 -070037#include "android-base/logging.h"
38#include "android-base/stringprintf.h"
felkachanga1da2772022-08-29 17:54:09 +080039#include "androidfw/ResourceTypes.h"
Ryan Mitchell19b27092018-08-13 11:36:27 -070040#include "idmap2/Policies.h"
Adam Lesinski93190b72017-11-03 15:20:17 -070041#include "text/Printer.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070042#include "util/Util.h"
43
Adam Lesinski93190b72017-11-03 15:20:17 -070044using ::aapt::text::Printer;
45using ::android::StringPiece;
46using ::android::base::StringPrintf;
47
Winson62ac8b52019-12-04 08:36:48 -080048using android::idmap2::policy::kPolicyStringToFlag;
49
50using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
51
Adam Lesinski330edcd2015-05-04 17:40:56 -070052namespace aapt {
53
Adam Lesinski6b372992017-08-09 10:54:23 -070054namespace {
55
Adam Lesinski93190b72017-11-03 15:20:17 -070056class ValueHeadlinePrinter : public ConstValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070057 public:
Adam Lesinskie59f0d82017-10-13 09:36:53 -070058 using ConstValueVisitor::Visit;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070059
Adam Lesinski93190b72017-11-03 15:20:17 -070060 explicit ValueHeadlinePrinter(const std::string& package, Printer* printer)
61 : package_(package), printer_(printer) {
62 }
63
Adam Lesinskie59f0d82017-10-13 09:36:53 -070064 void Visit(const Attribute* attr) override {
Adam Lesinski93190b72017-11-03 15:20:17 -070065 printer_->Print("(attr) type=");
66 printer_->Print(attr->MaskString());
67 if (!attr->symbols.empty()) {
68 printer_->Print(StringPrintf(" size=%zd", attr->symbols.size()));
69 }
70 }
71
72 void Visit(const Style* style) override {
73 printer_->Print(StringPrintf("(style) size=%zd", style->entries.size()));
74 if (style->parent) {
75 printer_->Print(" parent=");
76
77 const Reference& parent_ref = style->parent.value();
78 if (parent_ref.name) {
79 if (parent_ref.private_reference) {
80 printer_->Print("*");
81 }
82
83 const ResourceName& parent_name = parent_ref.name.value();
84 if (package_ != parent_name.package) {
85 printer_->Print(parent_name.package);
86 printer_->Print(":");
87 }
Iurii Makhnocff10ce2022-02-15 19:33:50 +000088 printer_->Print(parent_name.type.to_string());
Adam Lesinski93190b72017-11-03 15:20:17 -070089 printer_->Print("/");
90 printer_->Print(parent_name.entry);
91 if (parent_ref.id) {
92 printer_->Print(" (");
93 printer_->Print(parent_ref.id.value().to_string());
94 printer_->Print(")");
95 }
96 } else if (parent_ref.id) {
97 printer_->Print(parent_ref.id.value().to_string());
98 } else {
99 printer_->Print("???");
100 }
101 }
102 }
103
104 void Visit(const Array* array) override {
105 printer_->Print(StringPrintf("(array) size=%zd", array->elements.size()));
106 }
107
108 void Visit(const Plural* plural) override {
109 size_t count = std::count_if(plural->values.begin(), plural->values.end(),
110 [](const std::unique_ptr<Item>& v) { return v != nullptr; });
111 printer_->Print(StringPrintf("(plurals) size=%zd", count));
112 }
113
114 void Visit(const Styleable* styleable) override {
115 printer_->Println(StringPrintf("(styleable) size=%zd", styleable->entries.size()));
116 }
117
118 void VisitItem(const Item* item) override {
119 // Pretty much guaranteed to be one line.
120 if (const Reference* ref = ValueCast<Reference>(item)) {
121 // Special case Reference so that we can print local resources without a package name.
122 ref->PrettyPrint(package_, printer_);
123 } else {
124 item->PrettyPrint(printer_);
125 }
126 }
127
128 private:
129 std::string package_;
130 Printer* printer_;
131};
132
133class ValueBodyPrinter : public ConstValueVisitor {
134 public:
135 using ConstValueVisitor::Visit;
136
137 explicit ValueBodyPrinter(const std::string& package, Printer* printer)
138 : package_(package), printer_(printer) {
139 }
140
141 void Visit(const Attribute* attr) override {
142 constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700143 if (attr->type_mask & kMask) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700144 for (const auto& symbol : attr->symbols) {
Ryan Mitchell0c0cedf2019-04-15 16:47:58 -0700145 if (symbol.symbol.name) {
146 printer_->Print(symbol.symbol.name.value().entry);
147
148 if (symbol.symbol.id) {
149 printer_->Print("(");
150 printer_->Print(symbol.symbol.id.value().to_string());
151 printer_->Print(")");
152 }
153 } else if (symbol.symbol.id) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700154 printer_->Print(symbol.symbol.id.value().to_string());
Ryan Mitchell0c0cedf2019-04-15 16:47:58 -0700155 } else {
156 printer_->Print("???");
Adam Lesinski330edcd2015-05-04 17:40:56 -0700157 }
Ryan Mitchell0c0cedf2019-04-15 16:47:58 -0700158
Adam Lesinski93190b72017-11-03 15:20:17 -0700159 printer_->Println(StringPrintf("=0x%08x", symbol.value));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700160 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700161 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700162 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700163
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700164 void Visit(const Style* style) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700165 for (const auto& entry : style->entries) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700166 if (entry.key.name) {
167 const ResourceName& name = entry.key.name.value();
Adam Lesinski93190b72017-11-03 15:20:17 -0700168 if (!name.package.empty() && name.package != package_) {
169 printer_->Print(name.package);
170 printer_->Print(":");
Adam Lesinski330edcd2015-05-04 17:40:56 -0700171 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700172 printer_->Print(name.entry);
173
174 if (entry.key.id) {
175 printer_->Print("(");
176 printer_->Print(entry.key.id.value().to_string());
177 printer_->Print(")");
178 }
179 } else if (entry.key.id) {
180 printer_->Print(entry.key.id.value().to_string());
181 } else {
182 printer_->Print("???");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183 }
184
Adam Lesinski93190b72017-11-03 15:20:17 -0700185 printer_->Print("=");
186 PrintItem(*entry.value);
187 printer_->Println();
Adam Lesinski330edcd2015-05-04 17:40:56 -0700188 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700189 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700190
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700191 void Visit(const Array* array) override {
Adam Lesinski93190b72017-11-03 15:20:17 -0700192 const size_t count = array->elements.size();
193 printer_->Print("[");
Donald Chai42fe2b22019-05-07 20:03:27 -0700194 for (size_t i = 0u; i < count; i++) {
195 if (i != 0u && i % 4u == 0u) {
196 printer_->Println();
197 printer_->Print(" ");
Adam Lesinski93190b72017-11-03 15:20:17 -0700198 }
Donald Chai42fe2b22019-05-07 20:03:27 -0700199 PrintItem(*array->elements[i]);
200 if (i != count - 1) {
201 printer_->Print(", ");
202 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700203 }
Donald Chai42fe2b22019-05-07 20:03:27 -0700204 printer_->Println("]");
Adam Lesinski6b372992017-08-09 10:54:23 -0700205 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700206
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700207 void Visit(const Plural* plural) override {
Adam Lesinski93190b72017-11-03 15:20:17 -0700208 constexpr std::array<const char*, Plural::Count> kPluralNames = {
209 {"zero", "one", "two", "few", "many", "other"}};
210
211 for (size_t i = 0; i < Plural::Count; i++) {
212 if (plural->values[i] != nullptr) {
213 printer_->Print(StringPrintf("%s=", kPluralNames[i]));
214 PrintItem(*plural->values[i]);
215 printer_->Println();
216 }
217 }
Adam Lesinski6b372992017-08-09 10:54:23 -0700218 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700219
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700220 void Visit(const Styleable* styleable) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 for (const auto& attr : styleable->entries) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700222 if (attr.name) {
223 const ResourceName& name = attr.name.value();
Adam Lesinski93190b72017-11-03 15:20:17 -0700224 if (!name.package.empty() && name.package != package_) {
225 printer_->Print(name.package);
226 printer_->Print(":");
Adam Lesinski355f2852016-02-13 20:26:45 -0800227 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700228 printer_->Print(name.entry);
229
230 if (attr.id) {
231 printer_->Print("(");
232 printer_->Print(attr.id.value().to_string());
233 printer_->Print(")");
234 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700235 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700236
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700237 if (attr.id) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700238 printer_->Print(attr.id.value().to_string());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700239 }
Adam Lesinski5a217b02017-11-16 16:58:02 -0800240 printer_->Println();
Adam Lesinski330edcd2015-05-04 17:40:56 -0700241 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700242 }
243
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700244 void VisitItem(const Item* item) override {
Adam Lesinski93190b72017-11-03 15:20:17 -0700245 // Intentionally left empty, we already printed the Items.
Adam Lesinski6b372992017-08-09 10:54:23 -0700246 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700247
248 private:
249 void PrintItem(const Item& item) {
250 if (const Reference* ref = ValueCast<Reference>(&item)) {
251 // Special case Reference so that we can print local resources without a package name.
252 ref->PrettyPrint(package_, printer_);
253 } else {
254 item.PrettyPrint(printer_);
255 }
256 }
257
258 std::string package_;
259 Printer* printer_;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700260};
261
Adam Lesinski6b372992017-08-09 10:54:23 -0700262} // namespace
263
Adam Lesinski93190b72017-11-03 15:20:17 -0700264void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
265 Printer* printer) {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700266 const auto table_view = table.GetPartitionedView();
267 for (const auto& package : table_view.packages) {
268 ValueHeadlinePrinter headline_printer(package.name, printer);
269 ValueBodyPrinter body_printer(package.name, printer);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700270
Yurii Zubrytskyicf91ab82023-04-24 18:34:13 -0700271 auto& dynamicRefTable = table.GetReferencedPackages();
272 if (!dynamicRefTable.empty()) {
273 printer->Println(StringPrintf("DynamicRefTable entryCount=%d", int(dynamicRefTable.size())));
274 printer->Indent();
275 for (auto&& [id, name] : dynamicRefTable) {
276 printer->Println(StringPrintf("0x%02x -> %s", id, name.c_str()));
277 }
278 printer->Undent();
279 }
280
Adam Lesinski93190b72017-11-03 15:20:17 -0700281 printer->Print("Package name=");
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700282 printer->Print(package.name);
283 if (package.id) {
284 printer->Print(StringPrintf(" id=%02x", package.id.value()));
Adam Lesinski93190b72017-11-03 15:20:17 -0700285 }
286 printer->Println();
287
288 printer->Indent();
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700289 for (const auto& type : package.types) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700290 printer->Print("type ");
Iurii Makhnof0c5ff42022-02-22 13:31:02 +0000291 printer->Print(type.named_type.to_string());
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700292 if (type.id) {
293 printer->Print(StringPrintf(" id=%02x", type.id.value()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700294 }
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700295 printer->Println(StringPrintf(" entryCount=%zd", type.entries.size()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700296
Adam Lesinski93190b72017-11-03 15:20:17 -0700297 printer->Indent();
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700298 for (const ResourceTableEntryView& entry : type.entries) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700299 printer->Print("resource ");
Ryan Mitchell4382e442021-07-14 12:53:01 -0700300 printer->Print(ResourceId(package.id.value_or(0), type.id.value_or(0), entry.id.value_or(0))
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700301 .to_string());
Adam Lesinski93190b72017-11-03 15:20:17 -0700302 printer->Print(" ");
303
304 // Write the name without the package (this is obvious and too verbose).
Iurii Makhnof0c5ff42022-02-22 13:31:02 +0000305 printer->Print(type.named_type.to_string());
Adam Lesinski93190b72017-11-03 15:20:17 -0700306 printer->Print("/");
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700307 printer->Print(entry.name);
Adam Lesinski93190b72017-11-03 15:20:17 -0700308
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700309 switch (entry.visibility.level) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800310 case Visibility::Level::kPublic:
Adam Lesinski93190b72017-11-03 15:20:17 -0700311 printer->Print(" PUBLIC");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700312 break;
Adam Lesinski71be7052017-12-12 16:48:07 -0800313 case Visibility::Level::kPrivate:
Adam Lesinski93190b72017-11-03 15:20:17 -0700314 printer->Print(" _PRIVATE_");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700315 break;
Adam Lesinski71be7052017-12-12 16:48:07 -0800316 case Visibility::Level::kUndefined:
Adam Lesinski93190b72017-11-03 15:20:17 -0700317 // Print nothing.
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700318 break;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700319 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700320
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700321 if (entry.visibility.staged_api) {
Ryan Mitchell1499f502021-03-30 12:20:08 -0700322 printer->Print(" STAGED");
323 }
324
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700325 if (entry.overlayable_item) {
MÃ¥rten Kongstad1d3b64852019-09-17 13:02:32 +0200326 printer->Print(" OVERLAYABLE");
327 }
328
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700329 if (entry.staged_id) {
330 printer->Print(" STAGED_ID=");
331 printer->Print(entry.staged_id.value().id.to_string());
332 }
333
Adam Lesinski93190b72017-11-03 15:20:17 -0700334 printer->Println();
Adam Lesinski330edcd2015-05-04 17:40:56 -0700335
Adam Lesinski71be7052017-12-12 16:48:07 -0800336 if (options.show_values) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700337 printer->Indent();
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700338 for (const auto& value : entry.values) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800339 printer->Print("(");
340 printer->Print(value->config.to_string());
341 printer->Print(") ");
342 value->value->Accept(&headline_printer);
343 if (options.show_sources && !value->value->GetSource().path.empty()) {
344 printer->Print(" src=");
345 printer->Print(value->value->GetSource().to_string());
346 }
347 printer->Println();
348 printer->Indent();
349 value->value->Accept(&body_printer);
350 printer->Undent();
351 }
Yurii Zubrytskyie5c50e72025-02-12 19:47:09 -0800352 if (!entry.flag_disabled_values.empty()) {
353 printer->Println("Flag disabled values:");
354 for (const auto& value : entry.flag_disabled_values) {
355 printer->Print("(");
356 printer->Print(value->config.to_string());
357 printer->Print(") ");
358 value->value->Accept(&headline_printer);
359 if (options.show_sources && !value->value->GetSource().path.empty()) {
360 printer->Print(" src=");
361 printer->Print(value->value->GetSource().to_string());
362 }
363 printer->Println();
364 printer->Indent();
365 value->value->Accept(&body_printer);
366 printer->Undent();
Jeremy Meyer3d8d4a12024-08-23 17:29:03 -0700367 }
Jeremy Meyer3d8d4a12024-08-23 17:29:03 -0700368 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700369 printer->Undent();
Adam Lesinski330edcd2015-05-04 17:40:56 -0700370 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700371 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700372 printer->Undent();
Adam Lesinski330edcd2015-05-04 17:40:56 -0700373 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700374 printer->Undent();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700375 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700376}
377
Adam Lesinski6b372992017-08-09 10:54:23 -0700378static size_t GetNodeIndex(const std::vector<ResourceName>& names, const ResourceName& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700379 auto iter = std::lower_bound(names.begin(), names.end(), name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700380 CHECK(iter != names.end());
381 CHECK(*iter == name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700382 return std::distance(names.begin(), iter);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700383}
384
Adam Lesinski6b372992017-08-09 10:54:23 -0700385void Debug::PrintStyleGraph(ResourceTable* table, const ResourceName& target_style) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700386 std::map<ResourceName, std::set<ResourceName>> graph;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700387
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700388 std::queue<ResourceName> styles_to_visit;
389 styles_to_visit.push(target_style);
390 for (; !styles_to_visit.empty(); styles_to_visit.pop()) {
391 const ResourceName& style_name = styles_to_visit.front();
392 std::set<ResourceName>& parents = graph[style_name];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700393 if (!parents.empty()) {
394 // We've already visited this style.
395 continue;
396 }
397
Ryan Mitchell4382e442021-07-14 12:53:01 -0700398 std::optional<ResourceTable::SearchResult> result = table->FindResource(style_name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700399 if (result) {
400 ResourceEntry* entry = result.value().entry;
401 for (const auto& value : entry->values) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700402 if (Style* style = ValueCast<Style>(value->value.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700403 if (style->parent && style->parent.value().name) {
404 parents.insert(style->parent.value().name.value());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700405 styles_to_visit.push(style->parent.value().name.value());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700406 }
Adam Lesinskid13fb242015-05-12 20:40:48 -0700407 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700408 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700409 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700410 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700411
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700412 std::vector<ResourceName> names;
413 for (const auto& entry : graph) {
414 names.push_back(entry.first);
415 }
416
417 std::cout << "digraph styles {\n";
418 for (const auto& name : names) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700419 std::cout << " node_" << GetNodeIndex(names, name) << " [label=\"" << name << "\"];\n";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700420 }
421
422 for (const auto& entry : graph) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700423 const ResourceName& style_name = entry.first;
424 size_t style_node_index = GetNodeIndex(names, style_name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700425
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700426 for (const auto& parent_name : entry.second) {
427 std::cout << " node_" << style_node_index << " -> "
428 << "node_" << GetNodeIndex(names, parent_name) << ";\n";
Adam Lesinskid13fb242015-05-12 20:40:48 -0700429 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700430 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700431
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700432 std::cout << "}" << std::endl;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700433}
434
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700435void Debug::DumpHex(const void* data, size_t len) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700436 const uint8_t* d = (const uint8_t*)data;
437 for (size_t i = 0; i < len; i++) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700438 std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)d[i] << " ";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700439 if (i % 8 == 7) {
440 std::cerr << "\n";
Adam Lesinski52364f72016-01-11 13:10:24 -0800441 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700442 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800443
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700444 if (len - 1 % 8 != 7) {
445 std::cerr << std::endl;
446 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800447}
448
Ryan Mitchell5d275512018-07-19 14:29:00 -0700449void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer) {
450 using namespace android;
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800451
Ryan Mitchell5d275512018-07-19 14:29:00 -0700452 if (pool->getError() == NO_INIT) {
Adam Soutarf1e23ea2024-10-03 13:23:00 +0000453 printer->Print("String pool is uninitialized.\n");
Ryan Mitchell5d275512018-07-19 14:29:00 -0700454 return;
455 } else if (pool->getError() != NO_ERROR) {
456 printer->Print("String pool is corrupt/invalid.\n");
457 return;
458 }
459
460 SortedVector<const void*> uniqueStrings;
461 const size_t N = pool->size();
462 for (size_t i=0; i<N; i++) {
463 size_t len;
464 if (pool->isUTF8()) {
Ryan Mitchelldb21f09a2020-11-16 23:08:18 +0000465 uniqueStrings.add(UnpackOptionalString(pool->string8At(i), &len));
Ryan Mitchell5d275512018-07-19 14:29:00 -0700466 } else {
Ryan Mitchelldb21f09a2020-11-16 23:08:18 +0000467 uniqueStrings.add(UnpackOptionalString(pool->stringAt(i), &len));
Ryan Mitchell5d275512018-07-19 14:29:00 -0700468 }
469 }
470
471 printer->Print(StringPrintf("String pool of %zd unique %s %s strings, %zd entries and %zd styles "
472 "using %zd bytes:\n", uniqueStrings.size(),
473 pool->isUTF8() ? "UTF-8" : "UTF-16",
474 pool->isSorted() ? "sorted" : "non-sorted", N, pool->styleCount(),
475 pool->bytes()));
476
477 const size_t NS = pool->size();
478 for (size_t s=0; s<NS; s++) {
Ryan Mitchelldb21f09a2020-11-16 23:08:18 +0000479 auto str = pool->string8ObjectAt(s);
Tomasz Wasilczykade06312023-08-10 23:54:44 +0000480 printer->Print(StringPrintf("String #%zd : %s\n", s, str.has_value() ? str->c_str() : ""));
Ryan Mitchell5d275512018-07-19 14:29:00 -0700481 }
482}
483
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700484namespace {
485
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700486class XmlPrinter : public xml::ConstVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700487 public:
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700488 using xml::ConstVisitor::Visit;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700489
Chih-Hung Hsieh1fc78e12018-12-20 13:37:44 -0800490 explicit XmlPrinter(Printer* printer) : printer_(printer) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800491 }
492
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700493 void Visit(const xml::Element* el) override {
Adam Lesinski6b372992017-08-09 10:54:23 -0700494 for (const xml::NamespaceDecl& decl : el->namespace_decls) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800495 printer_->Println(StringPrintf("N: %s=%s (line=%zu)", decl.prefix.c_str(), decl.uri.c_str(),
496 decl.line_number));
497 printer_->Indent();
Adam Lesinski6b372992017-08-09 10:54:23 -0700498 }
499
Adam Lesinskida9eba32018-02-13 16:44:10 -0800500 printer_->Print("E: ");
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700501 if (!el->namespace_uri.empty()) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800502 printer_->Print(el->namespace_uri);
503 printer_->Print(":");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700504 }
Adam Lesinskida9eba32018-02-13 16:44:10 -0800505 printer_->Println(StringPrintf("%s (line=%zu)", el->name.c_str(), el->line_number));
506 printer_->Indent();
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700507
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700508 for (const xml::Attribute& attr : el->attributes) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800509 printer_->Print("A: ");
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700510 if (!attr.namespace_uri.empty()) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800511 printer_->Print(attr.namespace_uri);
512 printer_->Print(":");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700513 }
Adam Lesinskida9eba32018-02-13 16:44:10 -0800514 printer_->Print(attr.name);
Adam Lesinski4ca56972017-04-26 21:49:53 -0700515
516 if (attr.compiled_attribute) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800517 printer_->Print("(");
Ryan Mitchell4382e442021-07-14 12:53:01 -0700518 printer_->Print(attr.compiled_attribute.value().id.value_or(ResourceId(0)).to_string());
Adam Lesinskida9eba32018-02-13 16:44:10 -0800519 printer_->Print(")");
Adam Lesinski4ca56972017-04-26 21:49:53 -0700520 }
Adam Lesinskida9eba32018-02-13 16:44:10 -0800521 printer_->Print("=");
Shane Farmer6ed40612017-09-06 10:00:07 -0700522 if (attr.compiled_value != nullptr) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800523 attr.compiled_value->PrettyPrint(printer_);
Shane Farmer6ed40612017-09-06 10:00:07 -0700524 } else {
Adam Lesinskibbf42972018-02-14 13:36:09 -0800525 printer_->Print("\"");
Adam Lesinskida9eba32018-02-13 16:44:10 -0800526 printer_->Print(attr.value);
Adam Lesinskibbf42972018-02-14 13:36:09 -0800527 printer_->Print("\"");
528 }
529
530 if (!attr.value.empty()) {
531 printer_->Print(" (Raw: \"");
532 printer_->Print(attr.value);
533 printer_->Print("\")");
Shane Farmer6ed40612017-09-06 10:00:07 -0700534 }
Adam Lesinskida9eba32018-02-13 16:44:10 -0800535 printer_->Println();
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700536 }
537
Adam Lesinskida9eba32018-02-13 16:44:10 -0800538 printer_->Indent();
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700539 xml::ConstVisitor::Visit(el);
Adam Lesinskida9eba32018-02-13 16:44:10 -0800540 printer_->Undent();
541 printer_->Undent();
542
543 for (size_t i = 0; i < el->namespace_decls.size(); i++) {
544 printer_->Undent();
545 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700546 }
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700547
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700548 void Visit(const xml::Text* text) override {
felkachanga1da2772022-08-29 17:54:09 +0800549 printer_->Println(
550 StringPrintf("T: '%s'", android::ResTable::normalizeForOutput(text->text.c_str()).c_str()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700551 }
552
553 private:
Adam Lesinskida9eba32018-02-13 16:44:10 -0800554 Printer* printer_;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700555};
556
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700557} // namespace
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700558
Adam Lesinskida9eba32018-02-13 16:44:10 -0800559void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) {
560 XmlPrinter xml_visitor(printer);
561 doc.root->Accept(&xml_visitor);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700562}
Adam Lesinski52364f72016-01-11 13:10:24 -0800563
MÃ¥rten Kongstad1d3b64852019-09-17 13:02:32 +0200564struct DumpOverlayableEntry {
565 std::string overlayable_section;
566 std::string policy_subsection;
567 std::string resource_name;
568};
569
570void Debug::DumpOverlayable(const ResourceTable& table, text::Printer* printer) {
571 std::vector<DumpOverlayableEntry> items;
572 for (const auto& package : table.packages) {
573 for (const auto& type : package->types) {
574 for (const auto& entry : type->entries) {
575 if (entry->overlayable_item) {
576 const auto& overlayable_item = entry->overlayable_item.value();
577 const auto overlayable_section = StringPrintf(R"(name="%s" actor="%s")",
578 overlayable_item.overlayable->name.c_str(),
579 overlayable_item.overlayable->actor.c_str());
580 const auto policy_subsection = StringPrintf(R"(policies="%s")",
Ryan Mitchella7070132020-05-13 14:17:52 -0700581 android::idmap2::policy::PoliciesToDebugString(overlayable_item.policies).c_str());
MÃ¥rten Kongstad1d3b64852019-09-17 13:02:32 +0200582 const auto value =
Iurii Makhnof0c5ff42022-02-22 13:31:02 +0000583 StringPrintf("%s/%s", type->named_type.to_string().data(), entry->name.c_str());
MÃ¥rten Kongstad1d3b64852019-09-17 13:02:32 +0200584 items.push_back(DumpOverlayableEntry{overlayable_section, policy_subsection, value});
585 }
586 }
587 }
588 }
589
590 std::sort(items.begin(), items.end(),
591 [](const DumpOverlayableEntry& a, const DumpOverlayableEntry& b) {
592 if (a.overlayable_section != b.overlayable_section) {
593 return a.overlayable_section < b.overlayable_section;
594 }
595 if (a.policy_subsection != b.policy_subsection) {
596 return a.policy_subsection < b.policy_subsection;
597 }
598 return a.resource_name < b.resource_name;
599 });
600
601 std::string last_overlayable_section;
602 std::string last_policy_subsection;
603 for (const auto& item : items) {
604 if (last_overlayable_section != item.overlayable_section) {
605 printer->Println(item.overlayable_section);
606 last_overlayable_section = item.overlayable_section;
607 }
608 if (last_policy_subsection != item.policy_subsection) {
609 printer->Indent();
610 printer->Println(item.policy_subsection);
611 last_policy_subsection = item.policy_subsection;
612 printer->Undent();
613 }
614 printer->Indent();
615 printer->Indent();
616 printer->Println(item.resource_name);
617 printer->Undent();
618 printer->Undent();
619 }
620}
621
Ryan Mitchell19b27092018-08-13 11:36:27 -0700622namespace {
623
624using namespace android;
625
626class ChunkPrinter {
627 public:
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000628 ChunkPrinter(const void* data, size_t len, Printer* printer, android::IDiagnostics* diag)
Ryan Mitchell19b27092018-08-13 11:36:27 -0700629 : data_(data), data_len_(len), printer_(printer), diag_(diag) {
630 }
631
632 void PrintChunkHeader(const ResChunk_header* chunk) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000633 switch (android::util::DeviceToHost16(chunk->type)) {
Ryan Mitchell19b27092018-08-13 11:36:27 -0700634 case RES_STRING_POOL_TYPE:
635 printer_->Print("[RES_STRING_POOL_TYPE]");
636 break;
637 case RES_TABLE_LIBRARY_TYPE:
638 printer_->Print("[RES_TABLE_LIBRARY_TYPE]");
639 break;
640 case RES_TABLE_TYPE:
641 printer_->Print("[ResTable_header]");
642 break;
643 case RES_TABLE_PACKAGE_TYPE:
644 printer_->Print("[ResTable_package]");
645 break;
646 case RES_TABLE_TYPE_TYPE:
647 printer_->Print("[ResTable_type]");
648 break;
649 case RES_TABLE_TYPE_SPEC_TYPE:
650 printer_->Print("[RES_TABLE_TYPE_SPEC_TYPE]");
651 break;
652 default:
653 break;
654 }
655
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000656 printer_->Print(StringPrintf(" chunkSize: %u", android::util::DeviceToHost32(chunk->size)));
657 printer_->Print(
658 StringPrintf(" headerSize: %u", android::util::DeviceToHost32(chunk->headerSize)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700659 }
660
661 bool PrintTable(const ResTable_header* chunk) {
662 printer_->Print(
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000663 StringPrintf(" Package count: %u\n", android::util::DeviceToHost32(chunk->packageCount)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700664
665 // Print the chunks contained within the table
666 printer_->Indent();
667 bool success = PrintChunk(
668 ResChunkPullParser(GetChunkData(&chunk->header), GetChunkDataLen(&chunk->header)));
669 printer_->Undent();
670 return success;
671 }
672
673 void PrintResValue(const Res_value* value, const ConfigDescription& config,
674 const ResourceType* type) {
675 printer_->Print("[Res_value]");
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000676 printer_->Print(StringPrintf(" size: %u", android::util::DeviceToHost32(value->size)));
677 printer_->Print(
678 StringPrintf(" dataType: 0x%02x", android::util::DeviceToHost32(value->dataType)));
679 printer_->Print(StringPrintf(" data: 0x%08x", android::util::DeviceToHost32(value->data)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700680
681 if (type) {
682 auto item =
683 ResourceUtils::ParseBinaryResValue(*type, config, value_pool_, *value, &out_pool_);
684 printer_->Print(" (");
685 item->PrettyPrint(printer_);
686 printer_->Print(")");
687 }
Ryan Mitchell19b27092018-08-13 11:36:27 -0700688 }
689
Yurii Zubrytskyi7e1b1242024-07-24 15:50:05 -0700690 void PrintQualifiers(uint32_t qualifiers) const {
691 if (qualifiers == 0) {
692 printer_->Print("0");
693 return;
694 }
695
696 printer_->Print(StringPrintf("0x%04x: ", qualifiers));
697 static constinit std::array kValues = {
698 std::pair{ResTable_config::CONFIG_MCC, "mcc"},
699 std::pair{ResTable_config::CONFIG_MNC, "mnc"},
700 std::pair{ResTable_config::CONFIG_LOCALE, "locale"},
701 std::pair{ResTable_config::CONFIG_TOUCHSCREEN, "touchscreen"},
702 std::pair{ResTable_config::CONFIG_KEYBOARD, "keyboard"},
703 std::pair{ResTable_config::CONFIG_KEYBOARD_HIDDEN, "keyboard_hidden"},
704 std::pair{ResTable_config::CONFIG_NAVIGATION, "navigation"},
705 std::pair{ResTable_config::CONFIG_ORIENTATION, "orientation"},
706 std::pair{ResTable_config::CONFIG_DENSITY, "screen_density"},
707 std::pair{ResTable_config::CONFIG_SCREEN_SIZE, "screen_size"},
708 std::pair{ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE, "screen_smallest_size"},
709 std::pair{ResTable_config::CONFIG_VERSION, "version"},
710 std::pair{ResTable_config::CONFIG_SCREEN_LAYOUT, "screen_layout"},
711 std::pair{ResTable_config::CONFIG_UI_MODE, "ui_mode"},
712 std::pair{ResTable_config::CONFIG_LAYOUTDIR, "layout_dir"},
713 std::pair{ResTable_config::CONFIG_SCREEN_ROUND, "screen_round"},
714 std::pair{ResTable_config::CONFIG_COLOR_MODE, "color_mode"},
715 std::pair{ResTable_config::CONFIG_GRAMMATICAL_GENDER, "grammatical_gender"}};
716 const char* delimiter = "";
717 for (auto&& pair : kValues) {
718 if (qualifiers & pair.first) {
719 printer_->Print(StringPrintf("%s%s", delimiter, pair.second));
720 delimiter = "|";
721 }
722 }
723 }
724
725 bool PrintTypeSpec(const ResTable_typeSpec* chunk) const {
726 printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
727 printer_->Print(StringPrintf(" types: %u", android::util::DeviceToHost16(chunk->typesCount)));
728 printer_->Print(
729 StringPrintf(" entry configs: %u\n", android::util::DeviceToHost32(chunk->entryCount)));
730 printer_->Print("Entry qualifier masks:\n");
731 printer_->Indent();
732 std::span<const uint32_t> masks(reinterpret_cast<const uint32_t*>(GetChunkData(&chunk->header)),
733 GetChunkDataLen(&chunk->header) / sizeof(uint32_t));
734 int i = 0;
735 int non_empty_count = 0;
736 for (auto dev_mask : masks) {
737 auto mask = android::util::DeviceToHost32(dev_mask);
738 if (mask == 0) {
739 i++;
740 continue;
741 }
742 ++non_empty_count;
743 printer_->Print(StringPrintf("#0x%02x = ", i++));
744 if (mask & ResTable_typeSpec::SPEC_PUBLIC) {
745 mask &= ~ResTable_typeSpec::SPEC_PUBLIC;
746 printer_->Print("(PUBLIC) ");
747 }
748 if (mask & ResTable_typeSpec::SPEC_STAGED_API) {
749 mask &= ~ResTable_typeSpec::SPEC_STAGED_API;
750 printer_->Print("(STAGED) ");
751 }
752 PrintQualifiers(mask);
753 printer_->Print("\n");
754 }
755 if (non_empty_count > 0) {
756 printer_->Print("\n");
757 } else {
758 printer_->Print("(all empty)\n");
759 }
760 printer_->Undent();
761 return true;
762 }
763
Ryan Mitchell19b27092018-08-13 11:36:27 -0700764 bool PrintTableType(const ResTable_type* chunk) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000765 printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
Yurii Zubrytskyi9bafe4d2024-12-16 18:47:48 -0800766 const auto name =
767 android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1);
768 printer_->Print(StringPrintf(" name: %s", name.c_str()));
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000769 printer_->Print(StringPrintf(" flags: 0x%02x", android::util::DeviceToHost32(chunk->flags)));
Yurii Zubrytskyi9bafe4d2024-12-16 18:47:48 -0800770 printer_->Print(android::util::DeviceToHost32(chunk->flags) & ResTable_type::FLAG_SPARSE
771 ? " (SPARSE)"
772 : " (DENSE)");
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000773 printer_->Print(
774 StringPrintf(" entryCount: %u", android::util::DeviceToHost32(chunk->entryCount)));
775 printer_->Print(
776 StringPrintf(" entryStart: %u", android::util::DeviceToHost32(chunk->entriesStart)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700777
778 ConfigDescription config;
779 config.copyFromDtoH(chunk->config);
780 printer_->Print(StringPrintf(" config: %s\n", config.to_string().c_str()));
781
Yurii Zubrytskyi9bafe4d2024-12-16 18:47:48 -0800782 const ResourceType* type = ParseResourceType(name);
Ryan Mitchell19b27092018-08-13 11:36:27 -0700783
784 printer_->Indent();
785
786 TypeVariant tv(chunk);
787 for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
788 const ResTable_entry* entry = *it;
789 if (!entry) {
790 continue;
791 }
792
Eric Miao368cd192022-09-09 15:46:14 -0700793 if (entry->is_complex()) {
794 printer_->Print("[ResTable_map_entry]");
795 } else if (entry->is_compact()) {
796 printer_->Print("[ResTable_entry_compact]");
797 } else {
798 printer_->Print("[ResTable_entry]");
799 }
800
Ryan Mitchell19b27092018-08-13 11:36:27 -0700801 printer_->Print(StringPrintf(" id: 0x%04x", it.index()));
802 printer_->Print(StringPrintf(
Eric Miao368cd192022-09-09 15:46:14 -0700803 " name: %s", android::util::GetString(key_pool_, entry->key()).c_str()));
804 printer_->Print(StringPrintf(" keyIndex: %u", entry->key()));
805 printer_->Print(StringPrintf(" size: %zu", entry->size()));
806 printer_->Print(StringPrintf(" flags: 0x%04x", entry->flags()));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700807
808 printer_->Indent();
809
Eric Miao368cd192022-09-09 15:46:14 -0700810 if (auto map_entry = entry->map_entry()) {
811 uint32_t map_entry_count = android::util::DeviceToHost32(map_entry->count);
812 printer_->Print(StringPrintf(" count: 0x%04x", map_entry_count));
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000813 printer_->Print(StringPrintf(" parent: 0x%08x\n",
814 android::util::DeviceToHost32(map_entry->parent.ident)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700815
816 // Print the name and value mappings
Eric Miao368cd192022-09-09 15:46:14 -0700817 auto maps = (const ResTable_map*)((const uint8_t*)entry + entry->size());
818 for (size_t i = 0; i < map_entry_count; i++) {
Ryan Mitchell19b27092018-08-13 11:36:27 -0700819 PrintResValue(&(maps[i].value), config, type);
820
Yurii Zubrytskyi9bafe4d2024-12-16 18:47:48 -0800821 printer_->Print(StringPrintf(" name-id: 0x%08x\n",
822 android::util::DeviceToHost32(maps[i].name.ident)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700823 }
824 } else {
825 printer_->Print("\n");
826
827 // Print the value of the entry
Eric Miao368cd192022-09-09 15:46:14 -0700828 Res_value value = entry->value();
829 PrintResValue(&value, config, type);
Yurii Zubrytskyi9bafe4d2024-12-16 18:47:48 -0800830
831 printer_->Print("\n");
Ryan Mitchell19b27092018-08-13 11:36:27 -0700832 }
833
834 printer_->Undent();
835 }
836
837 printer_->Undent();
838 return true;
839 }
840
841 void PrintStringPool(const ResStringPool_header* chunk) {
842 // Initialize the string pools
843
844 ResStringPool* pool;
845 if (value_pool_.getError() == NO_INIT) {
846 pool = &value_pool_;
847 } else if (type_pool_.getError() == NO_INIT) {
848 pool = &type_pool_;
849 } else if (key_pool_.getError() == NO_INIT) {
850 pool = &key_pool_;
851 } else {
852 return;
853 }
854
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000855 pool->setTo(chunk, android::util::DeviceToHost32(
856 (reinterpret_cast<const ResChunk_header*>(chunk))->size));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700857
Yurii Zubrytskyi97f0f1e2024-07-02 15:31:01 -0700858 printer_->Print(StringPrintf(" strings: %zd styles %zd flags: %s|%s\n", pool->size(),
859 pool->styleCount(), pool->isUTF8() ? "UTF-8" : "UTF-16",
860 pool->isSorted() ? "SORTED" : "NON-SORTED"));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700861
862 for (size_t i = 0; i < pool->size(); i++) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000863 printer_->Print(StringPrintf("#%zd : %s\n", i, android::util::GetString(*pool, i).c_str()));
Yurii Zubrytskyi97f0f1e2024-07-02 15:31:01 -0700864 if (i < pool->styleCount()) {
865 printer_->Print(" [Style] ");
866 auto maybe_style = pool->styleAt(i);
867 if (!maybe_style) {
868 printer_->Print("??? missing\n");
869 } else {
870 std::vector<const ResStringPool_span*> spans;
871 for (auto style = maybe_style.value().unsafe_ptr();
872 style->name.index != android::ResStringPool_span::END; ++style) {
873 spans.push_back(style);
874 }
875 printer_->Print(StringPrintf("(%zd)", spans.size()));
876 if (!spans.empty()) {
877 printer_->Print(" :");
878 for (const auto& span : spans) {
879 printer_->Print(StringPrintf(
880 " %s:%u,%u", android::util::GetString(*pool, span->name.index).c_str(),
881 span->firstChar, span->lastChar));
882 }
883 printer_->Print("\n");
884 }
885 }
886 }
Ryan Mitchell19b27092018-08-13 11:36:27 -0700887 }
888 }
889
890 bool PrintPackage(const ResTable_package* chunk) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000891 printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700892
893 size_t len = strnlen16((const char16_t*)chunk->name, std::size(chunk->name));
894 std::u16string package_name(len, u'\0');
895 package_name.resize(len);
896 for (size_t i = 0; i < len; i++) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000897 package_name[i] = android::util::DeviceToHost16(chunk->name[i]);
Ryan Mitchell19b27092018-08-13 11:36:27 -0700898 }
899
900 printer_->Print(StringPrintf("name: %s", String8(package_name.c_str()).c_str()));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700901 printer_->Print(
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000902 StringPrintf(" typeStrings: %u", android::util::DeviceToHost32(chunk->typeStrings)));
903 printer_->Print(
904 StringPrintf(" lastPublicType: %u", android::util::DeviceToHost32(chunk->lastPublicType)));
905 printer_->Print(
906 StringPrintf(" keyStrings: %u", android::util::DeviceToHost32(chunk->keyStrings)));
907 printer_->Print(
908 StringPrintf(" lastPublicKey: %u", android::util::DeviceToHost32(chunk->lastPublicKey)));
909 printer_->Print(
910 StringPrintf(" typeIdOffset: %u\n", android::util::DeviceToHost32(chunk->typeIdOffset)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700911
912 // Print the chunks contained within the table
913 printer_->Indent();
914 bool success = PrintChunk(
915 ResChunkPullParser(GetChunkData(&chunk->header), GetChunkDataLen(&chunk->header)));
916 printer_->Undent();
917 return success;
918 }
919
920 bool PrintChunk(ResChunkPullParser&& parser) {
921 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
922 auto chunk = parser.chunk();
923 PrintChunkHeader(chunk);
924
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000925 switch (android::util::DeviceToHost16(chunk->type)) {
Ryan Mitchell19b27092018-08-13 11:36:27 -0700926 case RES_STRING_POOL_TYPE:
927 PrintStringPool(reinterpret_cast<const ResStringPool_header*>(chunk));
928 break;
929
930 case RES_TABLE_TYPE:
931 PrintTable(reinterpret_cast<const ResTable_header*>(chunk));
932 break;
933
934 case RES_TABLE_PACKAGE_TYPE:
935 type_pool_.uninit();
936 key_pool_.uninit();
937 PrintPackage(reinterpret_cast<const ResTable_package*>(chunk));
938 break;
939
940 case RES_TABLE_TYPE_TYPE:
941 PrintTableType(reinterpret_cast<const ResTable_type*>(chunk));
942 break;
943
Yurii Zubrytskyi7e1b1242024-07-24 15:50:05 -0700944 case RES_TABLE_TYPE_SPEC_TYPE:
945 PrintTypeSpec(reinterpret_cast<const ResTable_typeSpec*>(chunk));
946 break;
947
Ryan Mitchell19b27092018-08-13 11:36:27 -0700948 default:
949 printer_->Print("\n");
950 break;
951 }
952 }
953
954 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000955 diag_->Error(android::DiagMessage(source_) << "corrupt resource table: " << parser.error());
Ryan Mitchell19b27092018-08-13 11:36:27 -0700956 return false;
957 }
958
959 return true;
960 }
961
962 void Print() {
963 PrintChunk(ResChunkPullParser(data_, data_len_));
964 printer_->Print("[End]\n");
965 }
966
967 private:
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000968 const android::Source source_;
Ryan Mitchell19b27092018-08-13 11:36:27 -0700969 const void* data_;
970 const size_t data_len_;
971 Printer* printer_;
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000972 android::IDiagnostics* diag_;
Ryan Mitchell19b27092018-08-13 11:36:27 -0700973
974 // The standard value string pool for resource values.
975 ResStringPool value_pool_;
976
977 // The string pool that holds the names of the types defined
978 // in this table.
979 ResStringPool type_pool_;
980
981 // The string pool that holds the names of the entries defined
982 // in this table.
983 ResStringPool key_pool_;
984
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000985 android::StringPool out_pool_;
Ryan Mitchell19b27092018-08-13 11:36:27 -0700986};
987
988} // namespace
989
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000990void Debug::DumpChunks(const void* data, size_t len, Printer* printer,
991 android::IDiagnostics* diag) {
Ryan Mitchell19b27092018-08-13 11:36:27 -0700992 ChunkPrinter chunk_printer(data, len, printer, diag);
993 chunk_printer.Print();
994}
995
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700996} // namespace aapt