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

Commit 9a2f6e60 authored by Ryan Mitchell's avatar Ryan Mitchell
Browse files

AAPT2: Add Proguard rules for nav fragments

Adds generation of proguard rules for fragments in res/navigation. All
android:name attributes have keep rules generated for the classes they
reference.

Bug: 69929974
Test: aapt2_tests
Change-Id: I05a87484ab357ea5629b73caad8488182f474e1f
parent 5cfe061e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -500,7 +500,7 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer
    return {};
  }

  if (options_.update_proguard_spec && !proguard::CollectProguardRules(doc, keep_set_)) {
  if (options_.update_proguard_spec && !proguard::CollectProguardRules(context_, doc, keep_set_)) {
    return {};
  }

+30 −1
Original line number Diff line number Diff line
@@ -189,6 +189,29 @@ class XmlResourceVisitor : public BaseVisitor {
  DISALLOW_COPY_AND_ASSIGN(XmlResourceVisitor);
};

class NavigationVisitor : public BaseVisitor {
 public:
  NavigationVisitor(const ResourceFile& file, KeepSet* keep_set, const std::string& package)
      : BaseVisitor(file, keep_set), package_(package) {
  }

  void Visit(xml::Element* node) override {
    const auto& attr = node->FindAttribute(xml::kSchemaAndroid, "name");
    if (attr != nullptr && !attr->value.empty()) {
      std::string name = (attr->value[0] == '.') ? package_ + attr->value : attr->value;
      if (util::IsJavaClassName(name)) {
        AddClass(node->line_number, name);
      }
    }

    BaseVisitor::Visit(node);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(NavigationVisitor);
  const std::string package_;
};

class TransitionVisitor : public BaseVisitor {
 public:
  TransitionVisitor(const ResourceFile& file, KeepSet* keep_set) : BaseVisitor(file, keep_set) {
@@ -291,7 +314,7 @@ bool CollectProguardRulesForManifest(xml::XmlResource* res, KeepSet* keep_set, b
  return false;
}

bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set) {
bool CollectProguardRules(IAaptContext* context_, xml::XmlResource* res, KeepSet* keep_set) {
  if (!res->root) {
    return false;
  }
@@ -309,6 +332,12 @@ bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set) {
      break;
    }

    case ResourceType::kNavigation: {
      NavigationVisitor visitor(res->file, keep_set, context_->GetCompilationPackage());
      res->root->Accept(&visitor);
      break;
    }

    case ResourceType::kTransition: {
      TransitionVisitor visitor(res->file, keep_set);
      res->root->Accept(&visitor);
+1 −1
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ class KeepSet {
bool CollectProguardRulesForManifest(xml::XmlResource* res, KeepSet* keep_set,
                                     bool main_dex_only = false);

bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set);
bool CollectProguardRules(IAaptContext* context, xml::XmlResource* res, KeepSet* keep_set);

bool CollectResourceReferences(IAaptContext* context, ResourceTable* table, KeepSet* keep_set);

+38 −10
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ TEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
  layout->file.name = test::ParseNameOrDie("layout/foo");

  proguard::KeepSet set;
  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));

  std::string actual = GetKeepSetString(set);

@@ -56,7 +56,7 @@ TEST(ProguardRulesTest, FragmentClassRuleIsEmitted) {
  layout->file.name = test::ParseNameOrDie("layout/foo");

  proguard::KeepSet set;
  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));

  std::string actual = GetKeepSetString(set);

@@ -72,7 +72,7 @@ TEST(ProguardRulesTest, FragmentNameAndClassRulesAreEmitted) {
  layout->file.name = test::ParseNameOrDie("layout/foo");

  proguard::KeepSet set;
  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));

  std::string actual = GetKeepSetString(set);

@@ -80,6 +80,34 @@ TEST(ProguardRulesTest, FragmentNameAndClassRulesAreEmitted) {
  EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));
}

TEST(ProguardRulesTest, NavigationFragmentNameAndClassRulesAreEmitted) {
  std::unique_ptr<IAaptContext> context = test::ContextBuilder()
      .SetCompilationPackage("com.base").Build();
  std::unique_ptr<xml::XmlResource> navigation = test::BuildXmlDom(R"(
      <navigation
          xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto">
          <custom android:id="@id/foo"
              android:name="com.package.Foo"/>
          <fragment android:id="@id/bar"
              android:name="com.package.Bar">
              <nested android:id="@id/nested"
                  android:name=".Nested"/>
          </fragment>
      </navigation>
  )");

  navigation->file.name = test::ParseNameOrDie("navigation/graph.xml");

  proguard::KeepSet set;
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), navigation.get(), &set));

  std::string actual = GetKeepSetString(set);
  EXPECT_THAT(actual, HasSubstr("com.package.Foo"));
  EXPECT_THAT(actual, HasSubstr("com.package.Bar"));
  EXPECT_THAT(actual, HasSubstr("com.base.Nested"));
}

TEST(ProguardRulesTest, CustomViewRulesAreEmitted) {
  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
  std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
@@ -89,7 +117,7 @@ TEST(ProguardRulesTest, CustomViewRulesAreEmitted) {
  layout->file.name = test::ParseNameOrDie("layout/foo");

  proguard::KeepSet set;
  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));

  std::string actual = GetKeepSetString(set);

@@ -125,8 +153,8 @@ TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) {
  ASSERT_TRUE(xml_linker.Consume(context.get(), foo_layout.get()));

  proguard::KeepSet set = proguard::KeepSet(true);
  ASSERT_TRUE(proguard::CollectProguardRules(bar_layout.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(foo_layout.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), bar_layout.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), foo_layout.get(), &set));

  std::string actual = GetKeepSetString(set);

@@ -147,7 +175,7 @@ TEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) {

  proguard::KeepSet set = proguard::KeepSet(true);
  set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name);
  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));

  std::string actual = GetKeepSetString(set);

@@ -168,7 +196,7 @@ TEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) {

  proguard::KeepSet set = proguard::KeepSet(true);
  set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name);
  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));

  std::string actual = GetKeepSetString(set);

@@ -184,7 +212,7 @@ TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
  layout->file.name = test::ParseNameOrDie("layout/foo");

  proguard::KeepSet set;
  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));

  std::string actual = GetKeepSetString(set);

@@ -203,7 +231,7 @@ TEST(ProguardRulesTest, MenuRulesAreEmitted) {
  menu->file.name = test::ParseNameOrDie("menu/foo");

  proguard::KeepSet set;
  ASSERT_TRUE(proguard::CollectProguardRules(menu.get(), &set));
  ASSERT_TRUE(proguard::CollectProguardRules(context.get(), menu.get(), &set));

  std::string actual = GetKeepSetString(set);