Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ef0fa9d authored by Adam Lesinski's avatar Adam Lesinski
Browse files

AAPT2: Fixup namespace implementation

A few pieces were missing in the namespace mangling implementation.
Namespace aware libraries now work, along with R class generation.

Bug: 64706588
Test: make AaptTestNamespace_App
Change-Id: I12f78d6aa909e782c0faf7ceaa36058f2e6c864a
parent 668feb25
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -69,8 +69,7 @@ class NameMangler {
   * The mangled name should contain symbols that are illegal to define in XML,
   * so that there will never be name mangling collisions.
   */
  static std::string MangleEntry(const std::string& package,
                                 const std::string& name) {
  static std::string MangleEntry(const std::string& package, const std::string& name) {
    return package + "$" + name;
  }

@@ -86,8 +85,8 @@ class NameMangler {
    }

    out_package->assign(out_name->data(), pivot);
    out_name->assign(out_name->data() + pivot + 1,
                     out_name->size() - (pivot + 1));
    std::string new_name = out_name->substr(pivot + 1);
    *out_name = std::move(new_name);
    return true;
  }

+11 −18
Original line number Diff line number Diff line
@@ -605,7 +605,7 @@ std::unique_ptr<Item> ResourceParser::ParseXml(xml::XmlPullParser* parser,
  if (processed_item) {
    // Fix up the reference.
    if (Reference* ref = ValueCast<Reference>(processed_item.get())) {
      TransformReferenceFromNamespace(parser, "", ref);
      ResolvePackage(parser, ref);
    }
    return processed_item;
  }
@@ -1074,15 +1074,13 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
    return false;
  }

  Maybe<Reference> maybe_key =
      ResourceUtils::ParseXmlAttributeName(maybe_name.value());
  Maybe<Reference> maybe_key = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
  if (!maybe_key) {
    diag_->Error(DiagMessage(source) << "invalid attribute name '"
                                     << maybe_name.value() << "'");
    diag_->Error(DiagMessage(source) << "invalid attribute name '" << maybe_name.value() << "'");
    return false;
  }

  TransformReferenceFromNamespace(parser, "", &maybe_key.value());
  ResolvePackage(parser, &maybe_key.value());
  maybe_key.value().SetSource(source);

  std::unique_ptr<Item> value = ParseXml(parser, 0, kAllowRawString);
@@ -1091,8 +1089,7 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
    return false;
  }

  style->entries.push_back(
      Style::Entry{std::move(maybe_key.value()), std::move(value)});
  style->entries.push_back(Style::Entry{std::move(maybe_key.value()), std::move(value)});
  return true;
}

@@ -1104,21 +1101,18 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par

  Maybe<StringPiece> maybe_parent = xml::FindAttribute(parser, "parent");
  if (maybe_parent) {
    // If the parent is empty, we don't have a parent, but we also don't infer
    // either.
    // If the parent is empty, we don't have a parent, but we also don't infer either.
    if (!maybe_parent.value().empty()) {
      std::string err_str;
      style->parent = ResourceUtils::ParseStyleParentReference(
          maybe_parent.value(), &err_str);
      style->parent = ResourceUtils::ParseStyleParentReference(maybe_parent.value(), &err_str);
      if (!style->parent) {
        diag_->Error(DiagMessage(out_resource->source) << err_str);
        return false;
      }

      // Transform the namespace prefix to the actual package name, and mark the
      // reference as
      // Transform the namespace prefix to the actual package name, and mark the reference as
      // private if appropriate.
      TransformReferenceFromNamespace(parser, "", &style->parent.value());
      ResolvePackage(parser, &style->parent.value());
    }

  } else {
@@ -1127,8 +1121,7 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par
    size_t pos = style_name.find_last_of(u'.');
    if (pos != std::string::npos) {
      style->parent_inferred = true;
      style->parent = Reference(
          ResourceName({}, ResourceType::kStyle, style_name.substr(0, pos)));
      style->parent = Reference(ResourceName({}, ResourceType::kStyle, style_name.substr(0, pos)));
    }
  }

@@ -1373,7 +1366,7 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
      }

      Reference& child_ref = maybe_ref.value();
      xml::TransformReferenceFromNamespace(parser, "", &child_ref);
      xml::ResolvePackage(parser, &child_ref);

      // Create the ParsedResource that will add the attribute to the table.
      ParsedResource child_resource;
+100 −79
Original line number Diff line number Diff line
@@ -457,7 +457,8 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer
  const Source& src = doc->file.source;

  if (context_->IsVerbose()) {
    context_->GetDiagnostics()->Note(DiagMessage() << "linking " << src.path);
    context_->GetDiagnostics()->Note(DiagMessage()
                                     << "linking " << src.path << " (" << doc->file.name << ")");
  }

  XmlReferenceLinker xml_linker;
@@ -505,6 +506,8 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
  std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> config_sorted_files;

  for (auto& pkg : table->packages) {
    CHECK(!pkg->name.empty()) << "Packages must have names when being linked";

    for (auto& type : pkg->types) {
      // Sort by config and name, so that we get better locality in the zip file.
      config_sorted_files.clear();
@@ -701,7 +704,7 @@ class LinkCommand {
        util::make_unique<AssetManagerSymbolSource>();
    for (const std::string& path : options_.include_paths) {
      if (context_->IsVerbose()) {
        context_->GetDiagnostics()->Note(DiagMessage(path) << "loading include path");
        context_->GetDiagnostics()->Note(DiagMessage() << "including " << path);
      }

      // First try to load the file as a static lib.
@@ -819,11 +822,9 @@ class LinkCommand {
    return app_info;
  }

  /**
   * Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked.
   * Postcondition: ResourceTable has only one package left. All others are
   * stripped, or there is an error and false is returned.
   */
  // Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked.
  // Postcondition: ResourceTable has only one package left. All others are
  // stripped, or there is an error and false is returned.
  bool VerifyNoExternalPackages() {
    auto is_ext_package_func = [&](const std::unique_ptr<ResourceTablePackage>& pkg) -> bool {
      return context_->GetCompilationPackage() != pkg->name || !pkg->id ||
@@ -965,7 +966,91 @@ class LinkCommand {
      context_->GetDiagnostics()->Error(DiagMessage()
                                        << "failed writing to '" << out_path
                                        << "': " << android::base::SystemErrorCodeToString(errno));
      return false;
    }
    return true;
  }

  bool GenerateJavaClasses() {
    // The set of packages whose R class to call in the main classes onResourcesLoaded callback.
    std::vector<std::string> packages_to_callback;

    JavaClassGeneratorOptions template_options;
    template_options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
    template_options.javadoc_annotations = options_.javadoc_annotations;

    if (context_->GetPackageType() == PackageType::kStaticLib || options_.generate_non_final_ids) {
      template_options.use_final = false;
    }

    if (context_->GetPackageType() == PackageType::kSharedLib) {
      template_options.use_final = false;
      template_options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{};
    }

    const StringPiece actual_package = context_->GetCompilationPackage();
    StringPiece output_package = context_->GetCompilationPackage();
    if (options_.custom_java_package) {
      // Override the output java package to the custom one.
      output_package = options_.custom_java_package.value();
    }

    // Generate the private symbols if required.
    if (options_.private_symbols) {
      packages_to_callback.push_back(options_.private_symbols.value());

      // If we defined a private symbols package, we only emit Public symbols
      // to the original package, and private and public symbols to the private package.
      JavaClassGeneratorOptions options = template_options;
      options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
      if (!WriteJavaFile(&final_table_, actual_package, options_.private_symbols.value(),
                         options)) {
        return false;
      }
    }

    // Generate copies of the original package R class but with different package names.
    // This is to support non-namespaced builds.
    for (const std::string& extra_package : options_.extra_java_packages) {
      packages_to_callback.push_back(extra_package);

      JavaClassGeneratorOptions options = template_options;
      options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
      if (!WriteJavaFile(&final_table_, actual_package, extra_package, options)) {
        return false;
      }
    }

    // Generate R classes for each package that was merged (static library).
    // Use the actual package's resources only.
    for (const std::string& package : table_merger_->merged_packages()) {
      packages_to_callback.push_back(package);

      JavaClassGeneratorOptions options = template_options;
      options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
      if (!WriteJavaFile(&final_table_, package, package, options)) {
        return false;
      }
    }

    // Generate the main public R class.
    JavaClassGeneratorOptions options = template_options;

    // Only generate public symbols if we have a private package.
    if (options_.private_symbols) {
      options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
    }

    if (options.rewrite_callback_options) {
      options.rewrite_callback_options.value().packages_to_callback =
          std::move(packages_to_callback);
    }

    if (!WriteJavaFile(&final_table_, actual_package, output_package, options,
                       options_.generate_text_symbols_path)) {
      return false;
    }

    return true;
  }

@@ -1097,15 +1182,17 @@ class LinkCommand {

    bool result;
    if (options_.no_static_lib_packages) {
      // Merge all resources as if they were in the compilation package. This is
      // the old behavior of aapt.
      // Merge all resources as if they were in the compilation package. This is the old behavior
      // of aapt.

      // Add the package to the set of --extra-packages so we emit an R.java for
      // each library package.
      // Add the package to the set of --extra-packages so we emit an R.java for each library
      // package.
      if (!pkg->name.empty()) {
        options_.extra_java_packages.insert(pkg->name);
      }

      // Clear the package name, so as to make the resources look like they are coming from the
      // local package.
      pkg->name = "";
      if (override) {
        result = table_merger_->MergeOverlay(Source(input), table.get(), collection.get());
@@ -1673,8 +1760,7 @@ class LinkCommand {

    bool error = false;
    {
      // AndroidManifest.xml has no resource name, but the CallSite is built
      // from the name
      // AndroidManifest.xml has no resource name, but the CallSite is built from the name
      // (aka, which package the AndroidManifest.xml is coming from).
      // So we give it a package name so it can see local resources.
      manifest_xml->file.name.package = context_->GetCompilationPackage();
@@ -1727,72 +1813,7 @@ class LinkCommand {
    }

    if (options_.generate_java_class_path) {
      // The set of packages whose R class to call in the main classes
      // onResourcesLoaded callback.
      std::vector<std::string> packages_to_callback;

      JavaClassGeneratorOptions template_options;
      template_options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
      template_options.javadoc_annotations = options_.javadoc_annotations;

      if (context_->GetPackageType() == PackageType::kStaticLib ||
          options_.generate_non_final_ids) {
        template_options.use_final = false;
      }

      if (context_->GetPackageType() == PackageType::kSharedLib) {
        template_options.use_final = false;
        template_options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{};
      }

      const StringPiece actual_package = context_->GetCompilationPackage();
      StringPiece output_package = context_->GetCompilationPackage();
      if (options_.custom_java_package) {
        // Override the output java package to the custom one.
        output_package = options_.custom_java_package.value();
      }

      // Generate the private symbols if required.
      if (options_.private_symbols) {
        packages_to_callback.push_back(options_.private_symbols.value());

        // If we defined a private symbols package, we only emit Public symbols
        // to the original package, and private and public symbols to the
        // private package.
        JavaClassGeneratorOptions options = template_options;
        options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
        if (!WriteJavaFile(&final_table_, actual_package, options_.private_symbols.value(),
                           options)) {
          return 1;
        }
      }

      // Generate all the symbols for all extra packages.
      for (const std::string& extra_package : options_.extra_java_packages) {
        packages_to_callback.push_back(extra_package);

        JavaClassGeneratorOptions options = template_options;
        options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
        if (!WriteJavaFile(&final_table_, actual_package, extra_package, options)) {
          return 1;
        }
      }

      // Generate the main public R class.
      JavaClassGeneratorOptions options = template_options;

      // Only generate public symbols if we have a private package.
      if (options_.private_symbols) {
        options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
      }

      if (options.rewrite_callback_options) {
        options.rewrite_callback_options.value().packages_to_callback =
            std::move(packages_to_callback);
      }

      if (!WriteJavaFile(&final_table_, actual_package, output_package, options,
                         options_.generate_text_symbols_path)) {
      if (!GenerateJavaClasses()) {
        return 1;
      }
    }
+3 −3
Original line number Diff line number Diff line
@@ -69,10 +69,10 @@ class Visitor : public xml::PackageAwareVisitor {
    // Use an empty string for the compilation package because we don't want to default to
    // the local package if the user specified name="style" or something. This should just
    // be the default namespace.
    Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package, {});
    Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package);
    if (!maybe_pkg) {
      context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid namespace prefix '"
                                                         << name.package << "'");
      context_->GetDiagnostics()->Error(DiagMessage(src)
                                        << "invalid namespace prefix '" << name.package << "'");
      error_ = true;
      return;
    }
+2 −0
Original line number Diff line number Diff line
LOCAL_PATH := $(call my-dir)
include $(call all-makefiles-under,$(LOCAL_PATH))
Loading