xref: /aosp_15_r20/frameworks/base/tools/aapt2/Debug.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "Debug.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <androidfw/TypeWrappers.h>
20*d57664e9SAndroid Build Coastguard Worker #include <androidfw/Util.h>
21*d57664e9SAndroid Build Coastguard Worker #include <format/binary/ResChunkPullParser.h>
22*d57664e9SAndroid Build Coastguard Worker 
23*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
24*d57664e9SAndroid Build Coastguard Worker #include <array>
25*d57664e9SAndroid Build Coastguard Worker #include <map>
26*d57664e9SAndroid Build Coastguard Worker #include <memory>
27*d57664e9SAndroid Build Coastguard Worker #include <queue>
28*d57664e9SAndroid Build Coastguard Worker #include <set>
29*d57664e9SAndroid Build Coastguard Worker #include <span>
30*d57664e9SAndroid Build Coastguard Worker #include <utility>
31*d57664e9SAndroid Build Coastguard Worker #include <vector>
32*d57664e9SAndroid Build Coastguard Worker 
33*d57664e9SAndroid Build Coastguard Worker #include "ResourceTable.h"
34*d57664e9SAndroid Build Coastguard Worker #include "ResourceUtils.h"
35*d57664e9SAndroid Build Coastguard Worker #include "ResourceValues.h"
36*d57664e9SAndroid Build Coastguard Worker #include "ValueVisitor.h"
37*d57664e9SAndroid Build Coastguard Worker #include "android-base/logging.h"
38*d57664e9SAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
39*d57664e9SAndroid Build Coastguard Worker #include "androidfw/ResourceTypes.h"
40*d57664e9SAndroid Build Coastguard Worker #include "idmap2/Policies.h"
41*d57664e9SAndroid Build Coastguard Worker #include "text/Printer.h"
42*d57664e9SAndroid Build Coastguard Worker #include "util/Util.h"
43*d57664e9SAndroid Build Coastguard Worker 
44*d57664e9SAndroid Build Coastguard Worker using ::aapt::text::Printer;
45*d57664e9SAndroid Build Coastguard Worker using ::android::StringPiece;
46*d57664e9SAndroid Build Coastguard Worker using ::android::base::StringPrintf;
47*d57664e9SAndroid Build Coastguard Worker 
48*d57664e9SAndroid Build Coastguard Worker using android::idmap2::policy::kPolicyStringToFlag;
49*d57664e9SAndroid Build Coastguard Worker 
50*d57664e9SAndroid Build Coastguard Worker using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
51*d57664e9SAndroid Build Coastguard Worker 
52*d57664e9SAndroid Build Coastguard Worker namespace aapt {
53*d57664e9SAndroid Build Coastguard Worker 
54*d57664e9SAndroid Build Coastguard Worker namespace {
55*d57664e9SAndroid Build Coastguard Worker 
56*d57664e9SAndroid Build Coastguard Worker class ValueHeadlinePrinter : public ConstValueVisitor {
57*d57664e9SAndroid Build Coastguard Worker  public:
58*d57664e9SAndroid Build Coastguard Worker   using ConstValueVisitor::Visit;
59*d57664e9SAndroid Build Coastguard Worker 
ValueHeadlinePrinter(const std::string & package,Printer * printer)60*d57664e9SAndroid Build Coastguard Worker   explicit ValueHeadlinePrinter(const std::string& package, Printer* printer)
61*d57664e9SAndroid Build Coastguard Worker       : package_(package), printer_(printer) {
62*d57664e9SAndroid Build Coastguard Worker   }
63*d57664e9SAndroid Build Coastguard Worker 
Visit(const Attribute * attr)64*d57664e9SAndroid Build Coastguard Worker   void Visit(const Attribute* attr) override {
65*d57664e9SAndroid Build Coastguard Worker     printer_->Print("(attr) type=");
66*d57664e9SAndroid Build Coastguard Worker     printer_->Print(attr->MaskString());
67*d57664e9SAndroid Build Coastguard Worker     if (!attr->symbols.empty()) {
68*d57664e9SAndroid Build Coastguard Worker       printer_->Print(StringPrintf(" size=%zd", attr->symbols.size()));
69*d57664e9SAndroid Build Coastguard Worker     }
70*d57664e9SAndroid Build Coastguard Worker   }
71*d57664e9SAndroid Build Coastguard Worker 
Visit(const Style * style)72*d57664e9SAndroid Build Coastguard Worker   void Visit(const Style* style) override {
73*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf("(style) size=%zd", style->entries.size()));
74*d57664e9SAndroid Build Coastguard Worker     if (style->parent) {
75*d57664e9SAndroid Build Coastguard Worker       printer_->Print(" parent=");
76*d57664e9SAndroid Build Coastguard Worker 
77*d57664e9SAndroid Build Coastguard Worker       const Reference& parent_ref = style->parent.value();
78*d57664e9SAndroid Build Coastguard Worker       if (parent_ref.name) {
79*d57664e9SAndroid Build Coastguard Worker         if (parent_ref.private_reference) {
80*d57664e9SAndroid Build Coastguard Worker           printer_->Print("*");
81*d57664e9SAndroid Build Coastguard Worker         }
82*d57664e9SAndroid Build Coastguard Worker 
83*d57664e9SAndroid Build Coastguard Worker         const ResourceName& parent_name = parent_ref.name.value();
84*d57664e9SAndroid Build Coastguard Worker         if (package_ != parent_name.package) {
85*d57664e9SAndroid Build Coastguard Worker           printer_->Print(parent_name.package);
86*d57664e9SAndroid Build Coastguard Worker           printer_->Print(":");
87*d57664e9SAndroid Build Coastguard Worker         }
88*d57664e9SAndroid Build Coastguard Worker         printer_->Print(parent_name.type.to_string());
89*d57664e9SAndroid Build Coastguard Worker         printer_->Print("/");
90*d57664e9SAndroid Build Coastguard Worker         printer_->Print(parent_name.entry);
91*d57664e9SAndroid Build Coastguard Worker         if (parent_ref.id) {
92*d57664e9SAndroid Build Coastguard Worker           printer_->Print(" (");
93*d57664e9SAndroid Build Coastguard Worker           printer_->Print(parent_ref.id.value().to_string());
94*d57664e9SAndroid Build Coastguard Worker           printer_->Print(")");
95*d57664e9SAndroid Build Coastguard Worker         }
96*d57664e9SAndroid Build Coastguard Worker       } else if (parent_ref.id) {
97*d57664e9SAndroid Build Coastguard Worker         printer_->Print(parent_ref.id.value().to_string());
98*d57664e9SAndroid Build Coastguard Worker       } else {
99*d57664e9SAndroid Build Coastguard Worker         printer_->Print("???");
100*d57664e9SAndroid Build Coastguard Worker       }
101*d57664e9SAndroid Build Coastguard Worker     }
102*d57664e9SAndroid Build Coastguard Worker   }
103*d57664e9SAndroid Build Coastguard Worker 
Visit(const Array * array)104*d57664e9SAndroid Build Coastguard Worker   void Visit(const Array* array) override {
105*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf("(array) size=%zd", array->elements.size()));
106*d57664e9SAndroid Build Coastguard Worker   }
107*d57664e9SAndroid Build Coastguard Worker 
Visit(const Plural * plural)108*d57664e9SAndroid Build Coastguard Worker   void Visit(const Plural* plural) override {
109*d57664e9SAndroid Build Coastguard Worker     size_t count = std::count_if(plural->values.begin(), plural->values.end(),
110*d57664e9SAndroid Build Coastguard Worker                                  [](const std::unique_ptr<Item>& v) { return v != nullptr; });
111*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf("(plurals) size=%zd", count));
112*d57664e9SAndroid Build Coastguard Worker   }
113*d57664e9SAndroid Build Coastguard Worker 
Visit(const Styleable * styleable)114*d57664e9SAndroid Build Coastguard Worker   void Visit(const Styleable* styleable) override {
115*d57664e9SAndroid Build Coastguard Worker     printer_->Println(StringPrintf("(styleable) size=%zd", styleable->entries.size()));
116*d57664e9SAndroid Build Coastguard Worker   }
117*d57664e9SAndroid Build Coastguard Worker 
VisitItem(const Item * item)118*d57664e9SAndroid Build Coastguard Worker   void VisitItem(const Item* item) override {
119*d57664e9SAndroid Build Coastguard Worker     // Pretty much guaranteed to be one line.
120*d57664e9SAndroid Build Coastguard Worker     if (const Reference* ref = ValueCast<Reference>(item)) {
121*d57664e9SAndroid Build Coastguard Worker       // Special case Reference so that we can print local resources without a package name.
122*d57664e9SAndroid Build Coastguard Worker       ref->PrettyPrint(package_, printer_);
123*d57664e9SAndroid Build Coastguard Worker     } else {
124*d57664e9SAndroid Build Coastguard Worker       item->PrettyPrint(printer_);
125*d57664e9SAndroid Build Coastguard Worker     }
126*d57664e9SAndroid Build Coastguard Worker   }
127*d57664e9SAndroid Build Coastguard Worker 
128*d57664e9SAndroid Build Coastguard Worker  private:
129*d57664e9SAndroid Build Coastguard Worker   std::string package_;
130*d57664e9SAndroid Build Coastguard Worker   Printer* printer_;
131*d57664e9SAndroid Build Coastguard Worker };
132*d57664e9SAndroid Build Coastguard Worker 
133*d57664e9SAndroid Build Coastguard Worker class ValueBodyPrinter : public ConstValueVisitor {
134*d57664e9SAndroid Build Coastguard Worker  public:
135*d57664e9SAndroid Build Coastguard Worker   using ConstValueVisitor::Visit;
136*d57664e9SAndroid Build Coastguard Worker 
ValueBodyPrinter(const std::string & package,Printer * printer)137*d57664e9SAndroid Build Coastguard Worker   explicit ValueBodyPrinter(const std::string& package, Printer* printer)
138*d57664e9SAndroid Build Coastguard Worker       : package_(package), printer_(printer) {
139*d57664e9SAndroid Build Coastguard Worker   }
140*d57664e9SAndroid Build Coastguard Worker 
Visit(const Attribute * attr)141*d57664e9SAndroid Build Coastguard Worker   void Visit(const Attribute* attr) override {
142*d57664e9SAndroid Build Coastguard Worker     constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
143*d57664e9SAndroid Build Coastguard Worker     if (attr->type_mask & kMask) {
144*d57664e9SAndroid Build Coastguard Worker       for (const auto& symbol : attr->symbols) {
145*d57664e9SAndroid Build Coastguard Worker         if (symbol.symbol.name) {
146*d57664e9SAndroid Build Coastguard Worker           printer_->Print(symbol.symbol.name.value().entry);
147*d57664e9SAndroid Build Coastguard Worker 
148*d57664e9SAndroid Build Coastguard Worker           if (symbol.symbol.id) {
149*d57664e9SAndroid Build Coastguard Worker             printer_->Print("(");
150*d57664e9SAndroid Build Coastguard Worker             printer_->Print(symbol.symbol.id.value().to_string());
151*d57664e9SAndroid Build Coastguard Worker             printer_->Print(")");
152*d57664e9SAndroid Build Coastguard Worker           }
153*d57664e9SAndroid Build Coastguard Worker         } else if (symbol.symbol.id) {
154*d57664e9SAndroid Build Coastguard Worker           printer_->Print(symbol.symbol.id.value().to_string());
155*d57664e9SAndroid Build Coastguard Worker         } else {
156*d57664e9SAndroid Build Coastguard Worker           printer_->Print("???");
157*d57664e9SAndroid Build Coastguard Worker         }
158*d57664e9SAndroid Build Coastguard Worker 
159*d57664e9SAndroid Build Coastguard Worker         printer_->Println(StringPrintf("=0x%08x", symbol.value));
160*d57664e9SAndroid Build Coastguard Worker       }
161*d57664e9SAndroid Build Coastguard Worker     }
162*d57664e9SAndroid Build Coastguard Worker   }
163*d57664e9SAndroid Build Coastguard Worker 
Visit(const Style * style)164*d57664e9SAndroid Build Coastguard Worker   void Visit(const Style* style) override {
165*d57664e9SAndroid Build Coastguard Worker     for (const auto& entry : style->entries) {
166*d57664e9SAndroid Build Coastguard Worker       if (entry.key.name) {
167*d57664e9SAndroid Build Coastguard Worker         const ResourceName& name = entry.key.name.value();
168*d57664e9SAndroid Build Coastguard Worker         if (!name.package.empty() && name.package != package_) {
169*d57664e9SAndroid Build Coastguard Worker           printer_->Print(name.package);
170*d57664e9SAndroid Build Coastguard Worker           printer_->Print(":");
171*d57664e9SAndroid Build Coastguard Worker         }
172*d57664e9SAndroid Build Coastguard Worker         printer_->Print(name.entry);
173*d57664e9SAndroid Build Coastguard Worker 
174*d57664e9SAndroid Build Coastguard Worker         if (entry.key.id) {
175*d57664e9SAndroid Build Coastguard Worker           printer_->Print("(");
176*d57664e9SAndroid Build Coastguard Worker           printer_->Print(entry.key.id.value().to_string());
177*d57664e9SAndroid Build Coastguard Worker           printer_->Print(")");
178*d57664e9SAndroid Build Coastguard Worker         }
179*d57664e9SAndroid Build Coastguard Worker       } else if (entry.key.id) {
180*d57664e9SAndroid Build Coastguard Worker         printer_->Print(entry.key.id.value().to_string());
181*d57664e9SAndroid Build Coastguard Worker       } else {
182*d57664e9SAndroid Build Coastguard Worker         printer_->Print("???");
183*d57664e9SAndroid Build Coastguard Worker       }
184*d57664e9SAndroid Build Coastguard Worker 
185*d57664e9SAndroid Build Coastguard Worker       printer_->Print("=");
186*d57664e9SAndroid Build Coastguard Worker       PrintItem(*entry.value);
187*d57664e9SAndroid Build Coastguard Worker       printer_->Println();
188*d57664e9SAndroid Build Coastguard Worker     }
189*d57664e9SAndroid Build Coastguard Worker   }
190*d57664e9SAndroid Build Coastguard Worker 
Visit(const Array * array)191*d57664e9SAndroid Build Coastguard Worker   void Visit(const Array* array) override {
192*d57664e9SAndroid Build Coastguard Worker     const size_t count = array->elements.size();
193*d57664e9SAndroid Build Coastguard Worker     printer_->Print("[");
194*d57664e9SAndroid Build Coastguard Worker     for (size_t i = 0u; i < count; i++) {
195*d57664e9SAndroid Build Coastguard Worker       if (i != 0u && i % 4u == 0u) {
196*d57664e9SAndroid Build Coastguard Worker         printer_->Println();
197*d57664e9SAndroid Build Coastguard Worker         printer_->Print(" ");
198*d57664e9SAndroid Build Coastguard Worker       }
199*d57664e9SAndroid Build Coastguard Worker       PrintItem(*array->elements[i]);
200*d57664e9SAndroid Build Coastguard Worker       if (i != count - 1) {
201*d57664e9SAndroid Build Coastguard Worker         printer_->Print(", ");
202*d57664e9SAndroid Build Coastguard Worker       }
203*d57664e9SAndroid Build Coastguard Worker     }
204*d57664e9SAndroid Build Coastguard Worker     printer_->Println("]");
205*d57664e9SAndroid Build Coastguard Worker   }
206*d57664e9SAndroid Build Coastguard Worker 
Visit(const Plural * plural)207*d57664e9SAndroid Build Coastguard Worker   void Visit(const Plural* plural) override {
208*d57664e9SAndroid Build Coastguard Worker     constexpr std::array<const char*, Plural::Count> kPluralNames = {
209*d57664e9SAndroid Build Coastguard Worker         {"zero", "one", "two", "few", "many", "other"}};
210*d57664e9SAndroid Build Coastguard Worker 
211*d57664e9SAndroid Build Coastguard Worker     for (size_t i = 0; i < Plural::Count; i++) {
212*d57664e9SAndroid Build Coastguard Worker       if (plural->values[i] != nullptr) {
213*d57664e9SAndroid Build Coastguard Worker         printer_->Print(StringPrintf("%s=", kPluralNames[i]));
214*d57664e9SAndroid Build Coastguard Worker         PrintItem(*plural->values[i]);
215*d57664e9SAndroid Build Coastguard Worker         printer_->Println();
216*d57664e9SAndroid Build Coastguard Worker       }
217*d57664e9SAndroid Build Coastguard Worker     }
218*d57664e9SAndroid Build Coastguard Worker   }
219*d57664e9SAndroid Build Coastguard Worker 
Visit(const Styleable * styleable)220*d57664e9SAndroid Build Coastguard Worker   void Visit(const Styleable* styleable) override {
221*d57664e9SAndroid Build Coastguard Worker     for (const auto& attr : styleable->entries) {
222*d57664e9SAndroid Build Coastguard Worker       if (attr.name) {
223*d57664e9SAndroid Build Coastguard Worker         const ResourceName& name = attr.name.value();
224*d57664e9SAndroid Build Coastguard Worker         if (!name.package.empty() && name.package != package_) {
225*d57664e9SAndroid Build Coastguard Worker           printer_->Print(name.package);
226*d57664e9SAndroid Build Coastguard Worker           printer_->Print(":");
227*d57664e9SAndroid Build Coastguard Worker         }
228*d57664e9SAndroid Build Coastguard Worker         printer_->Print(name.entry);
229*d57664e9SAndroid Build Coastguard Worker 
230*d57664e9SAndroid Build Coastguard Worker         if (attr.id) {
231*d57664e9SAndroid Build Coastguard Worker           printer_->Print("(");
232*d57664e9SAndroid Build Coastguard Worker           printer_->Print(attr.id.value().to_string());
233*d57664e9SAndroid Build Coastguard Worker           printer_->Print(")");
234*d57664e9SAndroid Build Coastguard Worker         }
235*d57664e9SAndroid Build Coastguard Worker       }
236*d57664e9SAndroid Build Coastguard Worker 
237*d57664e9SAndroid Build Coastguard Worker       if (attr.id) {
238*d57664e9SAndroid Build Coastguard Worker         printer_->Print(attr.id.value().to_string());
239*d57664e9SAndroid Build Coastguard Worker       }
240*d57664e9SAndroid Build Coastguard Worker       printer_->Println();
241*d57664e9SAndroid Build Coastguard Worker     }
242*d57664e9SAndroid Build Coastguard Worker   }
243*d57664e9SAndroid Build Coastguard Worker 
VisitItem(const Item * item)244*d57664e9SAndroid Build Coastguard Worker   void VisitItem(const Item* item) override {
245*d57664e9SAndroid Build Coastguard Worker     // Intentionally left empty, we already printed the Items.
246*d57664e9SAndroid Build Coastguard Worker   }
247*d57664e9SAndroid Build Coastguard Worker 
248*d57664e9SAndroid Build Coastguard Worker  private:
PrintItem(const Item & item)249*d57664e9SAndroid Build Coastguard Worker   void PrintItem(const Item& item) {
250*d57664e9SAndroid Build Coastguard Worker     if (const Reference* ref = ValueCast<Reference>(&item)) {
251*d57664e9SAndroid Build Coastguard Worker       // Special case Reference so that we can print local resources without a package name.
252*d57664e9SAndroid Build Coastguard Worker       ref->PrettyPrint(package_, printer_);
253*d57664e9SAndroid Build Coastguard Worker     } else {
254*d57664e9SAndroid Build Coastguard Worker       item.PrettyPrint(printer_);
255*d57664e9SAndroid Build Coastguard Worker     }
256*d57664e9SAndroid Build Coastguard Worker   }
257*d57664e9SAndroid Build Coastguard Worker 
258*d57664e9SAndroid Build Coastguard Worker   std::string package_;
259*d57664e9SAndroid Build Coastguard Worker   Printer* printer_;
260*d57664e9SAndroid Build Coastguard Worker };
261*d57664e9SAndroid Build Coastguard Worker 
262*d57664e9SAndroid Build Coastguard Worker }  // namespace
263*d57664e9SAndroid Build Coastguard Worker 
PrintTable(const ResourceTable & table,const DebugPrintTableOptions & options,Printer * printer)264*d57664e9SAndroid Build Coastguard Worker void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
265*d57664e9SAndroid Build Coastguard Worker                        Printer* printer) {
266*d57664e9SAndroid Build Coastguard Worker   const auto table_view = table.GetPartitionedView();
267*d57664e9SAndroid Build Coastguard Worker   for (const auto& package : table_view.packages) {
268*d57664e9SAndroid Build Coastguard Worker     ValueHeadlinePrinter headline_printer(package.name, printer);
269*d57664e9SAndroid Build Coastguard Worker     ValueBodyPrinter body_printer(package.name, printer);
270*d57664e9SAndroid Build Coastguard Worker 
271*d57664e9SAndroid Build Coastguard Worker     auto& dynamicRefTable = table.GetReferencedPackages();
272*d57664e9SAndroid Build Coastguard Worker     if (!dynamicRefTable.empty()) {
273*d57664e9SAndroid Build Coastguard Worker       printer->Println(StringPrintf("DynamicRefTable entryCount=%d", int(dynamicRefTable.size())));
274*d57664e9SAndroid Build Coastguard Worker       printer->Indent();
275*d57664e9SAndroid Build Coastguard Worker       for (auto&& [id, name] : dynamicRefTable) {
276*d57664e9SAndroid Build Coastguard Worker         printer->Println(StringPrintf("0x%02x -> %s", id, name.c_str()));
277*d57664e9SAndroid Build Coastguard Worker       }
278*d57664e9SAndroid Build Coastguard Worker       printer->Undent();
279*d57664e9SAndroid Build Coastguard Worker     }
280*d57664e9SAndroid Build Coastguard Worker 
281*d57664e9SAndroid Build Coastguard Worker     printer->Print("Package name=");
282*d57664e9SAndroid Build Coastguard Worker     printer->Print(package.name);
283*d57664e9SAndroid Build Coastguard Worker     if (package.id) {
284*d57664e9SAndroid Build Coastguard Worker       printer->Print(StringPrintf(" id=%02x", package.id.value()));
285*d57664e9SAndroid Build Coastguard Worker     }
286*d57664e9SAndroid Build Coastguard Worker     printer->Println();
287*d57664e9SAndroid Build Coastguard Worker 
288*d57664e9SAndroid Build Coastguard Worker     printer->Indent();
289*d57664e9SAndroid Build Coastguard Worker     for (const auto& type : package.types) {
290*d57664e9SAndroid Build Coastguard Worker       printer->Print("type ");
291*d57664e9SAndroid Build Coastguard Worker       printer->Print(type.named_type.to_string());
292*d57664e9SAndroid Build Coastguard Worker       if (type.id) {
293*d57664e9SAndroid Build Coastguard Worker         printer->Print(StringPrintf(" id=%02x", type.id.value()));
294*d57664e9SAndroid Build Coastguard Worker       }
295*d57664e9SAndroid Build Coastguard Worker       printer->Println(StringPrintf(" entryCount=%zd", type.entries.size()));
296*d57664e9SAndroid Build Coastguard Worker 
297*d57664e9SAndroid Build Coastguard Worker       printer->Indent();
298*d57664e9SAndroid Build Coastguard Worker       for (const ResourceTableEntryView& entry : type.entries) {
299*d57664e9SAndroid Build Coastguard Worker         printer->Print("resource ");
300*d57664e9SAndroid Build Coastguard Worker         printer->Print(ResourceId(package.id.value_or(0), type.id.value_or(0), entry.id.value_or(0))
301*d57664e9SAndroid Build Coastguard Worker                            .to_string());
302*d57664e9SAndroid Build Coastguard Worker         printer->Print(" ");
303*d57664e9SAndroid Build Coastguard Worker 
304*d57664e9SAndroid Build Coastguard Worker         // Write the name without the package (this is obvious and too verbose).
305*d57664e9SAndroid Build Coastguard Worker         printer->Print(type.named_type.to_string());
306*d57664e9SAndroid Build Coastguard Worker         printer->Print("/");
307*d57664e9SAndroid Build Coastguard Worker         printer->Print(entry.name);
308*d57664e9SAndroid Build Coastguard Worker 
309*d57664e9SAndroid Build Coastguard Worker         switch (entry.visibility.level) {
310*d57664e9SAndroid Build Coastguard Worker           case Visibility::Level::kPublic:
311*d57664e9SAndroid Build Coastguard Worker             printer->Print(" PUBLIC");
312*d57664e9SAndroid Build Coastguard Worker             break;
313*d57664e9SAndroid Build Coastguard Worker           case Visibility::Level::kPrivate:
314*d57664e9SAndroid Build Coastguard Worker             printer->Print(" _PRIVATE_");
315*d57664e9SAndroid Build Coastguard Worker             break;
316*d57664e9SAndroid Build Coastguard Worker           case Visibility::Level::kUndefined:
317*d57664e9SAndroid Build Coastguard Worker             // Print nothing.
318*d57664e9SAndroid Build Coastguard Worker             break;
319*d57664e9SAndroid Build Coastguard Worker         }
320*d57664e9SAndroid Build Coastguard Worker 
321*d57664e9SAndroid Build Coastguard Worker         if (entry.visibility.staged_api) {
322*d57664e9SAndroid Build Coastguard Worker           printer->Print(" STAGED");
323*d57664e9SAndroid Build Coastguard Worker         }
324*d57664e9SAndroid Build Coastguard Worker 
325*d57664e9SAndroid Build Coastguard Worker         if (entry.overlayable_item) {
326*d57664e9SAndroid Build Coastguard Worker           printer->Print(" OVERLAYABLE");
327*d57664e9SAndroid Build Coastguard Worker         }
328*d57664e9SAndroid Build Coastguard Worker 
329*d57664e9SAndroid Build Coastguard Worker         if (entry.staged_id) {
330*d57664e9SAndroid Build Coastguard Worker           printer->Print(" STAGED_ID=");
331*d57664e9SAndroid Build Coastguard Worker           printer->Print(entry.staged_id.value().id.to_string());
332*d57664e9SAndroid Build Coastguard Worker         }
333*d57664e9SAndroid Build Coastguard Worker 
334*d57664e9SAndroid Build Coastguard Worker         printer->Println();
335*d57664e9SAndroid Build Coastguard Worker 
336*d57664e9SAndroid Build Coastguard Worker         if (options.show_values) {
337*d57664e9SAndroid Build Coastguard Worker           printer->Indent();
338*d57664e9SAndroid Build Coastguard Worker           for (const auto& value : entry.values) {
339*d57664e9SAndroid Build Coastguard Worker             printer->Print("(");
340*d57664e9SAndroid Build Coastguard Worker             printer->Print(value->config.to_string());
341*d57664e9SAndroid Build Coastguard Worker             printer->Print(") ");
342*d57664e9SAndroid Build Coastguard Worker             value->value->Accept(&headline_printer);
343*d57664e9SAndroid Build Coastguard Worker             if (options.show_sources && !value->value->GetSource().path.empty()) {
344*d57664e9SAndroid Build Coastguard Worker               printer->Print(" src=");
345*d57664e9SAndroid Build Coastguard Worker               printer->Print(value->value->GetSource().to_string());
346*d57664e9SAndroid Build Coastguard Worker             }
347*d57664e9SAndroid Build Coastguard Worker             printer->Println();
348*d57664e9SAndroid Build Coastguard Worker             printer->Indent();
349*d57664e9SAndroid Build Coastguard Worker             value->value->Accept(&body_printer);
350*d57664e9SAndroid Build Coastguard Worker             printer->Undent();
351*d57664e9SAndroid Build Coastguard Worker           }
352*d57664e9SAndroid Build Coastguard Worker           printer->Println("Flag disabled values:");
353*d57664e9SAndroid Build Coastguard Worker           for (const auto& value : entry.flag_disabled_values) {
354*d57664e9SAndroid Build Coastguard Worker             printer->Print("(");
355*d57664e9SAndroid Build Coastguard Worker             printer->Print(value->config.to_string());
356*d57664e9SAndroid Build Coastguard Worker             printer->Print(") ");
357*d57664e9SAndroid Build Coastguard Worker             value->value->Accept(&headline_printer);
358*d57664e9SAndroid Build Coastguard Worker             if (options.show_sources && !value->value->GetSource().path.empty()) {
359*d57664e9SAndroid Build Coastguard Worker               printer->Print(" src=");
360*d57664e9SAndroid Build Coastguard Worker               printer->Print(value->value->GetSource().to_string());
361*d57664e9SAndroid Build Coastguard Worker             }
362*d57664e9SAndroid Build Coastguard Worker             printer->Println();
363*d57664e9SAndroid Build Coastguard Worker             printer->Indent();
364*d57664e9SAndroid Build Coastguard Worker             value->value->Accept(&body_printer);
365*d57664e9SAndroid Build Coastguard Worker             printer->Undent();
366*d57664e9SAndroid Build Coastguard Worker           }
367*d57664e9SAndroid Build Coastguard Worker           printer->Undent();
368*d57664e9SAndroid Build Coastguard Worker         }
369*d57664e9SAndroid Build Coastguard Worker       }
370*d57664e9SAndroid Build Coastguard Worker       printer->Undent();
371*d57664e9SAndroid Build Coastguard Worker     }
372*d57664e9SAndroid Build Coastguard Worker     printer->Undent();
373*d57664e9SAndroid Build Coastguard Worker   }
374*d57664e9SAndroid Build Coastguard Worker }
375*d57664e9SAndroid Build Coastguard Worker 
GetNodeIndex(const std::vector<ResourceName> & names,const ResourceName & name)376*d57664e9SAndroid Build Coastguard Worker static size_t GetNodeIndex(const std::vector<ResourceName>& names, const ResourceName& name) {
377*d57664e9SAndroid Build Coastguard Worker   auto iter = std::lower_bound(names.begin(), names.end(), name);
378*d57664e9SAndroid Build Coastguard Worker   CHECK(iter != names.end());
379*d57664e9SAndroid Build Coastguard Worker   CHECK(*iter == name);
380*d57664e9SAndroid Build Coastguard Worker   return std::distance(names.begin(), iter);
381*d57664e9SAndroid Build Coastguard Worker }
382*d57664e9SAndroid Build Coastguard Worker 
PrintStyleGraph(ResourceTable * table,const ResourceName & target_style)383*d57664e9SAndroid Build Coastguard Worker void Debug::PrintStyleGraph(ResourceTable* table, const ResourceName& target_style) {
384*d57664e9SAndroid Build Coastguard Worker   std::map<ResourceName, std::set<ResourceName>> graph;
385*d57664e9SAndroid Build Coastguard Worker 
386*d57664e9SAndroid Build Coastguard Worker   std::queue<ResourceName> styles_to_visit;
387*d57664e9SAndroid Build Coastguard Worker   styles_to_visit.push(target_style);
388*d57664e9SAndroid Build Coastguard Worker   for (; !styles_to_visit.empty(); styles_to_visit.pop()) {
389*d57664e9SAndroid Build Coastguard Worker     const ResourceName& style_name = styles_to_visit.front();
390*d57664e9SAndroid Build Coastguard Worker     std::set<ResourceName>& parents = graph[style_name];
391*d57664e9SAndroid Build Coastguard Worker     if (!parents.empty()) {
392*d57664e9SAndroid Build Coastguard Worker       // We've already visited this style.
393*d57664e9SAndroid Build Coastguard Worker       continue;
394*d57664e9SAndroid Build Coastguard Worker     }
395*d57664e9SAndroid Build Coastguard Worker 
396*d57664e9SAndroid Build Coastguard Worker     std::optional<ResourceTable::SearchResult> result = table->FindResource(style_name);
397*d57664e9SAndroid Build Coastguard Worker     if (result) {
398*d57664e9SAndroid Build Coastguard Worker       ResourceEntry* entry = result.value().entry;
399*d57664e9SAndroid Build Coastguard Worker       for (const auto& value : entry->values) {
400*d57664e9SAndroid Build Coastguard Worker         if (Style* style = ValueCast<Style>(value->value.get())) {
401*d57664e9SAndroid Build Coastguard Worker           if (style->parent && style->parent.value().name) {
402*d57664e9SAndroid Build Coastguard Worker             parents.insert(style->parent.value().name.value());
403*d57664e9SAndroid Build Coastguard Worker             styles_to_visit.push(style->parent.value().name.value());
404*d57664e9SAndroid Build Coastguard Worker           }
405*d57664e9SAndroid Build Coastguard Worker         }
406*d57664e9SAndroid Build Coastguard Worker       }
407*d57664e9SAndroid Build Coastguard Worker     }
408*d57664e9SAndroid Build Coastguard Worker   }
409*d57664e9SAndroid Build Coastguard Worker 
410*d57664e9SAndroid Build Coastguard Worker   std::vector<ResourceName> names;
411*d57664e9SAndroid Build Coastguard Worker   for (const auto& entry : graph) {
412*d57664e9SAndroid Build Coastguard Worker     names.push_back(entry.first);
413*d57664e9SAndroid Build Coastguard Worker   }
414*d57664e9SAndroid Build Coastguard Worker 
415*d57664e9SAndroid Build Coastguard Worker   std::cout << "digraph styles {\n";
416*d57664e9SAndroid Build Coastguard Worker   for (const auto& name : names) {
417*d57664e9SAndroid Build Coastguard Worker     std::cout << "  node_" << GetNodeIndex(names, name) << " [label=\"" << name << "\"];\n";
418*d57664e9SAndroid Build Coastguard Worker   }
419*d57664e9SAndroid Build Coastguard Worker 
420*d57664e9SAndroid Build Coastguard Worker   for (const auto& entry : graph) {
421*d57664e9SAndroid Build Coastguard Worker     const ResourceName& style_name = entry.first;
422*d57664e9SAndroid Build Coastguard Worker     size_t style_node_index = GetNodeIndex(names, style_name);
423*d57664e9SAndroid Build Coastguard Worker 
424*d57664e9SAndroid Build Coastguard Worker     for (const auto& parent_name : entry.second) {
425*d57664e9SAndroid Build Coastguard Worker       std::cout << "  node_" << style_node_index << " -> "
426*d57664e9SAndroid Build Coastguard Worker                 << "node_" << GetNodeIndex(names, parent_name) << ";\n";
427*d57664e9SAndroid Build Coastguard Worker     }
428*d57664e9SAndroid Build Coastguard Worker   }
429*d57664e9SAndroid Build Coastguard Worker 
430*d57664e9SAndroid Build Coastguard Worker   std::cout << "}" << std::endl;
431*d57664e9SAndroid Build Coastguard Worker }
432*d57664e9SAndroid Build Coastguard Worker 
DumpHex(const void * data,size_t len)433*d57664e9SAndroid Build Coastguard Worker void Debug::DumpHex(const void* data, size_t len) {
434*d57664e9SAndroid Build Coastguard Worker   const uint8_t* d = (const uint8_t*)data;
435*d57664e9SAndroid Build Coastguard Worker   for (size_t i = 0; i < len; i++) {
436*d57664e9SAndroid Build Coastguard Worker     std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)d[i] << " ";
437*d57664e9SAndroid Build Coastguard Worker     if (i % 8 == 7) {
438*d57664e9SAndroid Build Coastguard Worker       std::cerr << "\n";
439*d57664e9SAndroid Build Coastguard Worker     }
440*d57664e9SAndroid Build Coastguard Worker   }
441*d57664e9SAndroid Build Coastguard Worker 
442*d57664e9SAndroid Build Coastguard Worker   if (len - 1 % 8 != 7) {
443*d57664e9SAndroid Build Coastguard Worker     std::cerr << std::endl;
444*d57664e9SAndroid Build Coastguard Worker   }
445*d57664e9SAndroid Build Coastguard Worker }
446*d57664e9SAndroid Build Coastguard Worker 
DumpResStringPool(const android::ResStringPool * pool,text::Printer * printer)447*d57664e9SAndroid Build Coastguard Worker void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer) {
448*d57664e9SAndroid Build Coastguard Worker   using namespace android;
449*d57664e9SAndroid Build Coastguard Worker 
450*d57664e9SAndroid Build Coastguard Worker   if (pool->getError() == NO_INIT) {
451*d57664e9SAndroid Build Coastguard Worker     printer->Print("String pool is uninitialized.\n");
452*d57664e9SAndroid Build Coastguard Worker     return;
453*d57664e9SAndroid Build Coastguard Worker   } else if (pool->getError() != NO_ERROR) {
454*d57664e9SAndroid Build Coastguard Worker     printer->Print("String pool is corrupt/invalid.\n");
455*d57664e9SAndroid Build Coastguard Worker     return;
456*d57664e9SAndroid Build Coastguard Worker   }
457*d57664e9SAndroid Build Coastguard Worker 
458*d57664e9SAndroid Build Coastguard Worker   SortedVector<const void*> uniqueStrings;
459*d57664e9SAndroid Build Coastguard Worker   const size_t N = pool->size();
460*d57664e9SAndroid Build Coastguard Worker   for (size_t i=0; i<N; i++) {
461*d57664e9SAndroid Build Coastguard Worker     size_t len;
462*d57664e9SAndroid Build Coastguard Worker     if (pool->isUTF8()) {
463*d57664e9SAndroid Build Coastguard Worker       uniqueStrings.add(UnpackOptionalString(pool->string8At(i), &len));
464*d57664e9SAndroid Build Coastguard Worker     } else {
465*d57664e9SAndroid Build Coastguard Worker       uniqueStrings.add(UnpackOptionalString(pool->stringAt(i), &len));
466*d57664e9SAndroid Build Coastguard Worker     }
467*d57664e9SAndroid Build Coastguard Worker   }
468*d57664e9SAndroid Build Coastguard Worker 
469*d57664e9SAndroid Build Coastguard Worker   printer->Print(StringPrintf("String pool of %zd unique %s %s strings, %zd entries and %zd styles "
470*d57664e9SAndroid Build Coastguard Worker                               "using %zd bytes:\n", uniqueStrings.size(),
471*d57664e9SAndroid Build Coastguard Worker                               pool->isUTF8() ? "UTF-8" : "UTF-16",
472*d57664e9SAndroid Build Coastguard Worker                               pool->isSorted() ? "sorted" : "non-sorted", N, pool->styleCount(),
473*d57664e9SAndroid Build Coastguard Worker                               pool->bytes()));
474*d57664e9SAndroid Build Coastguard Worker 
475*d57664e9SAndroid Build Coastguard Worker   const size_t NS = pool->size();
476*d57664e9SAndroid Build Coastguard Worker   for (size_t s=0; s<NS; s++) {
477*d57664e9SAndroid Build Coastguard Worker     auto str = pool->string8ObjectAt(s);
478*d57664e9SAndroid Build Coastguard Worker     printer->Print(StringPrintf("String #%zd : %s\n", s, str.has_value() ? str->c_str() : ""));
479*d57664e9SAndroid Build Coastguard Worker   }
480*d57664e9SAndroid Build Coastguard Worker }
481*d57664e9SAndroid Build Coastguard Worker 
482*d57664e9SAndroid Build Coastguard Worker namespace {
483*d57664e9SAndroid Build Coastguard Worker 
484*d57664e9SAndroid Build Coastguard Worker class XmlPrinter : public xml::ConstVisitor {
485*d57664e9SAndroid Build Coastguard Worker  public:
486*d57664e9SAndroid Build Coastguard Worker   using xml::ConstVisitor::Visit;
487*d57664e9SAndroid Build Coastguard Worker 
XmlPrinter(Printer * printer)488*d57664e9SAndroid Build Coastguard Worker   explicit XmlPrinter(Printer* printer) : printer_(printer) {
489*d57664e9SAndroid Build Coastguard Worker   }
490*d57664e9SAndroid Build Coastguard Worker 
Visit(const xml::Element * el)491*d57664e9SAndroid Build Coastguard Worker   void Visit(const xml::Element* el) override {
492*d57664e9SAndroid Build Coastguard Worker     for (const xml::NamespaceDecl& decl : el->namespace_decls) {
493*d57664e9SAndroid Build Coastguard Worker       printer_->Println(StringPrintf("N: %s=%s (line=%zu)", decl.prefix.c_str(), decl.uri.c_str(),
494*d57664e9SAndroid Build Coastguard Worker                                      decl.line_number));
495*d57664e9SAndroid Build Coastguard Worker       printer_->Indent();
496*d57664e9SAndroid Build Coastguard Worker     }
497*d57664e9SAndroid Build Coastguard Worker 
498*d57664e9SAndroid Build Coastguard Worker     printer_->Print("E: ");
499*d57664e9SAndroid Build Coastguard Worker     if (!el->namespace_uri.empty()) {
500*d57664e9SAndroid Build Coastguard Worker       printer_->Print(el->namespace_uri);
501*d57664e9SAndroid Build Coastguard Worker       printer_->Print(":");
502*d57664e9SAndroid Build Coastguard Worker     }
503*d57664e9SAndroid Build Coastguard Worker     printer_->Println(StringPrintf("%s (line=%zu)", el->name.c_str(), el->line_number));
504*d57664e9SAndroid Build Coastguard Worker     printer_->Indent();
505*d57664e9SAndroid Build Coastguard Worker 
506*d57664e9SAndroid Build Coastguard Worker     for (const xml::Attribute& attr : el->attributes) {
507*d57664e9SAndroid Build Coastguard Worker       printer_->Print("A: ");
508*d57664e9SAndroid Build Coastguard Worker       if (!attr.namespace_uri.empty()) {
509*d57664e9SAndroid Build Coastguard Worker         printer_->Print(attr.namespace_uri);
510*d57664e9SAndroid Build Coastguard Worker         printer_->Print(":");
511*d57664e9SAndroid Build Coastguard Worker       }
512*d57664e9SAndroid Build Coastguard Worker       printer_->Print(attr.name);
513*d57664e9SAndroid Build Coastguard Worker 
514*d57664e9SAndroid Build Coastguard Worker       if (attr.compiled_attribute) {
515*d57664e9SAndroid Build Coastguard Worker         printer_->Print("(");
516*d57664e9SAndroid Build Coastguard Worker         printer_->Print(attr.compiled_attribute.value().id.value_or(ResourceId(0)).to_string());
517*d57664e9SAndroid Build Coastguard Worker         printer_->Print(")");
518*d57664e9SAndroid Build Coastguard Worker       }
519*d57664e9SAndroid Build Coastguard Worker       printer_->Print("=");
520*d57664e9SAndroid Build Coastguard Worker       if (attr.compiled_value != nullptr) {
521*d57664e9SAndroid Build Coastguard Worker         attr.compiled_value->PrettyPrint(printer_);
522*d57664e9SAndroid Build Coastguard Worker       } else {
523*d57664e9SAndroid Build Coastguard Worker         printer_->Print("\"");
524*d57664e9SAndroid Build Coastguard Worker         printer_->Print(attr.value);
525*d57664e9SAndroid Build Coastguard Worker         printer_->Print("\"");
526*d57664e9SAndroid Build Coastguard Worker       }
527*d57664e9SAndroid Build Coastguard Worker 
528*d57664e9SAndroid Build Coastguard Worker       if (!attr.value.empty()) {
529*d57664e9SAndroid Build Coastguard Worker         printer_->Print(" (Raw: \"");
530*d57664e9SAndroid Build Coastguard Worker         printer_->Print(attr.value);
531*d57664e9SAndroid Build Coastguard Worker         printer_->Print("\")");
532*d57664e9SAndroid Build Coastguard Worker       }
533*d57664e9SAndroid Build Coastguard Worker       printer_->Println();
534*d57664e9SAndroid Build Coastguard Worker     }
535*d57664e9SAndroid Build Coastguard Worker 
536*d57664e9SAndroid Build Coastguard Worker     printer_->Indent();
537*d57664e9SAndroid Build Coastguard Worker     xml::ConstVisitor::Visit(el);
538*d57664e9SAndroid Build Coastguard Worker     printer_->Undent();
539*d57664e9SAndroid Build Coastguard Worker     printer_->Undent();
540*d57664e9SAndroid Build Coastguard Worker 
541*d57664e9SAndroid Build Coastguard Worker     for (size_t i = 0; i < el->namespace_decls.size(); i++) {
542*d57664e9SAndroid Build Coastguard Worker       printer_->Undent();
543*d57664e9SAndroid Build Coastguard Worker     }
544*d57664e9SAndroid Build Coastguard Worker   }
545*d57664e9SAndroid Build Coastguard Worker 
Visit(const xml::Text * text)546*d57664e9SAndroid Build Coastguard Worker   void Visit(const xml::Text* text) override {
547*d57664e9SAndroid Build Coastguard Worker     printer_->Println(
548*d57664e9SAndroid Build Coastguard Worker         StringPrintf("T: '%s'", android::ResTable::normalizeForOutput(text->text.c_str()).c_str()));
549*d57664e9SAndroid Build Coastguard Worker   }
550*d57664e9SAndroid Build Coastguard Worker 
551*d57664e9SAndroid Build Coastguard Worker  private:
552*d57664e9SAndroid Build Coastguard Worker   Printer* printer_;
553*d57664e9SAndroid Build Coastguard Worker };
554*d57664e9SAndroid Build Coastguard Worker 
555*d57664e9SAndroid Build Coastguard Worker }  // namespace
556*d57664e9SAndroid Build Coastguard Worker 
DumpXml(const xml::XmlResource & doc,Printer * printer)557*d57664e9SAndroid Build Coastguard Worker void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) {
558*d57664e9SAndroid Build Coastguard Worker   XmlPrinter xml_visitor(printer);
559*d57664e9SAndroid Build Coastguard Worker   doc.root->Accept(&xml_visitor);
560*d57664e9SAndroid Build Coastguard Worker }
561*d57664e9SAndroid Build Coastguard Worker 
562*d57664e9SAndroid Build Coastguard Worker struct DumpOverlayableEntry {
563*d57664e9SAndroid Build Coastguard Worker   std::string overlayable_section;
564*d57664e9SAndroid Build Coastguard Worker   std::string policy_subsection;
565*d57664e9SAndroid Build Coastguard Worker   std::string resource_name;
566*d57664e9SAndroid Build Coastguard Worker };
567*d57664e9SAndroid Build Coastguard Worker 
DumpOverlayable(const ResourceTable & table,text::Printer * printer)568*d57664e9SAndroid Build Coastguard Worker void Debug::DumpOverlayable(const ResourceTable& table, text::Printer* printer) {
569*d57664e9SAndroid Build Coastguard Worker   std::vector<DumpOverlayableEntry> items;
570*d57664e9SAndroid Build Coastguard Worker   for (const auto& package : table.packages) {
571*d57664e9SAndroid Build Coastguard Worker     for (const auto& type : package->types) {
572*d57664e9SAndroid Build Coastguard Worker       for (const auto& entry : type->entries) {
573*d57664e9SAndroid Build Coastguard Worker         if (entry->overlayable_item) {
574*d57664e9SAndroid Build Coastguard Worker           const auto& overlayable_item = entry->overlayable_item.value();
575*d57664e9SAndroid Build Coastguard Worker           const auto overlayable_section = StringPrintf(R"(name="%s" actor="%s")",
576*d57664e9SAndroid Build Coastguard Worker               overlayable_item.overlayable->name.c_str(),
577*d57664e9SAndroid Build Coastguard Worker               overlayable_item.overlayable->actor.c_str());
578*d57664e9SAndroid Build Coastguard Worker           const auto policy_subsection = StringPrintf(R"(policies="%s")",
579*d57664e9SAndroid Build Coastguard Worker               android::idmap2::policy::PoliciesToDebugString(overlayable_item.policies).c_str());
580*d57664e9SAndroid Build Coastguard Worker           const auto value =
581*d57664e9SAndroid Build Coastguard Worker               StringPrintf("%s/%s", type->named_type.to_string().data(), entry->name.c_str());
582*d57664e9SAndroid Build Coastguard Worker           items.push_back(DumpOverlayableEntry{overlayable_section, policy_subsection, value});
583*d57664e9SAndroid Build Coastguard Worker         }
584*d57664e9SAndroid Build Coastguard Worker       }
585*d57664e9SAndroid Build Coastguard Worker     }
586*d57664e9SAndroid Build Coastguard Worker   }
587*d57664e9SAndroid Build Coastguard Worker 
588*d57664e9SAndroid Build Coastguard Worker   std::sort(items.begin(), items.end(),
589*d57664e9SAndroid Build Coastguard Worker       [](const DumpOverlayableEntry& a, const DumpOverlayableEntry& b) {
590*d57664e9SAndroid Build Coastguard Worker         if (a.overlayable_section != b.overlayable_section) {
591*d57664e9SAndroid Build Coastguard Worker           return a.overlayable_section < b.overlayable_section;
592*d57664e9SAndroid Build Coastguard Worker         }
593*d57664e9SAndroid Build Coastguard Worker         if (a.policy_subsection != b.policy_subsection) {
594*d57664e9SAndroid Build Coastguard Worker           return a.policy_subsection < b.policy_subsection;
595*d57664e9SAndroid Build Coastguard Worker         }
596*d57664e9SAndroid Build Coastguard Worker         return a.resource_name < b.resource_name;
597*d57664e9SAndroid Build Coastguard Worker       });
598*d57664e9SAndroid Build Coastguard Worker 
599*d57664e9SAndroid Build Coastguard Worker   std::string last_overlayable_section;
600*d57664e9SAndroid Build Coastguard Worker   std::string last_policy_subsection;
601*d57664e9SAndroid Build Coastguard Worker   for (const auto& item : items) {
602*d57664e9SAndroid Build Coastguard Worker     if (last_overlayable_section != item.overlayable_section) {
603*d57664e9SAndroid Build Coastguard Worker       printer->Println(item.overlayable_section);
604*d57664e9SAndroid Build Coastguard Worker       last_overlayable_section = item.overlayable_section;
605*d57664e9SAndroid Build Coastguard Worker     }
606*d57664e9SAndroid Build Coastguard Worker     if (last_policy_subsection != item.policy_subsection) {
607*d57664e9SAndroid Build Coastguard Worker       printer->Indent();
608*d57664e9SAndroid Build Coastguard Worker       printer->Println(item.policy_subsection);
609*d57664e9SAndroid Build Coastguard Worker       last_policy_subsection = item.policy_subsection;
610*d57664e9SAndroid Build Coastguard Worker       printer->Undent();
611*d57664e9SAndroid Build Coastguard Worker     }
612*d57664e9SAndroid Build Coastguard Worker     printer->Indent();
613*d57664e9SAndroid Build Coastguard Worker     printer->Indent();
614*d57664e9SAndroid Build Coastguard Worker     printer->Println(item.resource_name);
615*d57664e9SAndroid Build Coastguard Worker     printer->Undent();
616*d57664e9SAndroid Build Coastguard Worker     printer->Undent();
617*d57664e9SAndroid Build Coastguard Worker   }
618*d57664e9SAndroid Build Coastguard Worker }
619*d57664e9SAndroid Build Coastguard Worker 
620*d57664e9SAndroid Build Coastguard Worker namespace {
621*d57664e9SAndroid Build Coastguard Worker 
622*d57664e9SAndroid Build Coastguard Worker using namespace android;
623*d57664e9SAndroid Build Coastguard Worker 
624*d57664e9SAndroid Build Coastguard Worker class ChunkPrinter {
625*d57664e9SAndroid Build Coastguard Worker  public:
ChunkPrinter(const void * data,size_t len,Printer * printer,android::IDiagnostics * diag)626*d57664e9SAndroid Build Coastguard Worker   ChunkPrinter(const void* data, size_t len, Printer* printer, android::IDiagnostics* diag)
627*d57664e9SAndroid Build Coastguard Worker       : data_(data), data_len_(len), printer_(printer), diag_(diag) {
628*d57664e9SAndroid Build Coastguard Worker   }
629*d57664e9SAndroid Build Coastguard Worker 
PrintChunkHeader(const ResChunk_header * chunk)630*d57664e9SAndroid Build Coastguard Worker   void PrintChunkHeader(const ResChunk_header* chunk) {
631*d57664e9SAndroid Build Coastguard Worker     switch (android::util::DeviceToHost16(chunk->type)) {
632*d57664e9SAndroid Build Coastguard Worker       case RES_STRING_POOL_TYPE:
633*d57664e9SAndroid Build Coastguard Worker         printer_->Print("[RES_STRING_POOL_TYPE]");
634*d57664e9SAndroid Build Coastguard Worker         break;
635*d57664e9SAndroid Build Coastguard Worker       case RES_TABLE_LIBRARY_TYPE:
636*d57664e9SAndroid Build Coastguard Worker         printer_->Print("[RES_TABLE_LIBRARY_TYPE]");
637*d57664e9SAndroid Build Coastguard Worker         break;
638*d57664e9SAndroid Build Coastguard Worker       case RES_TABLE_TYPE:
639*d57664e9SAndroid Build Coastguard Worker         printer_->Print("[ResTable_header]");
640*d57664e9SAndroid Build Coastguard Worker         break;
641*d57664e9SAndroid Build Coastguard Worker       case RES_TABLE_PACKAGE_TYPE:
642*d57664e9SAndroid Build Coastguard Worker         printer_->Print("[ResTable_package]");
643*d57664e9SAndroid Build Coastguard Worker         break;
644*d57664e9SAndroid Build Coastguard Worker       case RES_TABLE_TYPE_TYPE:
645*d57664e9SAndroid Build Coastguard Worker         printer_->Print("[ResTable_type]");
646*d57664e9SAndroid Build Coastguard Worker         break;
647*d57664e9SAndroid Build Coastguard Worker       case RES_TABLE_TYPE_SPEC_TYPE:
648*d57664e9SAndroid Build Coastguard Worker         printer_->Print("[RES_TABLE_TYPE_SPEC_TYPE]");
649*d57664e9SAndroid Build Coastguard Worker         break;
650*d57664e9SAndroid Build Coastguard Worker       default:
651*d57664e9SAndroid Build Coastguard Worker         break;
652*d57664e9SAndroid Build Coastguard Worker     }
653*d57664e9SAndroid Build Coastguard Worker 
654*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(" chunkSize: %u", android::util::DeviceToHost32(chunk->size)));
655*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
656*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" headerSize: %u", android::util::DeviceToHost32(chunk->headerSize)));
657*d57664e9SAndroid Build Coastguard Worker   }
658*d57664e9SAndroid Build Coastguard Worker 
PrintTable(const ResTable_header * chunk)659*d57664e9SAndroid Build Coastguard Worker   bool PrintTable(const ResTable_header* chunk) {
660*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
661*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" Package count: %u\n", android::util::DeviceToHost32(chunk->packageCount)));
662*d57664e9SAndroid Build Coastguard Worker 
663*d57664e9SAndroid Build Coastguard Worker     // Print the chunks contained within the table
664*d57664e9SAndroid Build Coastguard Worker     printer_->Indent();
665*d57664e9SAndroid Build Coastguard Worker     bool success = PrintChunk(
666*d57664e9SAndroid Build Coastguard Worker         ResChunkPullParser(GetChunkData(&chunk->header), GetChunkDataLen(&chunk->header)));
667*d57664e9SAndroid Build Coastguard Worker     printer_->Undent();
668*d57664e9SAndroid Build Coastguard Worker     return success;
669*d57664e9SAndroid Build Coastguard Worker   }
670*d57664e9SAndroid Build Coastguard Worker 
PrintResValue(const Res_value * value,const ConfigDescription & config,const ResourceType * type)671*d57664e9SAndroid Build Coastguard Worker   void PrintResValue(const Res_value* value, const ConfigDescription& config,
672*d57664e9SAndroid Build Coastguard Worker                      const ResourceType* type) {
673*d57664e9SAndroid Build Coastguard Worker     printer_->Print("[Res_value]");
674*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(" size: %u", android::util::DeviceToHost32(value->size)));
675*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
676*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" dataType: 0x%02x", android::util::DeviceToHost32(value->dataType)));
677*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(" data: 0x%08x", android::util::DeviceToHost32(value->data)));
678*d57664e9SAndroid Build Coastguard Worker 
679*d57664e9SAndroid Build Coastguard Worker     if (type) {
680*d57664e9SAndroid Build Coastguard Worker       auto item =
681*d57664e9SAndroid Build Coastguard Worker           ResourceUtils::ParseBinaryResValue(*type, config, value_pool_, *value, &out_pool_);
682*d57664e9SAndroid Build Coastguard Worker       printer_->Print(" (");
683*d57664e9SAndroid Build Coastguard Worker       item->PrettyPrint(printer_);
684*d57664e9SAndroid Build Coastguard Worker       printer_->Print(")");
685*d57664e9SAndroid Build Coastguard Worker     }
686*d57664e9SAndroid Build Coastguard Worker 
687*d57664e9SAndroid Build Coastguard Worker     printer_->Print("\n");
688*d57664e9SAndroid Build Coastguard Worker   }
689*d57664e9SAndroid Build Coastguard Worker 
PrintQualifiers(uint32_t qualifiers) const690*d57664e9SAndroid Build Coastguard Worker   void PrintQualifiers(uint32_t qualifiers) const {
691*d57664e9SAndroid Build Coastguard Worker     if (qualifiers == 0) {
692*d57664e9SAndroid Build Coastguard Worker       printer_->Print("0");
693*d57664e9SAndroid Build Coastguard Worker       return;
694*d57664e9SAndroid Build Coastguard Worker     }
695*d57664e9SAndroid Build Coastguard Worker 
696*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf("0x%04x: ", qualifiers));
697*d57664e9SAndroid Build Coastguard Worker     static constinit std::array kValues = {
698*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_MCC, "mcc"},
699*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_MNC, "mnc"},
700*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_LOCALE, "locale"},
701*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_TOUCHSCREEN, "touchscreen"},
702*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_KEYBOARD, "keyboard"},
703*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_KEYBOARD_HIDDEN, "keyboard_hidden"},
704*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_NAVIGATION, "navigation"},
705*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_ORIENTATION, "orientation"},
706*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_DENSITY, "screen_density"},
707*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_SCREEN_SIZE, "screen_size"},
708*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE, "screen_smallest_size"},
709*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_VERSION, "version"},
710*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_SCREEN_LAYOUT, "screen_layout"},
711*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_UI_MODE, "ui_mode"},
712*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_LAYOUTDIR, "layout_dir"},
713*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_SCREEN_ROUND, "screen_round"},
714*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_COLOR_MODE, "color_mode"},
715*d57664e9SAndroid Build Coastguard Worker         std::pair{ResTable_config::CONFIG_GRAMMATICAL_GENDER, "grammatical_gender"}};
716*d57664e9SAndroid Build Coastguard Worker     const char* delimiter = "";
717*d57664e9SAndroid Build Coastguard Worker     for (auto&& pair : kValues) {
718*d57664e9SAndroid Build Coastguard Worker       if (qualifiers & pair.first) {
719*d57664e9SAndroid Build Coastguard Worker         printer_->Print(StringPrintf("%s%s", delimiter, pair.second));
720*d57664e9SAndroid Build Coastguard Worker         delimiter = "|";
721*d57664e9SAndroid Build Coastguard Worker       }
722*d57664e9SAndroid Build Coastguard Worker     }
723*d57664e9SAndroid Build Coastguard Worker   }
724*d57664e9SAndroid Build Coastguard Worker 
PrintTypeSpec(const ResTable_typeSpec * chunk) const725*d57664e9SAndroid Build Coastguard Worker   bool PrintTypeSpec(const ResTable_typeSpec* chunk) const {
726*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
727*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(" types: %u", android::util::DeviceToHost16(chunk->typesCount)));
728*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
729*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" entry configs: %u\n", android::util::DeviceToHost32(chunk->entryCount)));
730*d57664e9SAndroid Build Coastguard Worker     printer_->Print("Entry qualifier masks:\n");
731*d57664e9SAndroid Build Coastguard Worker     printer_->Indent();
732*d57664e9SAndroid Build Coastguard Worker     std::span<const uint32_t> masks(reinterpret_cast<const uint32_t*>(GetChunkData(&chunk->header)),
733*d57664e9SAndroid Build Coastguard Worker                                     GetChunkDataLen(&chunk->header) / sizeof(uint32_t));
734*d57664e9SAndroid Build Coastguard Worker     int i = 0;
735*d57664e9SAndroid Build Coastguard Worker     int non_empty_count = 0;
736*d57664e9SAndroid Build Coastguard Worker     for (auto dev_mask : masks) {
737*d57664e9SAndroid Build Coastguard Worker       auto mask = android::util::DeviceToHost32(dev_mask);
738*d57664e9SAndroid Build Coastguard Worker       if (mask == 0) {
739*d57664e9SAndroid Build Coastguard Worker         i++;
740*d57664e9SAndroid Build Coastguard Worker         continue;
741*d57664e9SAndroid Build Coastguard Worker       }
742*d57664e9SAndroid Build Coastguard Worker       ++non_empty_count;
743*d57664e9SAndroid Build Coastguard Worker       printer_->Print(StringPrintf("#0x%02x = ", i++));
744*d57664e9SAndroid Build Coastguard Worker       if (mask & ResTable_typeSpec::SPEC_PUBLIC) {
745*d57664e9SAndroid Build Coastguard Worker         mask &= ~ResTable_typeSpec::SPEC_PUBLIC;
746*d57664e9SAndroid Build Coastguard Worker         printer_->Print("(PUBLIC) ");
747*d57664e9SAndroid Build Coastguard Worker       }
748*d57664e9SAndroid Build Coastguard Worker       if (mask & ResTable_typeSpec::SPEC_STAGED_API) {
749*d57664e9SAndroid Build Coastguard Worker         mask &= ~ResTable_typeSpec::SPEC_STAGED_API;
750*d57664e9SAndroid Build Coastguard Worker         printer_->Print("(STAGED) ");
751*d57664e9SAndroid Build Coastguard Worker       }
752*d57664e9SAndroid Build Coastguard Worker       PrintQualifiers(mask);
753*d57664e9SAndroid Build Coastguard Worker       printer_->Print("\n");
754*d57664e9SAndroid Build Coastguard Worker     }
755*d57664e9SAndroid Build Coastguard Worker     if (non_empty_count > 0) {
756*d57664e9SAndroid Build Coastguard Worker       printer_->Print("\n");
757*d57664e9SAndroid Build Coastguard Worker     } else {
758*d57664e9SAndroid Build Coastguard Worker       printer_->Print("(all empty)\n");
759*d57664e9SAndroid Build Coastguard Worker     }
760*d57664e9SAndroid Build Coastguard Worker     printer_->Undent();
761*d57664e9SAndroid Build Coastguard Worker     return true;
762*d57664e9SAndroid Build Coastguard Worker   }
763*d57664e9SAndroid Build Coastguard Worker 
PrintTableType(const ResTable_type * chunk)764*d57664e9SAndroid Build Coastguard Worker   bool PrintTableType(const ResTable_type* chunk) {
765*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
766*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(
767*d57664e9SAndroid Build Coastguard Worker         " name: %s",
768*d57664e9SAndroid Build Coastguard Worker         android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1)
769*d57664e9SAndroid Build Coastguard Worker             .c_str()));
770*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(" flags: 0x%02x", android::util::DeviceToHost32(chunk->flags)));
771*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
772*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" entryCount: %u", android::util::DeviceToHost32(chunk->entryCount)));
773*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
774*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" entryStart: %u", android::util::DeviceToHost32(chunk->entriesStart)));
775*d57664e9SAndroid Build Coastguard Worker 
776*d57664e9SAndroid Build Coastguard Worker     ConfigDescription config;
777*d57664e9SAndroid Build Coastguard Worker     config.copyFromDtoH(chunk->config);
778*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(" config: %s\n", config.to_string().c_str()));
779*d57664e9SAndroid Build Coastguard Worker 
780*d57664e9SAndroid Build Coastguard Worker     const ResourceType* type = ParseResourceType(
781*d57664e9SAndroid Build Coastguard Worker         android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1));
782*d57664e9SAndroid Build Coastguard Worker 
783*d57664e9SAndroid Build Coastguard Worker     printer_->Indent();
784*d57664e9SAndroid Build Coastguard Worker 
785*d57664e9SAndroid Build Coastguard Worker     TypeVariant tv(chunk);
786*d57664e9SAndroid Build Coastguard Worker     for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
787*d57664e9SAndroid Build Coastguard Worker       const ResTable_entry* entry = *it;
788*d57664e9SAndroid Build Coastguard Worker       if (!entry) {
789*d57664e9SAndroid Build Coastguard Worker         continue;
790*d57664e9SAndroid Build Coastguard Worker       }
791*d57664e9SAndroid Build Coastguard Worker 
792*d57664e9SAndroid Build Coastguard Worker       if (entry->is_complex()) {
793*d57664e9SAndroid Build Coastguard Worker         printer_->Print("[ResTable_map_entry]");
794*d57664e9SAndroid Build Coastguard Worker       } else if (entry->is_compact()) {
795*d57664e9SAndroid Build Coastguard Worker         printer_->Print("[ResTable_entry_compact]");
796*d57664e9SAndroid Build Coastguard Worker       } else {
797*d57664e9SAndroid Build Coastguard Worker         printer_->Print("[ResTable_entry]");
798*d57664e9SAndroid Build Coastguard Worker       }
799*d57664e9SAndroid Build Coastguard Worker 
800*d57664e9SAndroid Build Coastguard Worker       printer_->Print(StringPrintf(" id: 0x%04x", it.index()));
801*d57664e9SAndroid Build Coastguard Worker       printer_->Print(StringPrintf(
802*d57664e9SAndroid Build Coastguard Worker           " name: %s", android::util::GetString(key_pool_, entry->key()).c_str()));
803*d57664e9SAndroid Build Coastguard Worker       printer_->Print(StringPrintf(" keyIndex: %u", entry->key()));
804*d57664e9SAndroid Build Coastguard Worker       printer_->Print(StringPrintf(" size: %zu", entry->size()));
805*d57664e9SAndroid Build Coastguard Worker       printer_->Print(StringPrintf(" flags: 0x%04x", entry->flags()));
806*d57664e9SAndroid Build Coastguard Worker 
807*d57664e9SAndroid Build Coastguard Worker       printer_->Indent();
808*d57664e9SAndroid Build Coastguard Worker 
809*d57664e9SAndroid Build Coastguard Worker       if (auto map_entry = entry->map_entry()) {
810*d57664e9SAndroid Build Coastguard Worker         uint32_t map_entry_count = android::util::DeviceToHost32(map_entry->count);
811*d57664e9SAndroid Build Coastguard Worker         printer_->Print(StringPrintf(" count: 0x%04x", map_entry_count));
812*d57664e9SAndroid Build Coastguard Worker         printer_->Print(StringPrintf(" parent: 0x%08x\n",
813*d57664e9SAndroid Build Coastguard Worker                                      android::util::DeviceToHost32(map_entry->parent.ident)));
814*d57664e9SAndroid Build Coastguard Worker 
815*d57664e9SAndroid Build Coastguard Worker         // Print the name and value mappings
816*d57664e9SAndroid Build Coastguard Worker         auto maps = (const ResTable_map*)((const uint8_t*)entry + entry->size());
817*d57664e9SAndroid Build Coastguard Worker         for (size_t i = 0; i < map_entry_count; i++) {
818*d57664e9SAndroid Build Coastguard Worker           PrintResValue(&(maps[i].value), config, type);
819*d57664e9SAndroid Build Coastguard Worker 
820*d57664e9SAndroid Build Coastguard Worker           printer_->Print(StringPrintf(
821*d57664e9SAndroid Build Coastguard Worker               " name: %s name-id:%d\n",
822*d57664e9SAndroid Build Coastguard Worker               android::util::GetString(key_pool_, android::util::DeviceToHost32(maps[i].name.ident))
823*d57664e9SAndroid Build Coastguard Worker                   .c_str(),
824*d57664e9SAndroid Build Coastguard Worker               android::util::DeviceToHost32(maps[i].name.ident)));
825*d57664e9SAndroid Build Coastguard Worker         }
826*d57664e9SAndroid Build Coastguard Worker       } else {
827*d57664e9SAndroid Build Coastguard Worker         printer_->Print("\n");
828*d57664e9SAndroid Build Coastguard Worker 
829*d57664e9SAndroid Build Coastguard Worker         // Print the value of the entry
830*d57664e9SAndroid Build Coastguard Worker         Res_value value = entry->value();
831*d57664e9SAndroid Build Coastguard Worker         PrintResValue(&value, config, type);
832*d57664e9SAndroid Build Coastguard Worker       }
833*d57664e9SAndroid Build Coastguard Worker 
834*d57664e9SAndroid Build Coastguard Worker       printer_->Undent();
835*d57664e9SAndroid Build Coastguard Worker     }
836*d57664e9SAndroid Build Coastguard Worker 
837*d57664e9SAndroid Build Coastguard Worker     printer_->Undent();
838*d57664e9SAndroid Build Coastguard Worker     return true;
839*d57664e9SAndroid Build Coastguard Worker   }
840*d57664e9SAndroid Build Coastguard Worker 
PrintStringPool(const ResStringPool_header * chunk)841*d57664e9SAndroid Build Coastguard Worker   void PrintStringPool(const ResStringPool_header* chunk) {
842*d57664e9SAndroid Build Coastguard Worker     // Initialize the string pools
843*d57664e9SAndroid Build Coastguard Worker 
844*d57664e9SAndroid Build Coastguard Worker     ResStringPool* pool;
845*d57664e9SAndroid Build Coastguard Worker     if (value_pool_.getError() == NO_INIT) {
846*d57664e9SAndroid Build Coastguard Worker       pool = &value_pool_;
847*d57664e9SAndroid Build Coastguard Worker     } else if (type_pool_.getError() == NO_INIT) {
848*d57664e9SAndroid Build Coastguard Worker       pool = &type_pool_;
849*d57664e9SAndroid Build Coastguard Worker     } else if (key_pool_.getError() == NO_INIT) {
850*d57664e9SAndroid Build Coastguard Worker       pool = &key_pool_;
851*d57664e9SAndroid Build Coastguard Worker     } else {
852*d57664e9SAndroid Build Coastguard Worker       return;
853*d57664e9SAndroid Build Coastguard Worker     }
854*d57664e9SAndroid Build Coastguard Worker 
855*d57664e9SAndroid Build Coastguard Worker     pool->setTo(chunk, android::util::DeviceToHost32(
856*d57664e9SAndroid Build Coastguard Worker                            (reinterpret_cast<const ResChunk_header*>(chunk))->size));
857*d57664e9SAndroid Build Coastguard Worker 
858*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(" strings: %zd styles %zd flags: %s|%s\n", pool->size(),
859*d57664e9SAndroid Build Coastguard Worker                                  pool->styleCount(), pool->isUTF8() ? "UTF-8" : "UTF-16",
860*d57664e9SAndroid Build Coastguard Worker                                  pool->isSorted() ? "SORTED" : "NON-SORTED"));
861*d57664e9SAndroid Build Coastguard Worker 
862*d57664e9SAndroid Build Coastguard Worker     for (size_t i = 0; i < pool->size(); i++) {
863*d57664e9SAndroid Build Coastguard Worker       printer_->Print(StringPrintf("#%zd : %s\n", i, android::util::GetString(*pool, i).c_str()));
864*d57664e9SAndroid Build Coastguard Worker       if (i < pool->styleCount()) {
865*d57664e9SAndroid Build Coastguard Worker         printer_->Print(" [Style] ");
866*d57664e9SAndroid Build Coastguard Worker         auto maybe_style = pool->styleAt(i);
867*d57664e9SAndroid Build Coastguard Worker         if (!maybe_style) {
868*d57664e9SAndroid Build Coastguard Worker           printer_->Print("??? missing\n");
869*d57664e9SAndroid Build Coastguard Worker         } else {
870*d57664e9SAndroid Build Coastguard Worker           std::vector<const ResStringPool_span*> spans;
871*d57664e9SAndroid Build Coastguard Worker           for (auto style = maybe_style.value().unsafe_ptr();
872*d57664e9SAndroid Build Coastguard Worker                style->name.index != android::ResStringPool_span::END; ++style) {
873*d57664e9SAndroid Build Coastguard Worker             spans.push_back(style);
874*d57664e9SAndroid Build Coastguard Worker           }
875*d57664e9SAndroid Build Coastguard Worker           printer_->Print(StringPrintf("(%zd)", spans.size()));
876*d57664e9SAndroid Build Coastguard Worker           if (!spans.empty()) {
877*d57664e9SAndroid Build Coastguard Worker             printer_->Print(" :");
878*d57664e9SAndroid Build Coastguard Worker             for (const auto& span : spans) {
879*d57664e9SAndroid Build Coastguard Worker               printer_->Print(StringPrintf(
880*d57664e9SAndroid Build Coastguard Worker                   " %s:%u,%u", android::util::GetString(*pool, span->name.index).c_str(),
881*d57664e9SAndroid Build Coastguard Worker                   span->firstChar, span->lastChar));
882*d57664e9SAndroid Build Coastguard Worker             }
883*d57664e9SAndroid Build Coastguard Worker             printer_->Print("\n");
884*d57664e9SAndroid Build Coastguard Worker           }
885*d57664e9SAndroid Build Coastguard Worker         }
886*d57664e9SAndroid Build Coastguard Worker       }
887*d57664e9SAndroid Build Coastguard Worker     }
888*d57664e9SAndroid Build Coastguard Worker   }
889*d57664e9SAndroid Build Coastguard Worker 
PrintPackage(const ResTable_package * chunk)890*d57664e9SAndroid Build Coastguard Worker   bool PrintPackage(const ResTable_package* chunk) {
891*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
892*d57664e9SAndroid Build Coastguard Worker 
893*d57664e9SAndroid Build Coastguard Worker     size_t len = strnlen16((const char16_t*)chunk->name, std::size(chunk->name));
894*d57664e9SAndroid Build Coastguard Worker     std::u16string package_name(len, u'\0');
895*d57664e9SAndroid Build Coastguard Worker     package_name.resize(len);
896*d57664e9SAndroid Build Coastguard Worker     for (size_t i = 0; i < len; i++) {
897*d57664e9SAndroid Build Coastguard Worker       package_name[i] = android::util::DeviceToHost16(chunk->name[i]);
898*d57664e9SAndroid Build Coastguard Worker     }
899*d57664e9SAndroid Build Coastguard Worker 
900*d57664e9SAndroid Build Coastguard Worker     printer_->Print(StringPrintf("name: %s", String8(package_name.c_str()).c_str()));
901*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
902*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" typeStrings: %u", android::util::DeviceToHost32(chunk->typeStrings)));
903*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
904*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" lastPublicType: %u", android::util::DeviceToHost32(chunk->lastPublicType)));
905*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
906*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" keyStrings: %u", android::util::DeviceToHost32(chunk->keyStrings)));
907*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
908*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" lastPublicKey: %u", android::util::DeviceToHost32(chunk->lastPublicKey)));
909*d57664e9SAndroid Build Coastguard Worker     printer_->Print(
910*d57664e9SAndroid Build Coastguard Worker         StringPrintf(" typeIdOffset: %u\n", android::util::DeviceToHost32(chunk->typeIdOffset)));
911*d57664e9SAndroid Build Coastguard Worker 
912*d57664e9SAndroid Build Coastguard Worker     // Print the chunks contained within the table
913*d57664e9SAndroid Build Coastguard Worker     printer_->Indent();
914*d57664e9SAndroid Build Coastguard Worker     bool success = PrintChunk(
915*d57664e9SAndroid Build Coastguard Worker         ResChunkPullParser(GetChunkData(&chunk->header), GetChunkDataLen(&chunk->header)));
916*d57664e9SAndroid Build Coastguard Worker     printer_->Undent();
917*d57664e9SAndroid Build Coastguard Worker     return success;
918*d57664e9SAndroid Build Coastguard Worker   }
919*d57664e9SAndroid Build Coastguard Worker 
PrintChunk(ResChunkPullParser && parser)920*d57664e9SAndroid Build Coastguard Worker   bool PrintChunk(ResChunkPullParser&& parser) {
921*d57664e9SAndroid Build Coastguard Worker     while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
922*d57664e9SAndroid Build Coastguard Worker       auto chunk = parser.chunk();
923*d57664e9SAndroid Build Coastguard Worker       PrintChunkHeader(chunk);
924*d57664e9SAndroid Build Coastguard Worker 
925*d57664e9SAndroid Build Coastguard Worker       switch (android::util::DeviceToHost16(chunk->type)) {
926*d57664e9SAndroid Build Coastguard Worker         case RES_STRING_POOL_TYPE:
927*d57664e9SAndroid Build Coastguard Worker           PrintStringPool(reinterpret_cast<const ResStringPool_header*>(chunk));
928*d57664e9SAndroid Build Coastguard Worker           break;
929*d57664e9SAndroid Build Coastguard Worker 
930*d57664e9SAndroid Build Coastguard Worker         case RES_TABLE_TYPE:
931*d57664e9SAndroid Build Coastguard Worker           PrintTable(reinterpret_cast<const ResTable_header*>(chunk));
932*d57664e9SAndroid Build Coastguard Worker           break;
933*d57664e9SAndroid Build Coastguard Worker 
934*d57664e9SAndroid Build Coastguard Worker         case RES_TABLE_PACKAGE_TYPE:
935*d57664e9SAndroid Build Coastguard Worker           type_pool_.uninit();
936*d57664e9SAndroid Build Coastguard Worker           key_pool_.uninit();
937*d57664e9SAndroid Build Coastguard Worker           PrintPackage(reinterpret_cast<const ResTable_package*>(chunk));
938*d57664e9SAndroid Build Coastguard Worker           break;
939*d57664e9SAndroid Build Coastguard Worker 
940*d57664e9SAndroid Build Coastguard Worker         case RES_TABLE_TYPE_TYPE:
941*d57664e9SAndroid Build Coastguard Worker           PrintTableType(reinterpret_cast<const ResTable_type*>(chunk));
942*d57664e9SAndroid Build Coastguard Worker           break;
943*d57664e9SAndroid Build Coastguard Worker 
944*d57664e9SAndroid Build Coastguard Worker         case RES_TABLE_TYPE_SPEC_TYPE:
945*d57664e9SAndroid Build Coastguard Worker           PrintTypeSpec(reinterpret_cast<const ResTable_typeSpec*>(chunk));
946*d57664e9SAndroid Build Coastguard Worker           break;
947*d57664e9SAndroid Build Coastguard Worker 
948*d57664e9SAndroid Build Coastguard Worker         default:
949*d57664e9SAndroid Build Coastguard Worker           printer_->Print("\n");
950*d57664e9SAndroid Build Coastguard Worker           break;
951*d57664e9SAndroid Build Coastguard Worker       }
952*d57664e9SAndroid Build Coastguard Worker     }
953*d57664e9SAndroid Build Coastguard Worker 
954*d57664e9SAndroid Build Coastguard Worker     if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
955*d57664e9SAndroid Build Coastguard Worker       diag_->Error(android::DiagMessage(source_) << "corrupt resource table: " << parser.error());
956*d57664e9SAndroid Build Coastguard Worker       return false;
957*d57664e9SAndroid Build Coastguard Worker     }
958*d57664e9SAndroid Build Coastguard Worker 
959*d57664e9SAndroid Build Coastguard Worker     return true;
960*d57664e9SAndroid Build Coastguard Worker   }
961*d57664e9SAndroid Build Coastguard Worker 
Print()962*d57664e9SAndroid Build Coastguard Worker   void Print() {
963*d57664e9SAndroid Build Coastguard Worker     PrintChunk(ResChunkPullParser(data_, data_len_));
964*d57664e9SAndroid Build Coastguard Worker     printer_->Print("[End]\n");
965*d57664e9SAndroid Build Coastguard Worker   }
966*d57664e9SAndroid Build Coastguard Worker 
967*d57664e9SAndroid Build Coastguard Worker  private:
968*d57664e9SAndroid Build Coastguard Worker   const android::Source source_;
969*d57664e9SAndroid Build Coastguard Worker   const void* data_;
970*d57664e9SAndroid Build Coastguard Worker   const size_t data_len_;
971*d57664e9SAndroid Build Coastguard Worker   Printer* printer_;
972*d57664e9SAndroid Build Coastguard Worker   android::IDiagnostics* diag_;
973*d57664e9SAndroid Build Coastguard Worker 
974*d57664e9SAndroid Build Coastguard Worker   // The standard value string pool for resource values.
975*d57664e9SAndroid Build Coastguard Worker   ResStringPool value_pool_;
976*d57664e9SAndroid Build Coastguard Worker 
977*d57664e9SAndroid Build Coastguard Worker   // The string pool that holds the names of the types defined
978*d57664e9SAndroid Build Coastguard Worker   // in this table.
979*d57664e9SAndroid Build Coastguard Worker   ResStringPool type_pool_;
980*d57664e9SAndroid Build Coastguard Worker 
981*d57664e9SAndroid Build Coastguard Worker   // The string pool that holds the names of the entries defined
982*d57664e9SAndroid Build Coastguard Worker   // in this table.
983*d57664e9SAndroid Build Coastguard Worker   ResStringPool key_pool_;
984*d57664e9SAndroid Build Coastguard Worker 
985*d57664e9SAndroid Build Coastguard Worker   android::StringPool out_pool_;
986*d57664e9SAndroid Build Coastguard Worker };
987*d57664e9SAndroid Build Coastguard Worker 
988*d57664e9SAndroid Build Coastguard Worker }  // namespace
989*d57664e9SAndroid Build Coastguard Worker 
DumpChunks(const void * data,size_t len,Printer * printer,android::IDiagnostics * diag)990*d57664e9SAndroid Build Coastguard Worker void Debug::DumpChunks(const void* data, size_t len, Printer* printer,
991*d57664e9SAndroid Build Coastguard Worker                        android::IDiagnostics* diag) {
992*d57664e9SAndroid Build Coastguard Worker   ChunkPrinter chunk_printer(data, len, printer, diag);
993*d57664e9SAndroid Build Coastguard Worker   chunk_printer.Print();
994*d57664e9SAndroid Build Coastguard Worker }
995*d57664e9SAndroid Build Coastguard Worker 
996*d57664e9SAndroid Build Coastguard Worker }  // namespace aapt
997