blob: dfa2291733735e4f211b21edc28be11ba31cad4b [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>
Adam Lesinski330edcd2015-05-04 17:40:56 -070024#include <map>
25#include <memory>
Adam Lesinskid13fb242015-05-12 20:40:48 -070026#include <queue>
Adam Lesinski330edcd2015-05-04 17:40:56 -070027#include <set>
28#include <vector>
29
Adam Lesinskice5e56e2016-10-21 17:56:45 -070030#include "ResourceTable.h"
Ryan Mitchell19b27092018-08-13 11:36:27 -070031#include "ResourceUtils.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070032#include "ResourceValues.h"
33#include "ValueVisitor.h"
Ryan Mitchell19b27092018-08-13 11:36:27 -070034#include "android-base/logging.h"
35#include "android-base/stringprintf.h"
36#include "idmap2/Policies.h"
Adam Lesinski93190b72017-11-03 15:20:17 -070037#include "text/Printer.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070038#include "util/Util.h"
39
Adam Lesinski93190b72017-11-03 15:20:17 -070040using ::aapt::text::Printer;
41using ::android::StringPiece;
42using ::android::base::StringPrintf;
43
Winson62ac8b52019-12-04 08:36:48 -080044using android::idmap2::policy::kPolicyStringToFlag;
45
46using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
47
Adam Lesinski330edcd2015-05-04 17:40:56 -070048namespace aapt {
49
Adam Lesinski6b372992017-08-09 10:54:23 -070050namespace {
51
Adam Lesinski93190b72017-11-03 15:20:17 -070052class ValueHeadlinePrinter : public ConstValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070053 public:
Adam Lesinskie59f0d82017-10-13 09:36:53 -070054 using ConstValueVisitor::Visit;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070055
Adam Lesinski93190b72017-11-03 15:20:17 -070056 explicit ValueHeadlinePrinter(const std::string& package, Printer* printer)
57 : package_(package), printer_(printer) {
58 }
59
Adam Lesinskie59f0d82017-10-13 09:36:53 -070060 void Visit(const Attribute* attr) override {
Adam Lesinski93190b72017-11-03 15:20:17 -070061 printer_->Print("(attr) type=");
62 printer_->Print(attr->MaskString());
63 if (!attr->symbols.empty()) {
64 printer_->Print(StringPrintf(" size=%zd", attr->symbols.size()));
65 }
66 }
67
68 void Visit(const Style* style) override {
69 printer_->Print(StringPrintf("(style) size=%zd", style->entries.size()));
70 if (style->parent) {
71 printer_->Print(" parent=");
72
73 const Reference& parent_ref = style->parent.value();
74 if (parent_ref.name) {
75 if (parent_ref.private_reference) {
76 printer_->Print("*");
77 }
78
79 const ResourceName& parent_name = parent_ref.name.value();
80 if (package_ != parent_name.package) {
81 printer_->Print(parent_name.package);
82 printer_->Print(":");
83 }
Iurii Makhnocff10ce2022-02-15 19:33:50 +000084 printer_->Print(parent_name.type.to_string());
Adam Lesinski93190b72017-11-03 15:20:17 -070085 printer_->Print("/");
86 printer_->Print(parent_name.entry);
87 if (parent_ref.id) {
88 printer_->Print(" (");
89 printer_->Print(parent_ref.id.value().to_string());
90 printer_->Print(")");
91 }
92 } else if (parent_ref.id) {
93 printer_->Print(parent_ref.id.value().to_string());
94 } else {
95 printer_->Print("???");
96 }
97 }
98 }
99
100 void Visit(const Array* array) override {
101 printer_->Print(StringPrintf("(array) size=%zd", array->elements.size()));
102 }
103
104 void Visit(const Plural* plural) override {
105 size_t count = std::count_if(plural->values.begin(), plural->values.end(),
106 [](const std::unique_ptr<Item>& v) { return v != nullptr; });
107 printer_->Print(StringPrintf("(plurals) size=%zd", count));
108 }
109
110 void Visit(const Styleable* styleable) override {
111 printer_->Println(StringPrintf("(styleable) size=%zd", styleable->entries.size()));
112 }
113
114 void VisitItem(const Item* item) override {
115 // Pretty much guaranteed to be one line.
116 if (const Reference* ref = ValueCast<Reference>(item)) {
117 // Special case Reference so that we can print local resources without a package name.
118 ref->PrettyPrint(package_, printer_);
119 } else {
120 item->PrettyPrint(printer_);
121 }
122 }
123
124 private:
125 std::string package_;
126 Printer* printer_;
127};
128
129class ValueBodyPrinter : public ConstValueVisitor {
130 public:
131 using ConstValueVisitor::Visit;
132
133 explicit ValueBodyPrinter(const std::string& package, Printer* printer)
134 : package_(package), printer_(printer) {
135 }
136
137 void Visit(const Attribute* attr) override {
138 constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700139 if (attr->type_mask & kMask) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700140 for (const auto& symbol : attr->symbols) {
Ryan Mitchell0c0cedf2019-04-15 16:47:58 -0700141 if (symbol.symbol.name) {
142 printer_->Print(symbol.symbol.name.value().entry);
143
144 if (symbol.symbol.id) {
145 printer_->Print("(");
146 printer_->Print(symbol.symbol.id.value().to_string());
147 printer_->Print(")");
148 }
149 } else if (symbol.symbol.id) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700150 printer_->Print(symbol.symbol.id.value().to_string());
Ryan Mitchell0c0cedf2019-04-15 16:47:58 -0700151 } else {
152 printer_->Print("???");
Adam Lesinski330edcd2015-05-04 17:40:56 -0700153 }
Ryan Mitchell0c0cedf2019-04-15 16:47:58 -0700154
Adam Lesinski93190b72017-11-03 15:20:17 -0700155 printer_->Println(StringPrintf("=0x%08x", symbol.value));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700156 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700157 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700158 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700159
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700160 void Visit(const Style* style) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700161 for (const auto& entry : style->entries) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700162 if (entry.key.name) {
163 const ResourceName& name = entry.key.name.value();
Adam Lesinski93190b72017-11-03 15:20:17 -0700164 if (!name.package.empty() && name.package != package_) {
165 printer_->Print(name.package);
166 printer_->Print(":");
Adam Lesinski330edcd2015-05-04 17:40:56 -0700167 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700168 printer_->Print(name.entry);
169
170 if (entry.key.id) {
171 printer_->Print("(");
172 printer_->Print(entry.key.id.value().to_string());
173 printer_->Print(")");
174 }
175 } else if (entry.key.id) {
176 printer_->Print(entry.key.id.value().to_string());
177 } else {
178 printer_->Print("???");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700179 }
180
Adam Lesinski93190b72017-11-03 15:20:17 -0700181 printer_->Print("=");
182 PrintItem(*entry.value);
183 printer_->Println();
Adam Lesinski330edcd2015-05-04 17:40:56 -0700184 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700185 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700186
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700187 void Visit(const Array* array) override {
Adam Lesinski93190b72017-11-03 15:20:17 -0700188 const size_t count = array->elements.size();
189 printer_->Print("[");
Donald Chai42fe2b22019-05-07 20:03:27 -0700190 for (size_t i = 0u; i < count; i++) {
191 if (i != 0u && i % 4u == 0u) {
192 printer_->Println();
193 printer_->Print(" ");
Adam Lesinski93190b72017-11-03 15:20:17 -0700194 }
Donald Chai42fe2b22019-05-07 20:03:27 -0700195 PrintItem(*array->elements[i]);
196 if (i != count - 1) {
197 printer_->Print(", ");
198 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700199 }
Donald Chai42fe2b22019-05-07 20:03:27 -0700200 printer_->Println("]");
Adam Lesinski6b372992017-08-09 10:54:23 -0700201 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700202
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700203 void Visit(const Plural* plural) override {
Adam Lesinski93190b72017-11-03 15:20:17 -0700204 constexpr std::array<const char*, Plural::Count> kPluralNames = {
205 {"zero", "one", "two", "few", "many", "other"}};
206
207 for (size_t i = 0; i < Plural::Count; i++) {
208 if (plural->values[i] != nullptr) {
209 printer_->Print(StringPrintf("%s=", kPluralNames[i]));
210 PrintItem(*plural->values[i]);
211 printer_->Println();
212 }
213 }
Adam Lesinski6b372992017-08-09 10:54:23 -0700214 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700215
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700216 void Visit(const Styleable* styleable) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700217 for (const auto& attr : styleable->entries) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700218 if (attr.name) {
219 const ResourceName& name = attr.name.value();
Adam Lesinski93190b72017-11-03 15:20:17 -0700220 if (!name.package.empty() && name.package != package_) {
221 printer_->Print(name.package);
222 printer_->Print(":");
Adam Lesinski355f2852016-02-13 20:26:45 -0800223 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700224 printer_->Print(name.entry);
225
226 if (attr.id) {
227 printer_->Print("(");
228 printer_->Print(attr.id.value().to_string());
229 printer_->Print(")");
230 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700231 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700232
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700233 if (attr.id) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700234 printer_->Print(attr.id.value().to_string());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700235 }
Adam Lesinski5a217b02017-11-16 16:58:02 -0800236 printer_->Println();
Adam Lesinski330edcd2015-05-04 17:40:56 -0700237 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700238 }
239
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700240 void VisitItem(const Item* item) override {
Adam Lesinski93190b72017-11-03 15:20:17 -0700241 // Intentionally left empty, we already printed the Items.
Adam Lesinski6b372992017-08-09 10:54:23 -0700242 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700243
244 private:
245 void PrintItem(const Item& item) {
246 if (const Reference* ref = ValueCast<Reference>(&item)) {
247 // Special case Reference so that we can print local resources without a package name.
248 ref->PrettyPrint(package_, printer_);
249 } else {
250 item.PrettyPrint(printer_);
251 }
252 }
253
254 std::string package_;
255 Printer* printer_;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700256};
257
Adam Lesinski6b372992017-08-09 10:54:23 -0700258} // namespace
259
Adam Lesinski93190b72017-11-03 15:20:17 -0700260void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
261 Printer* printer) {
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700262 const auto table_view = table.GetPartitionedView();
263 for (const auto& package : table_view.packages) {
264 ValueHeadlinePrinter headline_printer(package.name, printer);
265 ValueBodyPrinter body_printer(package.name, printer);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700266
Adam Lesinski93190b72017-11-03 15:20:17 -0700267 printer->Print("Package name=");
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700268 printer->Print(package.name);
269 if (package.id) {
270 printer->Print(StringPrintf(" id=%02x", package.id.value()));
Adam Lesinski93190b72017-11-03 15:20:17 -0700271 }
272 printer->Println();
273
274 printer->Indent();
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700275 for (const auto& type : package.types) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700276 printer->Print("type ");
Iurii Makhnof0c5ff42022-02-22 13:31:02 +0000277 printer->Print(type.named_type.to_string());
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700278 if (type.id) {
279 printer->Print(StringPrintf(" id=%02x", type.id.value()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700280 }
Ryan Mitchell9634efb2021-03-19 14:53:17 -0700281 printer->Println(StringPrintf(" entryCount=%zd", type.entries.size()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700282
Adam Lesinski93190b72017-11-03 15:20:17 -0700283 printer->Indent();
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700284 for (const ResourceTableEntryView& entry : type.entries) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700285 printer->Print("resource ");
Ryan Mitchell4382e442021-07-14 12:53:01 -0700286 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 -0700287 .to_string());
Adam Lesinski93190b72017-11-03 15:20:17 -0700288 printer->Print(" ");
289
290 // Write the name without the package (this is obvious and too verbose).
Iurii Makhnof0c5ff42022-02-22 13:31:02 +0000291 printer->Print(type.named_type.to_string());
Adam Lesinski93190b72017-11-03 15:20:17 -0700292 printer->Print("/");
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700293 printer->Print(entry.name);
Adam Lesinski93190b72017-11-03 15:20:17 -0700294
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700295 switch (entry.visibility.level) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800296 case Visibility::Level::kPublic:
Adam Lesinski93190b72017-11-03 15:20:17 -0700297 printer->Print(" PUBLIC");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700298 break;
Adam Lesinski71be7052017-12-12 16:48:07 -0800299 case Visibility::Level::kPrivate:
Adam Lesinski93190b72017-11-03 15:20:17 -0700300 printer->Print(" _PRIVATE_");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700301 break;
Adam Lesinski71be7052017-12-12 16:48:07 -0800302 case Visibility::Level::kUndefined:
Adam Lesinski93190b72017-11-03 15:20:17 -0700303 // Print nothing.
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700304 break;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700305 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700306
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700307 if (entry.visibility.staged_api) {
Ryan Mitchell1499f502021-03-30 12:20:08 -0700308 printer->Print(" STAGED");
309 }
310
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700311 if (entry.overlayable_item) {
MÃ¥rten Kongstad1d3b64852019-09-17 13:02:32 +0200312 printer->Print(" OVERLAYABLE");
313 }
314
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700315 if (entry.staged_id) {
316 printer->Print(" STAGED_ID=");
317 printer->Print(entry.staged_id.value().id.to_string());
318 }
319
Adam Lesinski93190b72017-11-03 15:20:17 -0700320 printer->Println();
Adam Lesinski330edcd2015-05-04 17:40:56 -0700321
Adam Lesinski71be7052017-12-12 16:48:07 -0800322 if (options.show_values) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700323 printer->Indent();
Ryan Mitchell2fedba92021-04-23 07:47:38 -0700324 for (const auto& value : entry.values) {
Adam Lesinski71be7052017-12-12 16:48:07 -0800325 printer->Print("(");
326 printer->Print(value->config.to_string());
327 printer->Print(") ");
328 value->value->Accept(&headline_printer);
329 if (options.show_sources && !value->value->GetSource().path.empty()) {
330 printer->Print(" src=");
331 printer->Print(value->value->GetSource().to_string());
332 }
333 printer->Println();
334 printer->Indent();
335 value->value->Accept(&body_printer);
336 printer->Undent();
337 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700338 printer->Undent();
Adam Lesinski330edcd2015-05-04 17:40:56 -0700339 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700340 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700341 printer->Undent();
Adam Lesinski330edcd2015-05-04 17:40:56 -0700342 }
Adam Lesinski93190b72017-11-03 15:20:17 -0700343 printer->Undent();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700344 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700345}
346
Adam Lesinski6b372992017-08-09 10:54:23 -0700347static size_t GetNodeIndex(const std::vector<ResourceName>& names, const ResourceName& name) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700348 auto iter = std::lower_bound(names.begin(), names.end(), name);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700349 CHECK(iter != names.end());
350 CHECK(*iter == name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700351 return std::distance(names.begin(), iter);
Adam Lesinski330edcd2015-05-04 17:40:56 -0700352}
353
Adam Lesinski6b372992017-08-09 10:54:23 -0700354void Debug::PrintStyleGraph(ResourceTable* table, const ResourceName& target_style) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700355 std::map<ResourceName, std::set<ResourceName>> graph;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700356
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700357 std::queue<ResourceName> styles_to_visit;
358 styles_to_visit.push(target_style);
359 for (; !styles_to_visit.empty(); styles_to_visit.pop()) {
360 const ResourceName& style_name = styles_to_visit.front();
361 std::set<ResourceName>& parents = graph[style_name];
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700362 if (!parents.empty()) {
363 // We've already visited this style.
364 continue;
365 }
366
Ryan Mitchell4382e442021-07-14 12:53:01 -0700367 std::optional<ResourceTable::SearchResult> result = table->FindResource(style_name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700368 if (result) {
369 ResourceEntry* entry = result.value().entry;
370 for (const auto& value : entry->values) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700371 if (Style* style = ValueCast<Style>(value->value.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700372 if (style->parent && style->parent.value().name) {
373 parents.insert(style->parent.value().name.value());
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700374 styles_to_visit.push(style->parent.value().name.value());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700375 }
Adam Lesinskid13fb242015-05-12 20:40:48 -0700376 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700377 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700378 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700379 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700380
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700381 std::vector<ResourceName> names;
382 for (const auto& entry : graph) {
383 names.push_back(entry.first);
384 }
385
386 std::cout << "digraph styles {\n";
387 for (const auto& name : names) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700388 std::cout << " node_" << GetNodeIndex(names, name) << " [label=\"" << name << "\"];\n";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700389 }
390
391 for (const auto& entry : graph) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700392 const ResourceName& style_name = entry.first;
393 size_t style_node_index = GetNodeIndex(names, style_name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700394
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700395 for (const auto& parent_name : entry.second) {
396 std::cout << " node_" << style_node_index << " -> "
397 << "node_" << GetNodeIndex(names, parent_name) << ";\n";
Adam Lesinskid13fb242015-05-12 20:40:48 -0700398 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700399 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700400
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700401 std::cout << "}" << std::endl;
Adam Lesinski330edcd2015-05-04 17:40:56 -0700402}
403
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700404void Debug::DumpHex(const void* data, size_t len) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700405 const uint8_t* d = (const uint8_t*)data;
406 for (size_t i = 0; i < len; i++) {
Adam Lesinski6b372992017-08-09 10:54:23 -0700407 std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)d[i] << " ";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700408 if (i % 8 == 7) {
409 std::cerr << "\n";
Adam Lesinski52364f72016-01-11 13:10:24 -0800410 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700411 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800412
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700413 if (len - 1 % 8 != 7) {
414 std::cerr << std::endl;
415 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800416}
417
Ryan Mitchell5d275512018-07-19 14:29:00 -0700418void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer) {
419 using namespace android;
Ryan Mitchell4e9a9222018-11-13 10:40:07 -0800420
Ryan Mitchell5d275512018-07-19 14:29:00 -0700421 if (pool->getError() == NO_INIT) {
422 printer->Print("String pool is unitialized.\n");
423 return;
424 } else if (pool->getError() != NO_ERROR) {
425 printer->Print("String pool is corrupt/invalid.\n");
426 return;
427 }
428
429 SortedVector<const void*> uniqueStrings;
430 const size_t N = pool->size();
431 for (size_t i=0; i<N; i++) {
432 size_t len;
433 if (pool->isUTF8()) {
Ryan Mitchelldb21f09a2020-11-16 23:08:18 +0000434 uniqueStrings.add(UnpackOptionalString(pool->string8At(i), &len));
Ryan Mitchell5d275512018-07-19 14:29:00 -0700435 } else {
Ryan Mitchelldb21f09a2020-11-16 23:08:18 +0000436 uniqueStrings.add(UnpackOptionalString(pool->stringAt(i), &len));
Ryan Mitchell5d275512018-07-19 14:29:00 -0700437 }
438 }
439
440 printer->Print(StringPrintf("String pool of %zd unique %s %s strings, %zd entries and %zd styles "
441 "using %zd bytes:\n", uniqueStrings.size(),
442 pool->isUTF8() ? "UTF-8" : "UTF-16",
443 pool->isSorted() ? "sorted" : "non-sorted", N, pool->styleCount(),
444 pool->bytes()));
445
446 const size_t NS = pool->size();
447 for (size_t s=0; s<NS; s++) {
Ryan Mitchelldb21f09a2020-11-16 23:08:18 +0000448 auto str = pool->string8ObjectAt(s);
449 printer->Print(StringPrintf("String #%zd : %s\n", s, str.has_value() ? str->string() : ""));
Ryan Mitchell5d275512018-07-19 14:29:00 -0700450 }
451}
452
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700453namespace {
454
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700455class XmlPrinter : public xml::ConstVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700456 public:
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700457 using xml::ConstVisitor::Visit;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700458
Chih-Hung Hsieh1fc78e12018-12-20 13:37:44 -0800459 explicit XmlPrinter(Printer* printer) : printer_(printer) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800460 }
461
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700462 void Visit(const xml::Element* el) override {
Adam Lesinski6b372992017-08-09 10:54:23 -0700463 for (const xml::NamespaceDecl& decl : el->namespace_decls) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800464 printer_->Println(StringPrintf("N: %s=%s (line=%zu)", decl.prefix.c_str(), decl.uri.c_str(),
465 decl.line_number));
466 printer_->Indent();
Adam Lesinski6b372992017-08-09 10:54:23 -0700467 }
468
Adam Lesinskida9eba32018-02-13 16:44:10 -0800469 printer_->Print("E: ");
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700470 if (!el->namespace_uri.empty()) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800471 printer_->Print(el->namespace_uri);
472 printer_->Print(":");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700473 }
Adam Lesinskida9eba32018-02-13 16:44:10 -0800474 printer_->Println(StringPrintf("%s (line=%zu)", el->name.c_str(), el->line_number));
475 printer_->Indent();
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700476
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700477 for (const xml::Attribute& attr : el->attributes) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800478 printer_->Print("A: ");
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700479 if (!attr.namespace_uri.empty()) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800480 printer_->Print(attr.namespace_uri);
481 printer_->Print(":");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700482 }
Adam Lesinskida9eba32018-02-13 16:44:10 -0800483 printer_->Print(attr.name);
Adam Lesinski4ca56972017-04-26 21:49:53 -0700484
485 if (attr.compiled_attribute) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800486 printer_->Print("(");
Ryan Mitchell4382e442021-07-14 12:53:01 -0700487 printer_->Print(attr.compiled_attribute.value().id.value_or(ResourceId(0)).to_string());
Adam Lesinskida9eba32018-02-13 16:44:10 -0800488 printer_->Print(")");
Adam Lesinski4ca56972017-04-26 21:49:53 -0700489 }
Adam Lesinskida9eba32018-02-13 16:44:10 -0800490 printer_->Print("=");
Shane Farmer6ed40612017-09-06 10:00:07 -0700491 if (attr.compiled_value != nullptr) {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800492 attr.compiled_value->PrettyPrint(printer_);
Shane Farmer6ed40612017-09-06 10:00:07 -0700493 } else {
Adam Lesinskibbf42972018-02-14 13:36:09 -0800494 printer_->Print("\"");
Adam Lesinskida9eba32018-02-13 16:44:10 -0800495 printer_->Print(attr.value);
Adam Lesinskibbf42972018-02-14 13:36:09 -0800496 printer_->Print("\"");
497 }
498
499 if (!attr.value.empty()) {
500 printer_->Print(" (Raw: \"");
501 printer_->Print(attr.value);
502 printer_->Print("\")");
Shane Farmer6ed40612017-09-06 10:00:07 -0700503 }
Adam Lesinskida9eba32018-02-13 16:44:10 -0800504 printer_->Println();
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700505 }
506
Adam Lesinskida9eba32018-02-13 16:44:10 -0800507 printer_->Indent();
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700508 xml::ConstVisitor::Visit(el);
Adam Lesinskida9eba32018-02-13 16:44:10 -0800509 printer_->Undent();
510 printer_->Undent();
511
512 for (size_t i = 0; i < el->namespace_decls.size(); i++) {
513 printer_->Undent();
514 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700515 }
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700516
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700517 void Visit(const xml::Text* text) override {
Adam Lesinskida9eba32018-02-13 16:44:10 -0800518 printer_->Println(StringPrintf("T: '%s'", text->text.c_str()));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700519 }
520
521 private:
Adam Lesinskida9eba32018-02-13 16:44:10 -0800522 Printer* printer_;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700523};
524
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700525} // namespace
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700526
Adam Lesinskida9eba32018-02-13 16:44:10 -0800527void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) {
528 XmlPrinter xml_visitor(printer);
529 doc.root->Accept(&xml_visitor);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700530}
Adam Lesinski52364f72016-01-11 13:10:24 -0800531
MÃ¥rten Kongstad1d3b64852019-09-17 13:02:32 +0200532struct DumpOverlayableEntry {
533 std::string overlayable_section;
534 std::string policy_subsection;
535 std::string resource_name;
536};
537
538void Debug::DumpOverlayable(const ResourceTable& table, text::Printer* printer) {
539 std::vector<DumpOverlayableEntry> items;
540 for (const auto& package : table.packages) {
541 for (const auto& type : package->types) {
542 for (const auto& entry : type->entries) {
543 if (entry->overlayable_item) {
544 const auto& overlayable_item = entry->overlayable_item.value();
545 const auto overlayable_section = StringPrintf(R"(name="%s" actor="%s")",
546 overlayable_item.overlayable->name.c_str(),
547 overlayable_item.overlayable->actor.c_str());
548 const auto policy_subsection = StringPrintf(R"(policies="%s")",
Ryan Mitchella7070132020-05-13 14:17:52 -0700549 android::idmap2::policy::PoliciesToDebugString(overlayable_item.policies).c_str());
MÃ¥rten Kongstad1d3b64852019-09-17 13:02:32 +0200550 const auto value =
Iurii Makhnof0c5ff42022-02-22 13:31:02 +0000551 StringPrintf("%s/%s", type->named_type.to_string().data(), entry->name.c_str());
MÃ¥rten Kongstad1d3b64852019-09-17 13:02:32 +0200552 items.push_back(DumpOverlayableEntry{overlayable_section, policy_subsection, value});
553 }
554 }
555 }
556 }
557
558 std::sort(items.begin(), items.end(),
559 [](const DumpOverlayableEntry& a, const DumpOverlayableEntry& b) {
560 if (a.overlayable_section != b.overlayable_section) {
561 return a.overlayable_section < b.overlayable_section;
562 }
563 if (a.policy_subsection != b.policy_subsection) {
564 return a.policy_subsection < b.policy_subsection;
565 }
566 return a.resource_name < b.resource_name;
567 });
568
569 std::string last_overlayable_section;
570 std::string last_policy_subsection;
571 for (const auto& item : items) {
572 if (last_overlayable_section != item.overlayable_section) {
573 printer->Println(item.overlayable_section);
574 last_overlayable_section = item.overlayable_section;
575 }
576 if (last_policy_subsection != item.policy_subsection) {
577 printer->Indent();
578 printer->Println(item.policy_subsection);
579 last_policy_subsection = item.policy_subsection;
580 printer->Undent();
581 }
582 printer->Indent();
583 printer->Indent();
584 printer->Println(item.resource_name);
585 printer->Undent();
586 printer->Undent();
587 }
588}
589
Ryan Mitchell19b27092018-08-13 11:36:27 -0700590namespace {
591
592using namespace android;
593
594class ChunkPrinter {
595 public:
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000596 ChunkPrinter(const void* data, size_t len, Printer* printer, android::IDiagnostics* diag)
Ryan Mitchell19b27092018-08-13 11:36:27 -0700597 : data_(data), data_len_(len), printer_(printer), diag_(diag) {
598 }
599
600 void PrintChunkHeader(const ResChunk_header* chunk) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000601 switch (android::util::DeviceToHost16(chunk->type)) {
Ryan Mitchell19b27092018-08-13 11:36:27 -0700602 case RES_STRING_POOL_TYPE:
603 printer_->Print("[RES_STRING_POOL_TYPE]");
604 break;
605 case RES_TABLE_LIBRARY_TYPE:
606 printer_->Print("[RES_TABLE_LIBRARY_TYPE]");
607 break;
608 case RES_TABLE_TYPE:
609 printer_->Print("[ResTable_header]");
610 break;
611 case RES_TABLE_PACKAGE_TYPE:
612 printer_->Print("[ResTable_package]");
613 break;
614 case RES_TABLE_TYPE_TYPE:
615 printer_->Print("[ResTable_type]");
616 break;
617 case RES_TABLE_TYPE_SPEC_TYPE:
618 printer_->Print("[RES_TABLE_TYPE_SPEC_TYPE]");
619 break;
620 default:
621 break;
622 }
623
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000624 printer_->Print(StringPrintf(" chunkSize: %u", android::util::DeviceToHost32(chunk->size)));
625 printer_->Print(
626 StringPrintf(" headerSize: %u", android::util::DeviceToHost32(chunk->headerSize)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700627 }
628
629 bool PrintTable(const ResTable_header* chunk) {
630 printer_->Print(
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000631 StringPrintf(" Package count: %u\n", android::util::DeviceToHost32(chunk->packageCount)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700632
633 // Print the chunks contained within the table
634 printer_->Indent();
635 bool success = PrintChunk(
636 ResChunkPullParser(GetChunkData(&chunk->header), GetChunkDataLen(&chunk->header)));
637 printer_->Undent();
638 return success;
639 }
640
641 void PrintResValue(const Res_value* value, const ConfigDescription& config,
642 const ResourceType* type) {
643 printer_->Print("[Res_value]");
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000644 printer_->Print(StringPrintf(" size: %u", android::util::DeviceToHost32(value->size)));
645 printer_->Print(
646 StringPrintf(" dataType: 0x%02x", android::util::DeviceToHost32(value->dataType)));
647 printer_->Print(StringPrintf(" data: 0x%08x", android::util::DeviceToHost32(value->data)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700648
649 if (type) {
650 auto item =
651 ResourceUtils::ParseBinaryResValue(*type, config, value_pool_, *value, &out_pool_);
652 printer_->Print(" (");
653 item->PrettyPrint(printer_);
654 printer_->Print(")");
655 }
656
657 printer_->Print("\n");
658 }
659
660 bool PrintTableType(const ResTable_type* chunk) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000661 printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700662 printer_->Print(StringPrintf(
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000663 " name: %s",
664 android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1)
665 .c_str()));
666 printer_->Print(StringPrintf(" flags: 0x%02x", android::util::DeviceToHost32(chunk->flags)));
667 printer_->Print(
668 StringPrintf(" entryCount: %u", android::util::DeviceToHost32(chunk->entryCount)));
669 printer_->Print(
670 StringPrintf(" entryStart: %u", android::util::DeviceToHost32(chunk->entriesStart)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700671
672 ConfigDescription config;
673 config.copyFromDtoH(chunk->config);
674 printer_->Print(StringPrintf(" config: %s\n", config.to_string().c_str()));
675
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000676 const ResourceType* type = ParseResourceType(
677 android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700678
679 printer_->Indent();
680
681 TypeVariant tv(chunk);
682 for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
683 const ResTable_entry* entry = *it;
684 if (!entry) {
685 continue;
686 }
687
688 printer_->Print((entry->flags & ResTable_entry::FLAG_COMPLEX) ? "[ResTable_map_entry]"
689 : "[ResTable_entry]");
690 printer_->Print(StringPrintf(" id: 0x%04x", it.index()));
691 printer_->Print(StringPrintf(
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000692 " name: %s",
693 android::util::GetString(key_pool_, android::util::DeviceToHost32(entry->key.index))
694 .c_str()));
695 printer_->Print(
696 StringPrintf(" keyIndex: %u", android::util::DeviceToHost32(entry->key.index)));
697 printer_->Print(StringPrintf(" size: %u", android::util::DeviceToHost32(entry->size)));
698 printer_->Print(StringPrintf(" flags: 0x%04x", android::util::DeviceToHost32(entry->flags)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700699
700 printer_->Indent();
701
702 if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
703 auto map_entry = (const ResTable_map_entry*)entry;
Ryan Mitchell19b27092018-08-13 11:36:27 -0700704 printer_->Print(
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000705 StringPrintf(" count: 0x%04x", android::util::DeviceToHost32(map_entry->count)));
706 printer_->Print(StringPrintf(" parent: 0x%08x\n",
707 android::util::DeviceToHost32(map_entry->parent.ident)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700708
709 // Print the name and value mappings
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000710 auto maps = (const ResTable_map*)((const uint8_t*)entry +
711 android::util::DeviceToHost32(entry->size));
712 for (size_t i = 0, count = android::util::DeviceToHost32(map_entry->count); i < count;
713 i++) {
Ryan Mitchell19b27092018-08-13 11:36:27 -0700714 PrintResValue(&(maps[i].value), config, type);
715
716 printer_->Print(StringPrintf(
717 " name: %s name-id:%d\n",
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000718 android::util::GetString(key_pool_, android::util::DeviceToHost32(maps[i].name.ident))
719 .c_str(),
720 android::util::DeviceToHost32(maps[i].name.ident)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700721 }
722 } else {
723 printer_->Print("\n");
724
725 // Print the value of the entry
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000726 auto value =
727 (const Res_value*)((const uint8_t*)entry + android::util::DeviceToHost32(entry->size));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700728 PrintResValue(value, config, type);
729 }
730
731 printer_->Undent();
732 }
733
734 printer_->Undent();
735 return true;
736 }
737
738 void PrintStringPool(const ResStringPool_header* chunk) {
739 // Initialize the string pools
740
741 ResStringPool* pool;
742 if (value_pool_.getError() == NO_INIT) {
743 pool = &value_pool_;
744 } else if (type_pool_.getError() == NO_INIT) {
745 pool = &type_pool_;
746 } else if (key_pool_.getError() == NO_INIT) {
747 pool = &key_pool_;
748 } else {
749 return;
750 }
751
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000752 pool->setTo(chunk, android::util::DeviceToHost32(
753 (reinterpret_cast<const ResChunk_header*>(chunk))->size));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700754
755 printer_->Print("\n");
756
757 for (size_t i = 0; i < pool->size(); i++) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000758 printer_->Print(StringPrintf("#%zd : %s\n", i, android::util::GetString(*pool, i).c_str()));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700759 }
760 }
761
762 bool PrintPackage(const ResTable_package* chunk) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000763 printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700764
765 size_t len = strnlen16((const char16_t*)chunk->name, std::size(chunk->name));
766 std::u16string package_name(len, u'\0');
767 package_name.resize(len);
768 for (size_t i = 0; i < len; i++) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000769 package_name[i] = android::util::DeviceToHost16(chunk->name[i]);
Ryan Mitchell19b27092018-08-13 11:36:27 -0700770 }
771
772 printer_->Print(StringPrintf("name: %s", String8(package_name.c_str()).c_str()));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700773 printer_->Print(
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000774 StringPrintf(" typeStrings: %u", android::util::DeviceToHost32(chunk->typeStrings)));
775 printer_->Print(
776 StringPrintf(" lastPublicType: %u", android::util::DeviceToHost32(chunk->lastPublicType)));
777 printer_->Print(
778 StringPrintf(" keyStrings: %u", android::util::DeviceToHost32(chunk->keyStrings)));
779 printer_->Print(
780 StringPrintf(" lastPublicKey: %u", android::util::DeviceToHost32(chunk->lastPublicKey)));
781 printer_->Print(
782 StringPrintf(" typeIdOffset: %u\n", android::util::DeviceToHost32(chunk->typeIdOffset)));
Ryan Mitchell19b27092018-08-13 11:36:27 -0700783
784 // Print the chunks contained within the table
785 printer_->Indent();
786 bool success = PrintChunk(
787 ResChunkPullParser(GetChunkData(&chunk->header), GetChunkDataLen(&chunk->header)));
788 printer_->Undent();
789 return success;
790 }
791
792 bool PrintChunk(ResChunkPullParser&& parser) {
793 while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
794 auto chunk = parser.chunk();
795 PrintChunkHeader(chunk);
796
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000797 switch (android::util::DeviceToHost16(chunk->type)) {
Ryan Mitchell19b27092018-08-13 11:36:27 -0700798 case RES_STRING_POOL_TYPE:
799 PrintStringPool(reinterpret_cast<const ResStringPool_header*>(chunk));
800 break;
801
802 case RES_TABLE_TYPE:
803 PrintTable(reinterpret_cast<const ResTable_header*>(chunk));
804 break;
805
806 case RES_TABLE_PACKAGE_TYPE:
807 type_pool_.uninit();
808 key_pool_.uninit();
809 PrintPackage(reinterpret_cast<const ResTable_package*>(chunk));
810 break;
811
812 case RES_TABLE_TYPE_TYPE:
813 PrintTableType(reinterpret_cast<const ResTable_type*>(chunk));
814 break;
815
816 default:
817 printer_->Print("\n");
818 break;
819 }
820 }
821
822 if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000823 diag_->Error(android::DiagMessage(source_) << "corrupt resource table: " << parser.error());
Ryan Mitchell19b27092018-08-13 11:36:27 -0700824 return false;
825 }
826
827 return true;
828 }
829
830 void Print() {
831 PrintChunk(ResChunkPullParser(data_, data_len_));
832 printer_->Print("[End]\n");
833 }
834
835 private:
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000836 const android::Source source_;
Ryan Mitchell19b27092018-08-13 11:36:27 -0700837 const void* data_;
838 const size_t data_len_;
839 Printer* printer_;
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000840 android::IDiagnostics* diag_;
Ryan Mitchell19b27092018-08-13 11:36:27 -0700841
842 // The standard value string pool for resource values.
843 ResStringPool value_pool_;
844
845 // The string pool that holds the names of the types defined
846 // in this table.
847 ResStringPool type_pool_;
848
849 // The string pool that holds the names of the entries defined
850 // in this table.
851 ResStringPool key_pool_;
852
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000853 android::StringPool out_pool_;
Ryan Mitchell19b27092018-08-13 11:36:27 -0700854};
855
856} // namespace
857
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000858void Debug::DumpChunks(const void* data, size_t len, Printer* printer,
859 android::IDiagnostics* diag) {
Ryan Mitchell19b27092018-08-13 11:36:27 -0700860 ChunkPrinter chunk_printer(data, len, printer, diag);
861 chunk_printer.Print();
862}
863
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700864} // namespace aapt