xref: /aosp_15_r20/frameworks/base/tools/aapt2/format/proto/ProtoSerialize.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2016 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 "format/proto/ProtoSerialize.h"
18 
19 #include "ValueVisitor.h"
20 #include "androidfw/BigBuffer.h"
21 #include "optimize/Obfuscator.h"
22 
23 using android::ConfigDescription;
24 
25 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
26 
27 namespace aapt {
28 
SerializeStringPoolToPb(const android::StringPool & pool,pb::StringPool * out_pb_pool,android::IDiagnostics * diag)29 void SerializeStringPoolToPb(const android::StringPool& pool, pb::StringPool* out_pb_pool,
30                              android::IDiagnostics* diag) {
31   android::BigBuffer buffer(1024);
32   android::StringPool::FlattenUtf8(&buffer, pool, diag);
33 
34   std::string* data = out_pb_pool->mutable_data();
35   data->reserve(buffer.size());
36 
37   size_t offset = 0;
38   for (const android::BigBuffer::Block& block : buffer) {
39     data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size);
40     offset += block.size;
41   }
42 }
43 
SerializeSourceToPb(const android::Source & source,android::StringPool * src_pool,pb::Source * out_pb_source)44 void SerializeSourceToPb(const android::Source& source, android::StringPool* src_pool,
45                          pb::Source* out_pb_source) {
46   android::StringPool::Ref ref = src_pool->MakeRef(source.path);
47   out_pb_source->set_path_idx(static_cast<uint32_t>(ref.index()));
48   if (source.line) {
49     out_pb_source->mutable_position()->set_line_number(static_cast<uint32_t>(source.line.value()));
50   }
51 }
52 
SerializeVisibilityToPb(Visibility::Level state)53 static pb::Visibility::Level SerializeVisibilityToPb(Visibility::Level state) {
54   switch (state) {
55     case Visibility::Level::kPrivate:
56       return pb::Visibility::PRIVATE;
57     case Visibility::Level::kPublic:
58       return pb::Visibility::PUBLIC;
59     default:
60       break;
61   }
62   return pb::Visibility::UNKNOWN;
63 }
64 
SerializeConfig(const ConfigDescription & config,pb::Configuration * out_pb_config)65 void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config) {
66   out_pb_config->set_mcc(config.mcc);
67   out_pb_config->set_mnc(config.mnc);
68   out_pb_config->set_locale(config.GetBcp47LanguageTag());
69 
70   switch (config.screenLayout & ConfigDescription::MASK_LAYOUTDIR) {
71     case ConfigDescription::LAYOUTDIR_LTR:
72       out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR);
73       break;
74 
75     case ConfigDescription::LAYOUTDIR_RTL:
76       out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL);
77       break;
78   }
79 
80   out_pb_config->set_screen_width(config.screenWidth);
81   out_pb_config->set_screen_height(config.screenHeight);
82   out_pb_config->set_screen_width_dp(config.screenWidthDp);
83   out_pb_config->set_screen_height_dp(config.screenHeightDp);
84   out_pb_config->set_smallest_screen_width_dp(config.smallestScreenWidthDp);
85 
86   switch (config.screenLayout & ConfigDescription::MASK_SCREENSIZE) {
87     case ConfigDescription::SCREENSIZE_SMALL:
88       out_pb_config->set_screen_layout_size(
89           pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL);
90       break;
91 
92     case ConfigDescription::SCREENSIZE_NORMAL:
93       out_pb_config->set_screen_layout_size(
94           pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL);
95       break;
96 
97     case ConfigDescription::SCREENSIZE_LARGE:
98       out_pb_config->set_screen_layout_size(
99           pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE);
100       break;
101 
102     case ConfigDescription::SCREENSIZE_XLARGE:
103       out_pb_config->set_screen_layout_size(
104           pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE);
105       break;
106   }
107 
108   switch (config.screenLayout & ConfigDescription::MASK_SCREENLONG) {
109     case ConfigDescription::SCREENLONG_YES:
110       out_pb_config->set_screen_layout_long(
111           pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG);
112       break;
113 
114     case ConfigDescription::SCREENLONG_NO:
115       out_pb_config->set_screen_layout_long(
116           pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG);
117       break;
118   }
119 
120   switch (config.screenLayout2 & ConfigDescription::MASK_SCREENROUND) {
121     case ConfigDescription::SCREENROUND_YES:
122       out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND);
123       break;
124 
125     case ConfigDescription::SCREENROUND_NO:
126       out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND);
127       break;
128   }
129 
130   switch (config.colorMode & ConfigDescription::MASK_WIDE_COLOR_GAMUT) {
131     case ConfigDescription::WIDE_COLOR_GAMUT_YES:
132       out_pb_config->set_wide_color_gamut(pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG);
133       break;
134 
135     case ConfigDescription::WIDE_COLOR_GAMUT_NO:
136       out_pb_config->set_wide_color_gamut(
137           pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG);
138       break;
139   }
140 
141   switch (config.colorMode & ConfigDescription::MASK_HDR) {
142     case ConfigDescription::HDR_YES:
143       out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_HIGHDR);
144       break;
145 
146     case ConfigDescription::HDR_NO:
147       out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_LOWDR);
148       break;
149   }
150 
151   switch (config.orientation) {
152     case ConfigDescription::ORIENTATION_PORT:
153       out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_PORT);
154       break;
155 
156     case ConfigDescription::ORIENTATION_LAND:
157       out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_LAND);
158       break;
159 
160     case ConfigDescription::ORIENTATION_SQUARE:
161       out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_SQUARE);
162       break;
163   }
164 
165   switch (config.uiMode & ConfigDescription::MASK_UI_MODE_TYPE) {
166     case ConfigDescription::UI_MODE_TYPE_NORMAL:
167       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL);
168       break;
169 
170     case ConfigDescription::UI_MODE_TYPE_DESK:
171       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_DESK);
172       break;
173 
174     case ConfigDescription::UI_MODE_TYPE_CAR:
175       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_CAR);
176       break;
177 
178     case ConfigDescription::UI_MODE_TYPE_TELEVISION:
179       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION);
180       break;
181 
182     case ConfigDescription::UI_MODE_TYPE_APPLIANCE:
183       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE);
184       break;
185 
186     case ConfigDescription::UI_MODE_TYPE_WATCH:
187       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH);
188       break;
189 
190     case ConfigDescription::UI_MODE_TYPE_VR_HEADSET:
191       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET);
192       break;
193   }
194 
195   switch (config.uiMode & ConfigDescription::MASK_UI_MODE_NIGHT) {
196     case ConfigDescription::UI_MODE_NIGHT_YES:
197       out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT);
198       break;
199 
200     case ConfigDescription::UI_MODE_NIGHT_NO:
201       out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT);
202       break;
203   }
204 
205   out_pb_config->set_density(config.density);
206 
207   switch (config.touchscreen) {
208     case ConfigDescription::TOUCHSCREEN_NOTOUCH:
209       out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH);
210       break;
211 
212     case ConfigDescription::TOUCHSCREEN_STYLUS:
213       out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS);
214       break;
215 
216     case ConfigDescription::TOUCHSCREEN_FINGER:
217       out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER);
218       break;
219   }
220 
221   switch (config.inputFlags & ConfigDescription::MASK_KEYSHIDDEN) {
222     case ConfigDescription::KEYSHIDDEN_NO:
223       out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED);
224       break;
225 
226     case ConfigDescription::KEYSHIDDEN_YES:
227       out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN);
228       break;
229 
230     case ConfigDescription::KEYSHIDDEN_SOFT:
231       out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT);
232       break;
233   }
234 
235   switch (config.keyboard) {
236     case ConfigDescription::KEYBOARD_NOKEYS:
237       out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_NOKEYS);
238       break;
239 
240     case ConfigDescription::KEYBOARD_QWERTY:
241       out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_QWERTY);
242       break;
243 
244     case ConfigDescription::KEYBOARD_12KEY:
245       out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY);
246       break;
247   }
248 
249   switch (config.inputFlags & ConfigDescription::MASK_NAVHIDDEN) {
250     case ConfigDescription::NAVHIDDEN_NO:
251       out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED);
252       break;
253 
254     case ConfigDescription::NAVHIDDEN_YES:
255       out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN);
256       break;
257   }
258 
259   switch (config.navigation) {
260     case ConfigDescription::NAVIGATION_NONAV:
261       out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_NONAV);
262       break;
263 
264     case ConfigDescription::NAVIGATION_DPAD:
265       out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_DPAD);
266       break;
267 
268     case ConfigDescription::NAVIGATION_TRACKBALL:
269       out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_TRACKBALL);
270       break;
271 
272     case ConfigDescription::NAVIGATION_WHEEL:
273       out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_WHEEL);
274       break;
275   }
276 
277   out_pb_config->set_sdk_version(config.sdkVersion);
278 
279   // The constant values are the same across the structs.
280   out_pb_config->set_grammatical_gender(
281       static_cast<pb::Configuration_GrammaticalGender>(config.grammaticalInflection));
282 }
283 
SerializeOverlayableItemToPb(const OverlayableItem & overlayable_item,std::vector<Overlayable * > & serialized_overlayables,android::StringPool * source_pool,pb::Entry * pb_entry,pb::ResourceTable * pb_table)284 static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item,
285                                          std::vector<Overlayable*>& serialized_overlayables,
286                                          android::StringPool* source_pool, pb::Entry* pb_entry,
287                                          pb::ResourceTable* pb_table) {
288   // Retrieve the index of the overlayable in the list of groups that have already been serialized.
289   size_t i;
290   for (i = 0 ; i < serialized_overlayables.size(); i++) {
291     if (overlayable_item.overlayable.get() == serialized_overlayables[i]) {
292       break;
293     }
294   }
295 
296   // Serialize the overlayable if it has not been serialized already.
297   if (i == serialized_overlayables.size()) {
298     serialized_overlayables.push_back(overlayable_item.overlayable.get());
299     pb::Overlayable* pb_overlayable = pb_table->add_overlayable();
300     pb_overlayable->set_name(overlayable_item.overlayable->name);
301     pb_overlayable->set_actor(overlayable_item.overlayable->actor);
302     if (source_pool != nullptr) {
303       SerializeSourceToPb(overlayable_item.overlayable->source, source_pool,
304                           pb_overlayable->mutable_source());
305     }
306   }
307 
308   pb::OverlayableItem* pb_overlayable_item = pb_entry->mutable_overlayable_item();
309   pb_overlayable_item->set_overlayable_idx(i);
310 
311   if (overlayable_item.policies & PolicyFlags::PUBLIC) {
312     pb_overlayable_item->add_policy(pb::OverlayableItem::PUBLIC);
313   }
314   if (overlayable_item.policies & PolicyFlags::PRODUCT_PARTITION) {
315     pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT);
316   }
317   if (overlayable_item.policies & PolicyFlags::SYSTEM_PARTITION) {
318     pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM);
319   }
320   if (overlayable_item.policies & PolicyFlags::VENDOR_PARTITION) {
321     pb_overlayable_item->add_policy(pb::OverlayableItem::VENDOR);
322   }
323   if (overlayable_item.policies & PolicyFlags::SIGNATURE) {
324     pb_overlayable_item->add_policy(pb::OverlayableItem::SIGNATURE);
325   }
326   if (overlayable_item.policies & PolicyFlags::ODM_PARTITION) {
327     pb_overlayable_item->add_policy(pb::OverlayableItem::ODM);
328   }
329   if (overlayable_item.policies & PolicyFlags::OEM_PARTITION) {
330     pb_overlayable_item->add_policy(pb::OverlayableItem::OEM);
331   }
332   if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) {
333     pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR);
334   }
335   if (overlayable_item.policies & PolicyFlags::CONFIG_SIGNATURE) {
336     pb_overlayable_item->add_policy(pb::OverlayableItem::CONFIG_SIGNATURE);
337   }
338 
339   if (source_pool != nullptr) {
340     SerializeSourceToPb(overlayable_item.source, source_pool,
341                         pb_overlayable_item->mutable_source());
342   }
343   pb_overlayable_item->set_comment(overlayable_item.comment);
344 }
345 
SerializeTableToPb(const ResourceTable & table,pb::ResourceTable * out_table,android::IDiagnostics * diag,SerializeTableOptions options)346 void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
347                         android::IDiagnostics* diag, SerializeTableOptions options) {
348   auto source_pool = (options.exclude_sources) ? nullptr : util::make_unique<android::StringPool>();
349 
350   pb::ToolFingerprint* pb_fingerprint = out_table->add_tool_fingerprint();
351   pb_fingerprint->set_tool(util::GetToolName());
352   pb_fingerprint->set_version(util::GetToolFingerprint());
353   for (auto it = table.included_packages_.begin(); it != table.included_packages_.end(); ++it) {
354     pb::DynamicRefTable* pb_dynamic_ref = out_table->add_dynamic_ref_table();
355     pb_dynamic_ref->mutable_package_id()->set_id(it->first);
356     pb_dynamic_ref->set_package_name(it->second);
357   }
358   std::vector<Overlayable*> overlayables;
359   auto table_view = table.GetPartitionedView();
360   for (const auto& package : table_view.packages) {
361     pb::Package* pb_package = out_table->add_package();
362     if (package.id) {
363       pb_package->mutable_package_id()->set_id(package.id.value());
364     }
365     pb_package->set_package_name(package.name);
366 
367     for (const auto& type : package.types) {
368       pb::Type* pb_type = pb_package->add_type();
369       if (type.id) {
370         pb_type->mutable_type_id()->set_id(type.id.value());
371       }
372       pb_type->set_name(type.named_type.to_string());
373 
374       for (const auto& entry : type.entries) {
375         pb::Entry* pb_entry = pb_type->add_entry();
376         if (entry.id) {
377           pb_entry->mutable_entry_id()->set_id(entry.id.value());
378         }
379         auto onObfuscate = [pb_entry, &entry](Obfuscator::Result obfuscatedResult,
380                                               const ResourceName& resource_name) {
381           pb_entry->set_name(obfuscatedResult == Obfuscator::Result::Obfuscated
382                                  ? Obfuscator::kObfuscatedResourceName
383                                  : entry.name);
384         };
385 
386         Obfuscator::ObfuscateResourceName(options.collapse_key_stringpool,
387                                           options.name_collapse_exemptions, type.named_type, entry,
388                                           onObfuscate);
389 
390         // Write the Visibility struct.
391         pb::Visibility* pb_visibility = pb_entry->mutable_visibility();
392         pb_visibility->set_staged_api(entry.visibility.staged_api);
393         pb_visibility->set_level(SerializeVisibilityToPb(entry.visibility.level));
394         if (source_pool != nullptr) {
395           SerializeSourceToPb(entry.visibility.source, source_pool.get(),
396                               pb_visibility->mutable_source());
397         }
398         pb_visibility->set_comment(entry.visibility.comment);
399 
400         if (entry.allow_new) {
401           pb::AllowNew* pb_allow_new = pb_entry->mutable_allow_new();
402           if (source_pool != nullptr) {
403             SerializeSourceToPb(entry.allow_new.value().source, source_pool.get(),
404                                 pb_allow_new->mutable_source());
405           }
406           pb_allow_new->set_comment(entry.allow_new.value().comment);
407         }
408 
409         if (entry.overlayable_item) {
410           SerializeOverlayableItemToPb(entry.overlayable_item.value(), overlayables,
411                                        source_pool.get(), pb_entry, out_table);
412         }
413 
414         if (entry.staged_id) {
415           pb::StagedId* pb_staged_id = pb_entry->mutable_staged_id();
416           if (source_pool != nullptr) {
417             SerializeSourceToPb(entry.staged_id.value().source, source_pool.get(),
418                                 pb_staged_id->mutable_source());
419           }
420           pb_staged_id->set_staged_id(entry.staged_id.value().id.id);
421         }
422 
423         for (const ResourceConfigValue* config_value : entry.values) {
424           pb::ConfigValue* pb_config_value = pb_entry->add_config_value();
425           SerializeConfig(config_value->config, pb_config_value->mutable_config());
426           pb_config_value->mutable_config()->set_product(config_value->product);
427           SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(),
428                              source_pool.get());
429         }
430 
431         for (const ResourceConfigValue* config_value : entry.flag_disabled_values) {
432           pb::ConfigValue* pb_config_value = pb_entry->add_flag_disabled_config_value();
433           SerializeConfig(config_value->config, pb_config_value->mutable_config());
434           pb_config_value->mutable_config()->set_product(config_value->product);
435           SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(),
436                              source_pool.get());
437         }
438       }
439     }
440   }
441 
442   if (source_pool != nullptr) {
443     SerializeStringPoolToPb(*source_pool, out_table->mutable_source_pool(), diag);
444   }
445 }
446 
SerializeReferenceTypeToPb(Reference::Type type)447 static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) {
448   switch (type) {
449     case Reference::Type::kResource:
450       return pb::Reference_Type_REFERENCE;
451     case Reference::Type::kAttribute:
452       return pb::Reference_Type_ATTRIBUTE;
453     default:
454       break;
455   }
456   return pb::Reference_Type_REFERENCE;
457 }
458 
SerializeReferenceToPb(const Reference & ref,pb::Reference * pb_ref)459 static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) {
460   pb_ref->set_id(ref.id.value_or(ResourceId(0x0)).id);
461 
462   if (ref.name) {
463     pb_ref->set_name(ref.name.value().to_string());
464   }
465 
466   pb_ref->set_private_(ref.private_reference);
467   pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type));
468   if (ref.is_dynamic) {
469     pb_ref->mutable_is_dynamic()->set_value(ref.is_dynamic);
470   }
471   if (ref.type_flags) {
472     pb_ref->set_type_flags(*ref.type_flags);
473   }
474   pb_ref->set_allow_raw(ref.allow_raw);
475 }
476 
SerializeMacroToPb(const Macro & ref,pb::MacroBody * pb_macro)477 static void SerializeMacroToPb(const Macro& ref, pb::MacroBody* pb_macro) {
478   pb_macro->set_raw_string(ref.raw_value);
479 
480   auto pb_style_str = pb_macro->mutable_style_string();
481   pb_style_str->set_str(ref.style_string.str);
482   for (const auto& span : ref.style_string.spans) {
483     auto pb_span = pb_style_str->add_spans();
484     pb_span->set_name(span.name);
485     pb_span->set_start_index(span.first_char);
486     pb_span->set_end_index(span.last_char);
487   }
488 
489   for (const auto& untranslatable_section : ref.untranslatable_sections) {
490     auto pb_section = pb_macro->add_untranslatable_sections();
491     pb_section->set_start_index(untranslatable_section.start);
492     pb_section->set_end_index(untranslatable_section.end);
493   }
494 
495   for (const auto& namespace_decls : ref.alias_namespaces) {
496     auto pb_namespace = pb_macro->add_namespace_stack();
497     pb_namespace->set_prefix(namespace_decls.alias);
498     pb_namespace->set_package_name(namespace_decls.package_name);
499     pb_namespace->set_is_private(namespace_decls.is_private);
500   }
501 }
502 
503 template <typename T>
SerializeItemMetaDataToPb(const Item & item,T * pb_item,android::StringPool * src_pool)504 static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, android::StringPool* src_pool) {
505   if (src_pool != nullptr) {
506     SerializeSourceToPb(item.GetSource(), src_pool, pb_item->mutable_source());
507   }
508   pb_item->set_comment(item.GetComment());
509 }
510 
SerializePluralEnumToPb(size_t plural_idx)511 static pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx) {
512   switch (plural_idx) {
513     case Plural::Zero:
514       return pb::Plural_Arity_ZERO;
515     case Plural::One:
516       return pb::Plural_Arity_ONE;
517     case Plural::Two:
518       return pb::Plural_Arity_TWO;
519     case Plural::Few:
520       return pb::Plural_Arity_FEW;
521     case Plural::Many:
522       return pb::Plural_Arity_MANY;
523     default:
524       break;
525   }
526   return pb::Plural_Arity_OTHER;
527 }
528 
SerializeFileReferenceTypeToPb(const ResourceFile::Type & type)529 static pb::FileReference::Type SerializeFileReferenceTypeToPb(const ResourceFile::Type& type) {
530   switch (type) {
531     case ResourceFile::Type::kBinaryXml:
532       return pb::FileReference::BINARY_XML;
533     case ResourceFile::Type::kProtoXml:
534       return pb::FileReference::PROTO_XML;
535     case ResourceFile::Type::kPng:
536       return pb::FileReference::PNG;
537     default:
538       return pb::FileReference::UNKNOWN;
539   }
540 }
541 
542 namespace {
543 
544 class ValueSerializer : public ConstValueVisitor {
545  public:
546   using ConstValueVisitor::Visit;
547 
ValueSerializer(pb::Value * out_value,android::StringPool * src_pool)548   ValueSerializer(pb::Value* out_value, android::StringPool* src_pool)
549       : out_value_(out_value), src_pool_(src_pool) {
550   }
551 
Visit(const Reference * ref)552   void Visit(const Reference* ref) override {
553     SerializeReferenceToPb(*ref, out_value_->mutable_item()->mutable_ref());
554   }
555 
Visit(const String * str)556   void Visit(const String* str) override {
557     out_value_->mutable_item()->mutable_str()->set_value(*str->value);
558   }
559 
Visit(const RawString * str)560   void Visit(const RawString* str) override {
561     out_value_->mutable_item()->mutable_raw_str()->set_value(*str->value);
562   }
563 
Visit(const StyledString * str)564   void Visit(const StyledString* str) override {
565     pb::StyledString* pb_str = out_value_->mutable_item()->mutable_styled_str();
566     pb_str->set_value(str->value->value);
567     for (const android::StringPool::Span& span : str->value->spans) {
568       pb::StyledString::Span* pb_span = pb_str->add_span();
569       pb_span->set_tag(*span.name);
570       pb_span->set_first_char(span.first_char);
571       pb_span->set_last_char(span.last_char);
572     }
573   }
574 
Visit(const FileReference * file)575   void Visit(const FileReference* file) override {
576     pb::FileReference* pb_file = out_value_->mutable_item()->mutable_file();
577     pb_file->set_path(*file->path);
578     pb_file->set_type(SerializeFileReferenceTypeToPb(file->type));
579   }
580 
Visit(const Id *)581   void Visit(const Id* /*id*/) override {
582     out_value_->mutable_item()->mutable_id();
583   }
584 
Visit(const BinaryPrimitive * prim)585   void Visit(const BinaryPrimitive* prim) override {
586     android::Res_value val = {};
587     prim->Flatten(&val);
588 
589     pb::Primitive* pb_prim = out_value_->mutable_item()->mutable_prim();
590 
591     switch (val.dataType) {
592       case android::Res_value::TYPE_NULL: {
593         if (val.data == android::Res_value::DATA_NULL_UNDEFINED) {
594           pb_prim->set_allocated_null_value(new pb::Primitive_NullType());
595         } else if (val.data == android::Res_value::DATA_NULL_EMPTY) {
596           pb_prim->set_allocated_empty_value(new pb::Primitive_EmptyType());
597         } else {
598           LOG(FATAL) << "Unexpected data value for TYPE_NULL BinaryPrimitive: " << val.data;
599         }
600       } break;
601       case android::Res_value::TYPE_FLOAT: {
602         pb_prim->set_float_value(*(float*)&val.data);
603       } break;
604       case android::Res_value::TYPE_DIMENSION: {
605         pb_prim->set_dimension_value(val.data);
606       } break;
607       case android::Res_value::TYPE_FRACTION: {
608         pb_prim->set_fraction_value(val.data);
609       } break;
610       case android::Res_value::TYPE_INT_DEC: {
611         pb_prim->set_int_decimal_value(static_cast<int32_t>(val.data));
612       } break;
613       case android::Res_value::TYPE_INT_HEX: {
614         pb_prim->set_int_hexadecimal_value(val.data);
615       } break;
616       case android::Res_value::TYPE_INT_BOOLEAN: {
617         pb_prim->set_boolean_value(static_cast<bool>(val.data));
618       } break;
619       case android::Res_value::TYPE_INT_COLOR_ARGB8: {
620         pb_prim->set_color_argb8_value(val.data);
621       } break;
622       case android::Res_value::TYPE_INT_COLOR_RGB8: {
623         pb_prim->set_color_rgb8_value(val.data);
624       } break;
625       case android::Res_value::TYPE_INT_COLOR_ARGB4: {
626         pb_prim->set_color_argb4_value(val.data);
627       } break;
628       case android::Res_value::TYPE_INT_COLOR_RGB4: {
629         pb_prim->set_color_rgb4_value(val.data);
630       } break;
631       default:
632         LOG(FATAL) << "Unexpected BinaryPrimitive type: " << val.dataType;
633         break;
634     }
635   }
636 
Visit(const Attribute * attr)637   void Visit(const Attribute* attr) override {
638     pb::Attribute* pb_attr = out_value_->mutable_compound_value()->mutable_attr();
639     pb_attr->set_format_flags(attr->type_mask);
640     pb_attr->set_min_int(attr->min_int);
641     pb_attr->set_max_int(attr->max_int);
642 
643     for (auto& symbol : attr->symbols) {
644       pb::Attribute_Symbol* pb_symbol = pb_attr->add_symbol();
645       SerializeItemMetaDataToPb(symbol.symbol, pb_symbol, src_pool_);
646       SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name());
647       pb_symbol->set_value(symbol.value);
648       pb_symbol->set_type(symbol.type);
649     }
650   }
651 
Visit(const Style * style)652   void Visit(const Style* style) override {
653     pb::Style* pb_style = out_value_->mutable_compound_value()->mutable_style();
654     if (style->parent) {
655       const Reference& parent = style->parent.value();
656       SerializeReferenceToPb(parent, pb_style->mutable_parent());
657       if (src_pool_ != nullptr) {
658         SerializeSourceToPb(parent.GetSource(), src_pool_, pb_style->mutable_parent_source());
659       }
660     }
661 
662     for (const Style::Entry& entry : style->entries) {
663       pb::Style_Entry* pb_entry = pb_style->add_entry();
664       SerializeReferenceToPb(entry.key, pb_entry->mutable_key());
665       SerializeItemMetaDataToPb(entry.key, pb_entry, src_pool_);
666       SerializeItemToPb(*entry.value, pb_entry->mutable_item());
667     }
668   }
669 
Visit(const Styleable * styleable)670   void Visit(const Styleable* styleable) override {
671     pb::Styleable* pb_styleable = out_value_->mutable_compound_value()->mutable_styleable();
672     for (const Reference& entry : styleable->entries) {
673       pb::Styleable_Entry* pb_entry = pb_styleable->add_entry();
674       SerializeItemMetaDataToPb(entry, pb_entry, src_pool_);
675       SerializeReferenceToPb(entry, pb_entry->mutable_attr());
676     }
677   }
678 
Visit(const Array * array)679   void Visit(const Array* array) override {
680     pb::Array* pb_array = out_value_->mutable_compound_value()->mutable_array();
681     for (const std::unique_ptr<Item>& element : array->elements) {
682       pb::Array_Element* pb_element = pb_array->add_element();
683       SerializeItemMetaDataToPb(*element, pb_element, src_pool_);
684       SerializeItemToPb(*element, pb_element->mutable_item());
685     }
686   }
687 
Visit(const Plural * plural)688   void Visit(const Plural* plural) override {
689     pb::Plural* pb_plural = out_value_->mutable_compound_value()->mutable_plural();
690     const size_t count = plural->values.size();
691     for (size_t i = 0; i < count; i++) {
692       if (!plural->values[i]) {
693         // No plural value set here.
694         continue;
695       }
696 
697       pb::Plural_Entry* pb_entry = pb_plural->add_entry();
698       pb_entry->set_arity(SerializePluralEnumToPb(i));
699       SerializeItemMetaDataToPb(*plural->values[i], pb_entry, src_pool_);
700       SerializeItemToPb(*plural->values[i], pb_entry->mutable_item());
701     }
702   }
703 
Visit(const Macro * macro)704   void Visit(const Macro* macro) override {
705     pb::MacroBody* pb_macro = out_value_->mutable_compound_value()->mutable_macro();
706     SerializeMacroToPb(*macro, pb_macro);
707   }
708 
VisitAny(const Value * unknown)709   void VisitAny(const Value* unknown) override {
710     LOG(FATAL) << "unimplemented value: " << *unknown;
711   }
712 
713  private:
714   pb::Value* out_value_;
715   android::StringPool* src_pool_;
716 };
717 
718 }  // namespace
719 
SerializeValueToPb(const Value & value,pb::Value * out_value,android::StringPool * src_pool)720 void SerializeValueToPb(const Value& value, pb::Value* out_value, android::StringPool* src_pool) {
721   ValueSerializer serializer(out_value, src_pool);
722   value.Accept(&serializer);
723 
724   // Serialize the meta-data of the Value.
725   out_value->set_comment(value.GetComment());
726   out_value->set_weak(value.IsWeak());
727   if (src_pool != nullptr) {
728     SerializeSourceToPb(value.GetSource(), src_pool, out_value->mutable_source());
729   }
730   if (out_value->has_item()) {
731     out_value->mutable_item()->set_flag_status((uint32_t)value.GetFlagStatus());
732     if (value.GetFlag()) {
733       const auto& flag = value.GetFlag();
734       out_value->mutable_item()->set_flag_negated(flag->negated);
735       out_value->mutable_item()->set_flag_name(flag->name);
736     }
737   } else if (out_value->has_compound_value()) {
738     out_value->mutable_compound_value()->set_flag_status((uint32_t)value.GetFlagStatus());
739     if (value.GetFlag()) {
740       const auto& flag = value.GetFlag();
741       out_value->mutable_compound_value()->set_flag_negated(flag->negated);
742       out_value->mutable_compound_value()->set_flag_name(flag->name);
743     }
744   }
745 }
746 
SerializeItemToPb(const Item & item,pb::Item * out_item)747 void SerializeItemToPb(const Item& item, pb::Item* out_item) {
748   pb::Value value;
749   ValueSerializer serializer(&value, nullptr);
750   item.Accept(&serializer);
751   out_item->MergeFrom(value.item());
752   out_item->set_flag_status((uint32_t)item.GetFlagStatus());
753   if (item.GetFlag()) {
754     const auto& flag = item.GetFlag();
755     out_item->set_flag_negated(flag->negated);
756     out_item->set_flag_name(flag->name);
757   }
758 }
759 
SerializeCompiledFileToPb(const ResourceFile & file,pb::internal::CompiledFile * out_file)760 void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
761   out_file->set_resource_name(file.name.to_string());
762   out_file->set_source_path(file.source.path);
763   out_file->set_type(SerializeFileReferenceTypeToPb(file.type));
764   SerializeConfig(file.config, out_file->mutable_config());
765   out_file->set_flag_status((uint32_t)file.flag_status);
766   if (file.flag) {
767     out_file->set_flag_negated(file.flag->negated);
768     out_file->set_flag_name(file.flag->name);
769   }
770 
771   for (const SourcedResourceName& exported : file.exported_symbols) {
772     pb::internal::CompiledFile_Symbol* pb_symbol = out_file->add_exported_symbol();
773     pb_symbol->set_resource_name(exported.name.to_string());
774     pb_symbol->mutable_source()->set_line_number(exported.line);
775   }
776 }
777 
SerializeXmlCommon(const xml::Node & node,pb::XmlNode * out_node)778 static void SerializeXmlCommon(const xml::Node& node, pb::XmlNode* out_node) {
779   pb::SourcePosition* pb_src = out_node->mutable_source();
780   pb_src->set_line_number(node.line_number);
781   pb_src->set_column_number(node.column_number);
782 }
783 
SerializeXmlToPb(const xml::Element & el,pb::XmlNode * out_node,const SerializeXmlOptions options)784 void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node,
785                       const SerializeXmlOptions options) {
786   SerializeXmlCommon(el, out_node);
787 
788   pb::XmlElement* pb_element = out_node->mutable_element();
789   pb_element->set_name(el.name);
790   pb_element->set_namespace_uri(el.namespace_uri);
791 
792   for (const xml::NamespaceDecl& ns : el.namespace_decls) {
793     pb::XmlNamespace* pb_ns = pb_element->add_namespace_declaration();
794     pb_ns->set_prefix(ns.prefix);
795     pb_ns->set_uri(ns.uri);
796     pb::SourcePosition* pb_src = pb_ns->mutable_source();
797     pb_src->set_line_number(ns.line_number);
798     pb_src->set_column_number(ns.column_number);
799   }
800 
801   for (const xml::Attribute& attr : el.attributes) {
802     pb::XmlAttribute* pb_attr = pb_element->add_attribute();
803     pb_attr->set_name(attr.name);
804     pb_attr->set_namespace_uri(attr.namespace_uri);
805     pb_attr->set_value(attr.value);
806     if (attr.compiled_attribute) {
807       const ResourceId attr_id = attr.compiled_attribute.value().id.value_or(ResourceId{});
808       pb_attr->set_resource_id(attr_id.id);
809     }
810     if (attr.compiled_value != nullptr) {
811       SerializeItemToPb(*attr.compiled_value, pb_attr->mutable_compiled_item());
812       pb::SourcePosition* pb_src = pb_attr->mutable_source();
813       pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or(0));
814     }
815   }
816 
817   for (const std::unique_ptr<xml::Node>& child : el.children) {
818     if (const xml::Element* child_el = xml::NodeCast<xml::Element>(child.get())) {
819       SerializeXmlToPb(*child_el, pb_element->add_child());
820     } else if (const xml::Text* text_el = xml::NodeCast<xml::Text>(child.get())) {
821       if (options.remove_empty_text_nodes && util::TrimWhitespace(text_el->text).empty()) {
822         // Do not serialize whitespace text nodes if told not to
823         continue;
824       }
825 
826       pb::XmlNode *pb_child_node = pb_element->add_child();
827       SerializeXmlCommon(*text_el, pb_child_node);
828       pb_child_node->set_text(text_el->text);
829     } else {
830       LOG(FATAL) << "unhandled XmlNode type";
831     }
832   }
833 }
834 
SerializeXmlResourceToPb(const xml::XmlResource & resource,pb::XmlNode * out_node,const SerializeXmlOptions options)835 void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node,
836                               const SerializeXmlOptions options) {
837   SerializeXmlToPb(*resource.root, out_node, options);
838 }
839 
840 }  // namespace aapt
841