AAPT2: Enable building proto artifacts

- This will allow the bundle tool to ingest the outputs of the aapt2 link
  phase.

Bug: 64143208
Test: manual
Change-Id: I1a4b3ce5c2ffbbdc4bc642c3371a9ef2e7e9ad71
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 1555d6126..61c304b 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -35,11 +35,11 @@
 
 namespace {
 
-class PrintVisitor : public DescendingValueVisitor {
+class PrintVisitor : public ConstValueVisitor {
  public:
-  using DescendingValueVisitor::Visit;
+  using ConstValueVisitor::Visit;
 
-  void Visit(Attribute* attr) override {
+  void Visit(const Attribute* attr) override {
     std::cout << "(attr) type=";
     attr->PrintMask(&std::cout);
     static constexpr uint32_t kMask =
@@ -55,7 +55,7 @@
     }
   }
 
-  void Visit(Style* style) override {
+  void Visit(const Style* style) override {
     std::cout << "(style)";
     if (style->parent) {
       const Reference& parent_ref = style->parent.value();
@@ -90,15 +90,15 @@
     }
   }
 
-  void Visit(Array* array) override {
+  void Visit(const Array* array) override {
     array->Print(&std::cout);
   }
 
-  void Visit(Plural* plural) override {
+  void Visit(const Plural* plural) override {
     plural->Print(&std::cout);
   }
 
-  void Visit(Styleable* styleable) override {
+  void Visit(const Styleable* styleable) override {
     std::cout << "(styleable)";
     for (const auto& attr : styleable->entries) {
       std::cout << "\n        ";
@@ -116,17 +116,17 @@
     }
   }
 
-  void VisitItem(Item* item) override {
+  void VisitItem(const Item* item) override {
     item->Print(&std::cout);
   }
 };
 
 }  // namespace
 
-void Debug::PrintTable(ResourceTable* table, const DebugPrintTableOptions& options) {
+void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options) {
   PrintVisitor visitor;
 
-  for (auto& package : table->packages) {
+  for (const auto& package : table.packages) {
     std::cout << "Package name=" << package->name;
     if (package->id) {
       std::cout << " id=" << std::hex << (int)package->id.value() << std::dec;
@@ -261,11 +261,11 @@
 
 namespace {
 
-class XmlPrinter : public xml::Visitor {
+class XmlPrinter : public xml::ConstVisitor {
  public:
-  using xml::Visitor::Visit;
+  using xml::ConstVisitor::Visit;
 
-  void Visit(xml::Element* el) override {
+  void Visit(const xml::Element* el) override {
     const size_t previous_size = prefix_.size();
 
     for (const xml::NamespaceDecl& decl : el->namespace_decls) {
@@ -301,11 +301,11 @@
     }
 
     prefix_ += "  ";
-    xml::Visitor::Visit(el);
+    xml::ConstVisitor::Visit(el);
     prefix_.resize(previous_size);
   }
 
-  void Visit(xml::Text* text) override {
+  void Visit(const xml::Text* text) override {
     std::cerr << prefix_ << "T: '" << text->text << "'\n";
   }
 
@@ -315,9 +315,9 @@
 
 }  // namespace
 
-void Debug::DumpXml(xml::XmlResource* doc) {
+void Debug::DumpXml(const xml::XmlResource& doc) {
   XmlPrinter printer;
-  doc->root->Accept(&printer);
+  doc.root->Accept(&printer);
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index e2456c7..296d04b 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -31,13 +31,11 @@
 };
 
 struct Debug {
-  static void PrintTable(ResourceTable* table,
-                         const DebugPrintTableOptions& options = {});
+  static void PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options = {});
   static void PrintStyleGraph(ResourceTable* table,
                               const ResourceName& target_style);
   static void DumpHex(const void* data, size_t len);
-  static void DumpXml(xml::XmlResource* doc);
-  static std::string ToString(xml::XmlResource* doc);
+  static void DumpXml(const xml::XmlResource& doc);
 };
 
 }  // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 6fac6e9..24187d9 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -704,8 +704,15 @@
       } else {
         if (type != ResourceType::kString && util::StartsWith(str, "res/")) {
           // This must be a FileReference.
-          return util::make_unique<FileReference>(dst_pool->MakeRef(
-              str, StringPool::Context(StringPool::Context::kHighPriority, config)));
+          std::unique_ptr<FileReference> file_ref =
+              util::make_unique<FileReference>(dst_pool->MakeRef(
+                  str, StringPool::Context(StringPool::Context::kHighPriority, config)));
+          if (util::EndsWith(*file_ref->path, ".xml")) {
+            file_ref->type = ResourceFile::Type::kBinaryXml;
+          } else if (util::EndsWith(*file_ref->path, ".png")) {
+            file_ref->type = ResourceFile::Type::kPng;
+          }
+          return std::move(file_ref);
         }
 
         // There are no styles associated with this string, so treat it as a simple string.
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index 174b7f6..7e7c86d 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -269,8 +269,19 @@
 
 // A value that is a reference to an external entity, like an XML file or a PNG.
 message FileReference {
+  enum Type {
+    UNKNOWN = 0;
+    PNG = 1;
+    BINARY_XML = 2;
+    PROTO_XML = 3;
+  }
+
   // Path to a file within the APK (typically res/type-config/entry.ext).
   string path = 1;
+
+  // The type of file this path points to. For UAM bundle, this cannot be
+  // BINARY_XML.
+  Type type = 2;
 }
 
 // A value that represents a primitive data type (float, int, boolean, etc.).
diff --git a/tools/aapt2/ResourcesInternal.proto b/tools/aapt2/ResourcesInternal.proto
index c16cf65..520b242 100644
--- a/tools/aapt2/ResourcesInternal.proto
+++ b/tools/aapt2/ResourcesInternal.proto
@@ -41,14 +41,8 @@
   // The configuration for which the resource is defined.
   aapt.pb.Configuration config = 2;
 
-  enum Type {
-    UNKNOWN = 0;
-    PNG = 1;
-    BINARY_XML = 2;
-    PROTO_XML = 3;
-  }
-
-  Type type = 3;
+  // The type of the file.
+  aapt.pb.FileReference.Type type = 3;
 
   // The filesystem path to where the source file originated.
   // Mainly used to display helpful error messages.
@@ -56,7 +50,4 @@
 
   // Any symbols this file auto-generates/exports (eg. @+id/foo in an XML file).
   repeated Symbol exported_symbol = 5;
-
-  // If this is a compiled XML file, this is the root node.
-  aapt.pb.XmlNode xml_root = 6;
 }
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 7be6dc0..090c3fb 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -65,21 +65,19 @@
   std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
   if (zip) {
     ResourceTable table;
-    if (io::IFile* file = zip->FindFile("resources.arsc.flat")) {
+    if (io::IFile* file = zip->FindFile("resources.pb")) {
       std::unique_ptr<io::IData> data = file->OpenAsData();
       if (data == nullptr) {
-        context->GetDiagnostics()->Error(DiagMessage(file_path)
-                                         << "failed to open resources.arsc.flat");
+        context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
         return false;
       }
 
       pb::ResourceTable pb_table;
       if (!pb_table.ParseFromArray(data->data(), data->size())) {
-        context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.arsc.flat");
+        context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.pb");
         return false;
       }
 
-      ResourceTable table;
       if (!DeserializeTableFromPb(pb_table, &table, &err)) {
         context->GetDiagnostics()->Error(DiagMessage(file_path)
                                          << "failed to parse table: " << err);
@@ -98,7 +96,7 @@
       }
     }
 
-    Debug::PrintTable(&table, print_options);
+    Debug::PrintTable(table, print_options);
     return true;
   }
 
@@ -137,7 +135,7 @@
         continue;
       }
 
-      Debug::PrintTable(&table, print_options);
+      Debug::PrintTable(table, print_options);
     } else if (entry->Type() == ContainerEntryType::kResFile) {
       pb::internal::CompiledFile pb_compiled_file;
       off64_t offset;
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index baee9c9..55a4c43 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -71,6 +71,14 @@
 
 namespace aapt {
 
+constexpr static const char kApkResourceTablePath[] = "resources.arsc";
+constexpr static const char kProtoResourceTablePath[] = "resources.pb";
+
+enum class OutputFormat {
+  kApk,
+  kProto,
+};
+
 struct LinkOptions {
   std::string output_path;
   std::string manifest_path;
@@ -79,6 +87,7 @@
   std::vector<std::string> assets_dirs;
   bool output_to_directory = false;
   bool auto_add_overlay = false;
+  OutputFormat output_format = OutputFormat::kApk;
 
   // Java/Proguard options.
   Maybe<std::string> generate_java_class_path;
@@ -253,26 +262,39 @@
   IAaptContext* context_;
 };
 
-static bool FlattenXml(IAaptContext* context, xml::XmlResource* xml_res, const StringPiece& path,
-                       bool keep_raw_values, bool utf16, IArchiveWriter* writer) {
-  BigBuffer buffer(1024);
-  XmlFlattenerOptions options = {};
-  options.keep_raw_values = keep_raw_values;
-  options.use_utf16 = utf16;
-  XmlFlattener flattener(&buffer, options);
-  if (!flattener.Consume(context, xml_res)) {
-    return false;
-  }
-
+static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res,
+                       const StringPiece& path, bool keep_raw_values, bool utf16,
+                       OutputFormat format, IArchiveWriter* writer) {
   if (context->IsVerbose()) {
     context->GetDiagnostics()->Note(DiagMessage(path) << "writing to archive (keep_raw_values="
                                                       << (keep_raw_values ? "true" : "false")
                                                       << ")");
   }
 
-  io::BigBufferInputStream input_stream(&buffer);
-  return io::CopyInputStreamToArchive(context, &input_stream, path.to_string(),
-                                      ArchiveEntry::kCompress, writer);
+  switch (format) {
+    case OutputFormat::kApk: {
+      BigBuffer buffer(1024);
+      XmlFlattenerOptions options = {};
+      options.keep_raw_values = keep_raw_values;
+      options.use_utf16 = utf16;
+      XmlFlattener flattener(&buffer, options);
+      if (!flattener.Consume(context, &xml_res)) {
+        return false;
+      }
+
+      io::BigBufferInputStream input_stream(&buffer);
+      return io::CopyInputStreamToArchive(context, &input_stream, path.to_string(),
+                                          ArchiveEntry::kCompress, writer);
+    } break;
+
+    case OutputFormat::kProto: {
+      pb::XmlNode pb_node;
+      SerializeXmlResourceToPb(xml_res, &pb_node);
+      return io::CopyProtoToArchive(context, &pb_node, path.to_string(), ArchiveEntry::kCompress,
+                                    writer);
+    } break;
+  }
+  return false;
 }
 
 static std::unique_ptr<ResourceTable> LoadTableFromPb(const Source& source, const void* data,
@@ -310,6 +332,7 @@
   bool keep_raw_values = false;
   bool do_not_compress_anything = false;
   bool update_proguard_spec = false;
+  OutputFormat output_format = OutputFormat::kApk;
   std::unordered_set<std::string> extensions_to_not_compress;
 };
 
@@ -627,8 +650,9 @@
                 return false;
               }
             }
-            error |= !FlattenXml(context_, doc.get(), dst_path, options_.keep_raw_values,
-                                 false /*utf16*/, archive_writer);
+
+            error |= !FlattenXml(context_, *doc, dst_path, options_.keep_raw_values,
+                                 false /*utf16*/, options_.output_format, archive_writer);
           }
         } else {
           error |= !io::CopyFileToArchive(context_, file_op.file_to_copy, file_op.dst_path,
@@ -927,23 +951,29 @@
     }
   }
 
-  bool FlattenTable(ResourceTable* table, IArchiveWriter* writer) {
-    BigBuffer buffer(1024);
-    TableFlattener flattener(options_.table_flattener_options, &buffer);
-    if (!flattener.Consume(context_, table)) {
-      context_->GetDiagnostics()->Error(DiagMessage() << "failed to flatten resource table");
-      return false;
+  bool FlattenTable(ResourceTable* table, OutputFormat format, IArchiveWriter* writer) {
+    switch (format) {
+      case OutputFormat::kApk: {
+        BigBuffer buffer(1024);
+        TableFlattener flattener(options_.table_flattener_options, &buffer);
+        if (!flattener.Consume(context_, table)) {
+          context_->GetDiagnostics()->Error(DiagMessage() << "failed to flatten resource table");
+          return false;
+        }
+
+        io::BigBufferInputStream input_stream(&buffer);
+        return io::CopyInputStreamToArchive(context_, &input_stream, kApkResourceTablePath,
+                                            ArchiveEntry::kAlign, writer);
+      } break;
+
+      case OutputFormat::kProto: {
+        pb::ResourceTable pb_table;
+        SerializeTableToPb(*table, &pb_table);
+        return io::CopyProtoToArchive(context_, &pb_table, kProtoResourceTablePath,
+                                      ArchiveEntry::kCompress, writer);
+      } break;
     }
-
-    io::BigBufferInputStream input_stream(&buffer);
-    return io::CopyInputStreamToArchive(context_, &input_stream, "resources.arsc",
-                                        ArchiveEntry::kAlign, writer);
-  }
-
-  bool FlattenTableToPb(ResourceTable* table, IArchiveWriter* writer) {
-    pb::ResourceTable pb_table;
-    SerializeTableToPb(*table, &pb_table);
-    return io::CopyProtoToArchive(context_, &pb_table, "resources.arsc.flat", 0, writer);
+    return false;
   }
 
   bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate,
@@ -1172,7 +1202,7 @@
   }
 
   std::unique_ptr<ResourceTable> LoadTablePbFromCollection(io::IFileCollection* collection) {
-    io::IFile* file = collection->FindFile("resources.arsc.flat");
+    io::IFile* file = collection->FindFile(kProtoResourceTablePath);
     if (!file) {
       return {};
     }
@@ -1466,15 +1496,13 @@
     return true;
   }
 
-  /**
-   * Writes the AndroidManifest, ResourceTable, and all XML files referenced by
-   * the ResourceTable to the IArchiveWriter.
-   */
+  // Writes the AndroidManifest, ResourceTable, and all XML files referenced by the ResourceTable
+  // to the IArchiveWriter.
   bool WriteApk(IArchiveWriter* writer, proguard::KeepSet* keep_set, xml::XmlResource* manifest,
                 ResourceTable* table) {
     const bool keep_raw_values = context_->GetPackageType() == PackageType::kStaticLib;
-    bool result = FlattenXml(context_, manifest, "AndroidManifest.xml", keep_raw_values,
-                             true /*utf16*/, writer);
+    bool result = FlattenXml(context_, *manifest, "AndroidManifest.xml", keep_raw_values,
+                             true /*utf16*/, options_.output_format, writer);
     if (!result) {
       return false;
     }
@@ -1489,6 +1517,7 @@
     file_flattener_options.no_xml_namespaces = options_.no_xml_namespaces;
     file_flattener_options.update_proguard_spec =
         static_cast<bool>(options_.generate_proguard_rules_path);
+    file_flattener_options.output_format = options_.output_format;
 
     ResourceFileFlattener file_flattener(file_flattener_options, context_, keep_set);
 
@@ -1497,15 +1526,9 @@
       return false;
     }
 
-    if (context_->GetPackageType() == PackageType::kStaticLib) {
-      if (!FlattenTableToPb(table, writer)) {
-        return false;
-      }
-    } else {
-      if (!FlattenTable(table, writer)) {
-        context_->GetDiagnostics()->Error(DiagMessage() << "failed to write resources.arsc");
-        return false;
-      }
+    if (!FlattenTable(table, options_.output_format, writer)) {
+      context_->GetDiagnostics()->Error(DiagMessage() << "failed to write resource table");
+      return false;
     }
     return true;
   }
@@ -1869,6 +1892,7 @@
   bool verbose = false;
   bool shared_lib = false;
   bool static_lib = false;
+  bool proto_format = false;
   Maybe<std::string> stable_id_file_path;
   std::vector<std::string> split_args;
   Flags flags =
@@ -1949,6 +1973,10 @@
           .OptionalSwitch("--shared-lib", "Generates a shared Android runtime library.",
                           &shared_lib)
           .OptionalSwitch("--static-lib", "Generate a static Android library.", &static_lib)
+          .OptionalSwitch("--proto-format",
+                          "Generates compiled resources in Protobuf format.\n"
+                          "Suitable as input to the bundle tool for generating an App Bundle.",
+                          &proto_format)
           .OptionalSwitch("--no-static-lib-packages",
                           "Merge all library resources under the app's package.",
                           &options.no_static_lib_packages)
@@ -2035,21 +2063,25 @@
     context.SetVerbose(verbose);
   }
 
-  if (shared_lib && static_lib) {
-    context.GetDiagnostics()->Error(DiagMessage()
-                                    << "only one of --shared-lib and --static-lib can be defined");
+  if (int{shared_lib} + int{static_lib} + int{proto_format} > 1) {
+    context.GetDiagnostics()->Error(
+        DiagMessage()
+        << "only one of --shared-lib, --static-lib, or --proto_format can be defined");
     return 1;
   }
 
+  // The default build type.
+  context.SetPackageType(PackageType::kApp);
+  context.SetPackageId(kAppPackageId);
+
   if (shared_lib) {
     context.SetPackageType(PackageType::kSharedLib);
     context.SetPackageId(0x00);
   } else if (static_lib) {
     context.SetPackageType(PackageType::kStaticLib);
-    context.SetPackageId(kAppPackageId);
-  } else {
-    context.SetPackageType(PackageType::kApp);
-    context.SetPackageId(kAppPackageId);
+    options.output_format = OutputFormat::kProto;
+  } else if (proto_format) {
+    options.output_format = OutputFormat::kProto;
   }
 
   if (package_id) {
diff --git a/tools/aapt2/format/Container_test.cpp b/tools/aapt2/format/Container_test.cpp
index 3d064d0..dc81a3a 100644
--- a/tools/aapt2/format/Container_test.cpp
+++ b/tools/aapt2/format/Container_test.cpp
@@ -43,7 +43,7 @@
 
     pb::internal::CompiledFile pb_compiled_file;
     pb_compiled_file.set_resource_name("android:layout/main.xml");
-    pb_compiled_file.set_type(pb::internal::CompiledFile::Type::CompiledFile_Type_PROTO_XML);
+    pb_compiled_file.set_type(pb::FileReference::PROTO_XML);
     pb_compiled_file.set_source_path("res/layout/main.xml");
     io::StringInputStream data(expected_data);
     ASSERT_TRUE(writer.AddResFileEntry(pb_compiled_file, &data));
diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp
index 2456c3d..345cc95 100644
--- a/tools/aapt2/format/binary/XmlFlattener.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener.cpp
@@ -56,9 +56,9 @@
   return false;
 }
 
-class XmlFlattenerVisitor : public xml::Visitor {
+class XmlFlattenerVisitor : public xml::ConstVisitor {
  public:
-  using xml::Visitor::Visit;
+  using xml::ConstVisitor::Visit;
 
   StringPool pool;
   std::map<uint8_t, StringPool> package_pools;
@@ -74,7 +74,7 @@
       : buffer_(buffer), options_(options) {
   }
 
-  void Visit(xml::Text* node) override {
+  void Visit(const xml::Text* node) override {
     if (util::TrimWhitespace(node->text).empty()) {
       // Skip whitespace only text nodes.
       return;
@@ -95,7 +95,7 @@
     writer.Finish();
   }
 
-  void Visit(xml::Element* node) override {
+  void Visit(const xml::Element* node) override {
     for (const xml::NamespaceDecl& decl : node->namespace_decls) {
       // Skip dedicated tools namespace.
       if (decl.uri != xml::kSchemaTools) {
@@ -125,7 +125,7 @@
       start_writer.Finish();
     }
 
-    xml::Visitor::Visit(node);
+    xml::ConstVisitor::Visit(node);
 
     {
       ChunkWriter end_writer(buffer_);
@@ -182,12 +182,13 @@
     writer.Finish();
   }
 
-  void WriteAttributes(xml::Element* node, ResXMLTree_attrExt* flat_elem, ChunkWriter* writer) {
+  void WriteAttributes(const xml::Element* node, ResXMLTree_attrExt* flat_elem,
+                       ChunkWriter* writer) {
     filtered_attrs_.clear();
     filtered_attrs_.reserve(node->attributes.size());
 
     // Filter the attributes.
-    for (xml::Attribute& attr : node->attributes) {
+    for (const xml::Attribute& attr : node->attributes) {
       if (attr.namespace_uri != xml::kSchemaTools) {
         filtered_attrs_.push_back(&attr);
       }
@@ -282,12 +283,12 @@
   XmlFlattenerOptions options_;
 
   // Scratch vector to filter attributes. We avoid allocations making this a member.
-  std::vector<xml::Attribute*> filtered_attrs_;
+  std::vector<const xml::Attribute*> filtered_attrs_;
 };
 
 }  // namespace
 
-bool XmlFlattener::Flatten(IAaptContext* context, xml::Node* node) {
+bool XmlFlattener::Flatten(IAaptContext* context, const xml::Node* node) {
   BigBuffer node_buffer(1024);
   XmlFlattenerVisitor visitor(&node_buffer, options_);
   node->Accept(&visitor);
@@ -341,7 +342,7 @@
   return true;
 }
 
-bool XmlFlattener::Consume(IAaptContext* context, xml::XmlResource* resource) {
+bool XmlFlattener::Consume(IAaptContext* context, const xml::XmlResource* resource) {
   if (!resource->root) {
     return false;
   }
diff --git a/tools/aapt2/format/binary/XmlFlattener.h b/tools/aapt2/format/binary/XmlFlattener.h
index 8db2281..1f9e777 100644
--- a/tools/aapt2/format/binary/XmlFlattener.h
+++ b/tools/aapt2/format/binary/XmlFlattener.h
@@ -34,18 +34,18 @@
   bool use_utf16 = false;
 };
 
-class XmlFlattener : public IXmlResourceConsumer {
+class XmlFlattener {
  public:
   XmlFlattener(BigBuffer* buffer, XmlFlattenerOptions options)
       : buffer_(buffer), options_(options) {
   }
 
-  bool Consume(IAaptContext* context, xml::XmlResource* resource) override;
+  bool Consume(IAaptContext* context, const xml::XmlResource* resource);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(XmlFlattener);
 
-  bool Flatten(IAaptContext* context, xml::Node* node);
+  bool Flatten(IAaptContext* context, const xml::Node* node);
 
   BigBuffer* buffer_;
   XmlFlattenerOptions options_;
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index c722307..86bd865 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -390,8 +390,15 @@
     }
 
     ResourceTableType* type = pkg->FindOrCreateType(*res_type);
+    if (pb_type.has_type_id()) {
+      type->id = static_cast<uint8_t>(pb_type.type_id().id());
+    }
+
     for (const pb::Entry& pb_entry : pb_type.entry()) {
       ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name());
+      if (pb_entry.has_entry_id()) {
+        entry->id = static_cast<uint16_t>(pb_entry.entry_id().id());
+      }
 
       // Deserialize the symbol status (public/private with source and comments).
       if (pb_entry.has_symbol_status()) {
@@ -405,21 +412,11 @@
 
         const SymbolState visibility = DeserializeVisibilityFromPb(pb_status.visibility());
         entry->symbol_status.state = visibility;
-
         if (visibility == SymbolState::kPublic) {
-          // This is a public symbol, we must encode the ID now if there is one.
-          if (pb_entry.has_entry_id()) {
-            entry->id = static_cast<uint16_t>(pb_entry.entry_id().id());
-          }
-
-          if (type->symbol_status.state != SymbolState::kPublic) {
-            // If the type has not been made public, do so now.
-            type->symbol_status.state = SymbolState::kPublic;
-            if (pb_type.has_type_id()) {
-              type->id = static_cast<uint8_t>(pb_type.type_id().id());
-            }
-          }
+          // Propagate the public visibility up to the Type.
+          type->symbol_status.state = SymbolState::kPublic;
         } else if (visibility == SymbolState::kPrivate) {
+          // Only propagate if no previous state was assigned.
           if (type->symbol_status.state == SymbolState::kUndefined) {
             type->symbol_status.state = SymbolState::kPrivate;
           }
@@ -484,15 +481,14 @@
   return true;
 }
 
-static ResourceFile::Type DeserializeCompiledFileType(
-    const pb::internal::CompiledFile::Type& pb_type) {
-  switch (pb_type) {
-    case pb::internal::CompiledFile::Type::CompiledFile_Type_PNG:
-      return ResourceFile::Type::kPng;
-    case pb::internal::CompiledFile::Type::CompiledFile_Type_BINARY_XML:
+static ResourceFile::Type DeserializeFileReferenceTypeFromPb(const pb::FileReference::Type& type) {
+  switch (type) {
+    case pb::FileReference::BINARY_XML:
       return ResourceFile::Type::kBinaryXml;
-    case pb::internal::CompiledFile::Type::CompiledFile_Type_PROTO_XML:
+    case pb::FileReference::PROTO_XML:
       return ResourceFile::Type::kProtoXml;
+    case pb::FileReference::PNG:
+      return ResourceFile::Type::kPng;
     default:
       return ResourceFile::Type::kUnknown;
   }
@@ -510,7 +506,7 @@
 
   out_file->name = name_ref.ToResourceName();
   out_file->source.path = pb_file.source_path();
-  out_file->type = DeserializeCompiledFileType(pb_file.type());
+  out_file->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
 
   std::string config_error;
   if (!DeserializeConfigFromPb(pb_file.config(), &out_file->config, &config_error)) {
@@ -773,8 +769,12 @@
     } break;
 
     case pb::Item::kFile: {
-      return util::make_unique<FileReference>(value_pool->MakeRef(
-          pb_item.file().path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
+      const pb::FileReference& pb_file = pb_item.file();
+      std::unique_ptr<FileReference> file_ref =
+          util::make_unique<FileReference>(value_pool->MakeRef(
+              pb_file.path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
+      file_ref->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
+      return std::move(file_ref);
     } break;
 
     default:
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index a75bbc7..1d184fe 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -361,6 +361,19 @@
   return pb::Plural_Arity_OTHER;
 }
 
+static pb::FileReference::Type SerializeFileReferenceTypeToPb(const ResourceFile::Type& type) {
+  switch (type) {
+    case ResourceFile::Type::kBinaryXml:
+      return pb::FileReference::BINARY_XML;
+    case ResourceFile::Type::kProtoXml:
+      return pb::FileReference::PROTO_XML;
+    case ResourceFile::Type::kPng:
+      return pb::FileReference::PNG;
+    default:
+      return pb::FileReference::UNKNOWN;
+  }
+}
+
 namespace {
 
 class ValueSerializer : public ConstValueVisitor {
@@ -395,7 +408,9 @@
   }
 
   void Visit(const FileReference* file) override {
-    out_value_->mutable_item()->mutable_file()->set_path(*file->path);
+    pb::FileReference* pb_file = out_value_->mutable_item()->mutable_file();
+    pb_file->set_path(*file->path);
+    pb_file->set_type(SerializeFileReferenceTypeToPb(file->type));
   }
 
   void Visit(const Id* /*id*/) override {
@@ -507,23 +522,10 @@
   out_item->MergeFrom(value.item());
 }
 
-static pb::internal::CompiledFile::Type SerializeCompiledFileType(const ResourceFile::Type& type) {
-  switch (type) {
-    case ResourceFile::Type::kPng:
-      return pb::internal::CompiledFile::Type::CompiledFile_Type_PNG;
-    case ResourceFile::Type::kBinaryXml:
-      return pb::internal::CompiledFile::Type::CompiledFile_Type_BINARY_XML;
-    case ResourceFile::Type::kProtoXml:
-      return pb::internal::CompiledFile::Type::CompiledFile_Type_PROTO_XML;
-    default:
-      return pb::internal::CompiledFile::Type::CompiledFile_Type_UNKNOWN;
-  }
-}
-
 void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
   out_file->set_resource_name(file.name.ToString());
   out_file->set_source_path(file.source.path);
-  out_file->set_type(SerializeCompiledFileType(file.type));
+  out_file->set_type(SerializeFileReferenceTypeToPb(file.type));
   SerializeConfig(file.config, out_file->mutable_config());
 
   for (const SourcedResourceName& exported : file.exported_symbols) {