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 }
432 }
433
434 if (source_pool != nullptr) {
435 SerializeStringPoolToPb(*source_pool, out_table->mutable_source_pool(), diag);
436 }
437 }
438
SerializeReferenceTypeToPb(Reference::Type type)439 static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) {
440 switch (type) {
441 case Reference::Type::kResource:
442 return pb::Reference_Type_REFERENCE;
443 case Reference::Type::kAttribute:
444 return pb::Reference_Type_ATTRIBUTE;
445 default:
446 break;
447 }
448 return pb::Reference_Type_REFERENCE;
449 }
450
SerializeReferenceToPb(const Reference & ref,pb::Reference * pb_ref)451 static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) {
452 pb_ref->set_id(ref.id.value_or(ResourceId(0x0)).id);
453
454 if (ref.name) {
455 pb_ref->set_name(ref.name.value().to_string());
456 }
457
458 pb_ref->set_private_(ref.private_reference);
459 pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type));
460 if (ref.is_dynamic) {
461 pb_ref->mutable_is_dynamic()->set_value(ref.is_dynamic);
462 }
463 if (ref.type_flags) {
464 pb_ref->set_type_flags(*ref.type_flags);
465 }
466 pb_ref->set_allow_raw(ref.allow_raw);
467 }
468
SerializeMacroToPb(const Macro & ref,pb::MacroBody * pb_macro)469 static void SerializeMacroToPb(const Macro& ref, pb::MacroBody* pb_macro) {
470 pb_macro->set_raw_string(ref.raw_value);
471
472 auto pb_style_str = pb_macro->mutable_style_string();
473 pb_style_str->set_str(ref.style_string.str);
474 for (const auto& span : ref.style_string.spans) {
475 auto pb_span = pb_style_str->add_spans();
476 pb_span->set_name(span.name);
477 pb_span->set_start_index(span.first_char);
478 pb_span->set_end_index(span.last_char);
479 }
480
481 for (const auto& untranslatable_section : ref.untranslatable_sections) {
482 auto pb_section = pb_macro->add_untranslatable_sections();
483 pb_section->set_start_index(untranslatable_section.start);
484 pb_section->set_end_index(untranslatable_section.end);
485 }
486
487 for (const auto& namespace_decls : ref.alias_namespaces) {
488 auto pb_namespace = pb_macro->add_namespace_stack();
489 pb_namespace->set_prefix(namespace_decls.alias);
490 pb_namespace->set_package_name(namespace_decls.package_name);
491 pb_namespace->set_is_private(namespace_decls.is_private);
492 }
493 }
494
495 template <typename T>
SerializeItemMetaDataToPb(const Item & item,T * pb_item,android::StringPool * src_pool)496 static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, android::StringPool* src_pool) {
497 if (src_pool != nullptr) {
498 SerializeSourceToPb(item.GetSource(), src_pool, pb_item->mutable_source());
499 }
500 pb_item->set_comment(item.GetComment());
501 }
502
SerializePluralEnumToPb(size_t plural_idx)503 static pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx) {
504 switch (plural_idx) {
505 case Plural::Zero:
506 return pb::Plural_Arity_ZERO;
507 case Plural::One:
508 return pb::Plural_Arity_ONE;
509 case Plural::Two:
510 return pb::Plural_Arity_TWO;
511 case Plural::Few:
512 return pb::Plural_Arity_FEW;
513 case Plural::Many:
514 return pb::Plural_Arity_MANY;
515 default:
516 break;
517 }
518 return pb::Plural_Arity_OTHER;
519 }
520
SerializeFileReferenceTypeToPb(const ResourceFile::Type & type)521 static pb::FileReference::Type SerializeFileReferenceTypeToPb(const ResourceFile::Type& type) {
522 switch (type) {
523 case ResourceFile::Type::kBinaryXml:
524 return pb::FileReference::BINARY_XML;
525 case ResourceFile::Type::kProtoXml:
526 return pb::FileReference::PROTO_XML;
527 case ResourceFile::Type::kPng:
528 return pb::FileReference::PNG;
529 default:
530 return pb::FileReference::UNKNOWN;
531 }
532 }
533
534 namespace {
535
536 class ValueSerializer : public ConstValueVisitor {
537 public:
538 using ConstValueVisitor::Visit;
539
ValueSerializer(pb::Value * out_value,android::StringPool * src_pool)540 ValueSerializer(pb::Value* out_value, android::StringPool* src_pool)
541 : out_value_(out_value), src_pool_(src_pool) {
542 }
543
Visit(const Reference * ref)544 void Visit(const Reference* ref) override {
545 SerializeReferenceToPb(*ref, out_value_->mutable_item()->mutable_ref());
546 }
547
Visit(const String * str)548 void Visit(const String* str) override {
549 out_value_->mutable_item()->mutable_str()->set_value(*str->value);
550 }
551
Visit(const RawString * str)552 void Visit(const RawString* str) override {
553 out_value_->mutable_item()->mutable_raw_str()->set_value(*str->value);
554 }
555
Visit(const StyledString * str)556 void Visit(const StyledString* str) override {
557 pb::StyledString* pb_str = out_value_->mutable_item()->mutable_styled_str();
558 pb_str->set_value(str->value->value);
559 for (const android::StringPool::Span& span : str->value->spans) {
560 pb::StyledString::Span* pb_span = pb_str->add_span();
561 pb_span->set_tag(*span.name);
562 pb_span->set_first_char(span.first_char);
563 pb_span->set_last_char(span.last_char);
564 }
565 }
566
Visit(const FileReference * file)567 void Visit(const FileReference* file) override {
568 pb::FileReference* pb_file = out_value_->mutable_item()->mutable_file();
569 pb_file->set_path(*file->path);
570 pb_file->set_type(SerializeFileReferenceTypeToPb(file->type));
571 }
572
Visit(const Id *)573 void Visit(const Id* /*id*/) override {
574 out_value_->mutable_item()->mutable_id();
575 }
576
Visit(const BinaryPrimitive * prim)577 void Visit(const BinaryPrimitive* prim) override {
578 android::Res_value val = {};
579 prim->Flatten(&val);
580
581 pb::Primitive* pb_prim = out_value_->mutable_item()->mutable_prim();
582
583 switch (val.dataType) {
584 case android::Res_value::TYPE_NULL: {
585 if (val.data == android::Res_value::DATA_NULL_UNDEFINED) {
586 pb_prim->set_allocated_null_value(new pb::Primitive_NullType());
587 } else if (val.data == android::Res_value::DATA_NULL_EMPTY) {
588 pb_prim->set_allocated_empty_value(new pb::Primitive_EmptyType());
589 } else {
590 LOG(FATAL) << "Unexpected data value for TYPE_NULL BinaryPrimitive: " << val.data;
591 }
592 } break;
593 case android::Res_value::TYPE_FLOAT: {
594 pb_prim->set_float_value(*(float*)&val.data);
595 } break;
596 case android::Res_value::TYPE_DIMENSION: {
597 pb_prim->set_dimension_value(val.data);
598 } break;
599 case android::Res_value::TYPE_FRACTION: {
600 pb_prim->set_fraction_value(val.data);
601 } break;
602 case android::Res_value::TYPE_INT_DEC: {
603 pb_prim->set_int_decimal_value(static_cast<int32_t>(val.data));
604 } break;
605 case android::Res_value::TYPE_INT_HEX: {
606 pb_prim->set_int_hexadecimal_value(val.data);
607 } break;
608 case android::Res_value::TYPE_INT_BOOLEAN: {
609 pb_prim->set_boolean_value(static_cast<bool>(val.data));
610 } break;
611 case android::Res_value::TYPE_INT_COLOR_ARGB8: {
612 pb_prim->set_color_argb8_value(val.data);
613 } break;
614 case android::Res_value::TYPE_INT_COLOR_RGB8: {
615 pb_prim->set_color_rgb8_value(val.data);
616 } break;
617 case android::Res_value::TYPE_INT_COLOR_ARGB4: {
618 pb_prim->set_color_argb4_value(val.data);
619 } break;
620 case android::Res_value::TYPE_INT_COLOR_RGB4: {
621 pb_prim->set_color_rgb4_value(val.data);
622 } break;
623 default:
624 LOG(FATAL) << "Unexpected BinaryPrimitive type: " << val.dataType;
625 break;
626 }
627 }
628
Visit(const Attribute * attr)629 void Visit(const Attribute* attr) override {
630 pb::Attribute* pb_attr = out_value_->mutable_compound_value()->mutable_attr();
631 pb_attr->set_format_flags(attr->type_mask);
632 pb_attr->set_min_int(attr->min_int);
633 pb_attr->set_max_int(attr->max_int);
634
635 for (auto& symbol : attr->symbols) {
636 pb::Attribute_Symbol* pb_symbol = pb_attr->add_symbol();
637 SerializeItemMetaDataToPb(symbol.symbol, pb_symbol, src_pool_);
638 SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name());
639 pb_symbol->set_value(symbol.value);
640 pb_symbol->set_type(symbol.type);
641 }
642 }
643
Visit(const Style * style)644 void Visit(const Style* style) override {
645 pb::Style* pb_style = out_value_->mutable_compound_value()->mutable_style();
646 if (style->parent) {
647 const Reference& parent = style->parent.value();
648 SerializeReferenceToPb(parent, pb_style->mutable_parent());
649 if (src_pool_ != nullptr) {
650 SerializeSourceToPb(parent.GetSource(), src_pool_, pb_style->mutable_parent_source());
651 }
652 }
653
654 for (const Style::Entry& entry : style->entries) {
655 pb::Style_Entry* pb_entry = pb_style->add_entry();
656 SerializeReferenceToPb(entry.key, pb_entry->mutable_key());
657 SerializeItemMetaDataToPb(entry.key, pb_entry, src_pool_);
658 SerializeItemToPb(*entry.value, pb_entry->mutable_item());
659 }
660 }
661
Visit(const Styleable * styleable)662 void Visit(const Styleable* styleable) override {
663 pb::Styleable* pb_styleable = out_value_->mutable_compound_value()->mutable_styleable();
664 for (const Reference& entry : styleable->entries) {
665 pb::Styleable_Entry* pb_entry = pb_styleable->add_entry();
666 SerializeItemMetaDataToPb(entry, pb_entry, src_pool_);
667 SerializeReferenceToPb(entry, pb_entry->mutable_attr());
668 }
669 }
670
Visit(const Array * array)671 void Visit(const Array* array) override {
672 pb::Array* pb_array = out_value_->mutable_compound_value()->mutable_array();
673 for (const std::unique_ptr<Item>& element : array->elements) {
674 pb::Array_Element* pb_element = pb_array->add_element();
675 SerializeItemMetaDataToPb(*element, pb_element, src_pool_);
676 SerializeItemToPb(*element, pb_element->mutable_item());
677 }
678 }
679
Visit(const Plural * plural)680 void Visit(const Plural* plural) override {
681 pb::Plural* pb_plural = out_value_->mutable_compound_value()->mutable_plural();
682 const size_t count = plural->values.size();
683 for (size_t i = 0; i < count; i++) {
684 if (!plural->values[i]) {
685 // No plural value set here.
686 continue;
687 }
688
689 pb::Plural_Entry* pb_entry = pb_plural->add_entry();
690 pb_entry->set_arity(SerializePluralEnumToPb(i));
691 SerializeItemMetaDataToPb(*plural->values[i], pb_entry, src_pool_);
692 SerializeItemToPb(*plural->values[i], pb_entry->mutable_item());
693 }
694 }
695
Visit(const Macro * macro)696 void Visit(const Macro* macro) override {
697 pb::MacroBody* pb_macro = out_value_->mutable_compound_value()->mutable_macro();
698 SerializeMacroToPb(*macro, pb_macro);
699 }
700
VisitAny(const Value * unknown)701 void VisitAny(const Value* unknown) override {
702 LOG(FATAL) << "unimplemented value: " << *unknown;
703 }
704
705 private:
706 pb::Value* out_value_;
707 android::StringPool* src_pool_;
708 };
709
710 } // namespace
711
SerializeValueToPb(const Value & value,pb::Value * out_value,android::StringPool * src_pool)712 void SerializeValueToPb(const Value& value, pb::Value* out_value, android::StringPool* src_pool) {
713 ValueSerializer serializer(out_value, src_pool);
714 value.Accept(&serializer);
715
716 // Serialize the meta-data of the Value.
717 out_value->set_comment(value.GetComment());
718 out_value->set_weak(value.IsWeak());
719 if (src_pool != nullptr) {
720 SerializeSourceToPb(value.GetSource(), src_pool, out_value->mutable_source());
721 }
722 }
723
SerializeItemToPb(const Item & item,pb::Item * out_item)724 void SerializeItemToPb(const Item& item, pb::Item* out_item) {
725 pb::Value value;
726 ValueSerializer serializer(&value, nullptr);
727 item.Accept(&serializer);
728 out_item->MergeFrom(value.item());
729 }
730
SerializeCompiledFileToPb(const ResourceFile & file,pb::internal::CompiledFile * out_file)731 void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
732 out_file->set_resource_name(file.name.to_string());
733 out_file->set_source_path(file.source.path);
734 out_file->set_type(SerializeFileReferenceTypeToPb(file.type));
735 SerializeConfig(file.config, out_file->mutable_config());
736
737 for (const SourcedResourceName& exported : file.exported_symbols) {
738 pb::internal::CompiledFile_Symbol* pb_symbol = out_file->add_exported_symbol();
739 pb_symbol->set_resource_name(exported.name.to_string());
740 pb_symbol->mutable_source()->set_line_number(exported.line);
741 }
742 }
743
SerializeXmlCommon(const xml::Node & node,pb::XmlNode * out_node)744 static void SerializeXmlCommon(const xml::Node& node, pb::XmlNode* out_node) {
745 pb::SourcePosition* pb_src = out_node->mutable_source();
746 pb_src->set_line_number(node.line_number);
747 pb_src->set_column_number(node.column_number);
748 }
749
SerializeXmlToPb(const xml::Element & el,pb::XmlNode * out_node,const SerializeXmlOptions options)750 void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node,
751 const SerializeXmlOptions options) {
752 SerializeXmlCommon(el, out_node);
753
754 pb::XmlElement* pb_element = out_node->mutable_element();
755 pb_element->set_name(el.name);
756 pb_element->set_namespace_uri(el.namespace_uri);
757
758 for (const xml::NamespaceDecl& ns : el.namespace_decls) {
759 pb::XmlNamespace* pb_ns = pb_element->add_namespace_declaration();
760 pb_ns->set_prefix(ns.prefix);
761 pb_ns->set_uri(ns.uri);
762 pb::SourcePosition* pb_src = pb_ns->mutable_source();
763 pb_src->set_line_number(ns.line_number);
764 pb_src->set_column_number(ns.column_number);
765 }
766
767 for (const xml::Attribute& attr : el.attributes) {
768 pb::XmlAttribute* pb_attr = pb_element->add_attribute();
769 pb_attr->set_name(attr.name);
770 pb_attr->set_namespace_uri(attr.namespace_uri);
771 pb_attr->set_value(attr.value);
772 if (attr.compiled_attribute) {
773 const ResourceId attr_id = attr.compiled_attribute.value().id.value_or(ResourceId{});
774 pb_attr->set_resource_id(attr_id.id);
775 }
776 if (attr.compiled_value != nullptr) {
777 SerializeItemToPb(*attr.compiled_value, pb_attr->mutable_compiled_item());
778 pb::SourcePosition* pb_src = pb_attr->mutable_source();
779 pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or(0));
780 }
781 }
782
783 for (const std::unique_ptr<xml::Node>& child : el.children) {
784 if (const xml::Element* child_el = xml::NodeCast<xml::Element>(child.get())) {
785 SerializeXmlToPb(*child_el, pb_element->add_child());
786 } else if (const xml::Text* text_el = xml::NodeCast<xml::Text>(child.get())) {
787 if (options.remove_empty_text_nodes && util::TrimWhitespace(text_el->text).empty()) {
788 // Do not serialize whitespace text nodes if told not to
789 continue;
790 }
791
792 pb::XmlNode *pb_child_node = pb_element->add_child();
793 SerializeXmlCommon(*text_el, pb_child_node);
794 pb_child_node->set_text(text_el->text);
795 } else {
796 LOG(FATAL) << "unhandled XmlNode type";
797 }
798 }
799 }
800
SerializeXmlResourceToPb(const xml::XmlResource & resource,pb::XmlNode * out_node,const SerializeXmlOptions options)801 void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node,
802 const SerializeXmlOptions options) {
803 SerializeXmlToPb(*resource.root, out_node, options);
804 }
805
806 } // namespace aapt
807