Make link creation additive. am: 7f8f6a08fa
am: 7b3c55cc1b

Change-Id: I80c1c9a2693de22e0508f94a5035dd7a9ca820d1
diff --git a/contents/namespace/art.cc b/contents/namespace/art.cc
index 0f18dca..d2f60c3 100644
--- a/contents/namespace/art.cc
+++ b/contents/namespace/art.cc
@@ -37,10 +37,9 @@
   // /system/framework and /data.
   // TODO(b/130340935): Use a dynamically created linker namespace similar to
   // classloader-namespace for oat files, and tighten this up.
-  ns.CreateLink(ctx.IsVendorSection() ? "system" : "default",
-                /*allow_all_shared_libs=*/true);
+  ns.GetLink(ctx.IsVendorSection() ? "system" : "default").AllowAllSharedLibs();
 
-  ns.CreateLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
+  ns.GetLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
 
   return ns;
 }
diff --git a/contents/namespace/conscrypt.cc b/contents/namespace/conscrypt.cc
index 4a7fac8..61d6c14 100644
--- a/contents/namespace/conscrypt.cc
+++ b/contents/namespace/conscrypt.cc
@@ -37,8 +37,8 @@
                /*is_visible=*/true);
 
   ns.AddSearchPath("/apex/com.android.conscrypt/${LIB}", AsanPath::SAME_PATH);
-  ns.CreateLink("art").AddSharedLib("libandroidio.so");
-  ns.CreateLink("default").AddSharedLib(kLibsFromDefault);
+  ns.GetLink("art").AddSharedLib("libandroidio.so");
+  ns.GetLink("default").AddSharedLib(kLibsFromDefault);
 
   return ns;
 }
diff --git a/contents/namespace/media.cc b/contents/namespace/media.cc
index 4f4ab3a..2f90493 100644
--- a/contents/namespace/media.cc
+++ b/contents/namespace/media.cc
@@ -22,6 +22,7 @@
 #include "linkerconfig/environment.h"
 
 using android::linkerconfig::modules::AsanPath;
+using android::linkerconfig::modules::Link;
 using android::linkerconfig::modules::Namespace;
 
 namespace {
@@ -63,7 +64,7 @@
   ns.AddPermittedPath("/apex/com.android.media/${LIB}/extractors",
                       AsanPath::SAME_PATH);
 
-  auto& link_to_default = ns.CreateLink("default");
+  Link& link_to_default = ns.GetLink("default");
   if (is_legacy) {
     link_to_default.AddSharedLib(kLibsFromDefaultLegacy);
   } else {
@@ -73,10 +74,10 @@
     }
   }
 
-  ns.CreateLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
+  ns.GetLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
 
   return ns;
 }
 }  // namespace contents
 }  // namespace linkerconfig
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/contents/namespace/neuralnetworks.cc b/contents/namespace/neuralnetworks.cc
index 0c2e759..c11e224 100644
--- a/contents/namespace/neuralnetworks.cc
+++ b/contents/namespace/neuralnetworks.cc
@@ -30,7 +30,7 @@
                    AsanPath::SAME_PATH);
 
   std::string link_target = ctx.IsVendorSection() ? "system" : "default";
-  ns.CreateLink(link_target)
+  ns.GetLink(link_target)
       .AddSharedLib({"libc.so",
                      "libcgrouprc.so",
                      "libdl.so",
@@ -45,4 +45,4 @@
 }
 }  // namespace contents
 }  // namespace linkerconfig
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/contents/namespace/resolv.cc b/contents/namespace/resolv.cc
index 42850de..623069e 100644
--- a/contents/namespace/resolv.cc
+++ b/contents/namespace/resolv.cc
@@ -41,11 +41,11 @@
 Namespace BuildResolvNamespace([[maybe_unused]] const Context& ctx) {
   Namespace ns("resolv", /*is_isolated=*/true, /*is_visible=*/true);
   ns.AddSearchPath("/apex/com.android.resolv/${LIB}", AsanPath::SAME_PATH);
-  ns.CreateLink("default").AddSharedLib(
+  ns.GetLink("default").AddSharedLib(
       ctx.IsSystemSection() ? kLibsFromDefault : kLibsFromUnrestrictedDefault);
 
   return ns;
 }
 }  // namespace contents
 }  // namespace linkerconfig
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/contents/namespace/rs.cc b/contents/namespace/rs.cc
index c1ddc42..ba11c5d 100644
--- a/contents/namespace/rs.cc
+++ b/contents/namespace/rs.cc
@@ -37,13 +37,13 @@
   ns.AddPermittedPath("/system/vendor/${LIB}", AsanPath::NONE);
   ns.AddPermittedPath("/data", AsanPath::SAME_PATH);
 
-  ns.CreateLink("default").AddSharedLib({"@{LLNDK_LIBRARIES}",
-                                         "@{SANITIZER_RUNTIME_LIBRARIES}",
-                                         "@{PRIVATE_LLNDK_LIBRARIES:}"});
-  ns.CreateLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
+  ns.GetLink("default").AddSharedLib({"@{LLNDK_LIBRARIES}",
+                                      "@{SANITIZER_RUNTIME_LIBRARIES}",
+                                      "@{PRIVATE_LLNDK_LIBRARIES:}"});
+  ns.GetLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
 
   return ns;
 }
 }  // namespace contents
 }  // namespace linkerconfig
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/contents/namespace/sphal.cc b/contents/namespace/sphal.cc
index 92df268..5378920 100644
--- a/contents/namespace/sphal.cc
+++ b/contents/namespace/sphal.cc
@@ -32,14 +32,14 @@
   ns.AddPermittedPath("/vendor/${LIB}", AsanPath::WITH_DATA_ASAN);
   ns.AddPermittedPath("/system/vendor/${LIB}", AsanPath::NONE);
 
-  ns.CreateLink("rs").AddSharedLib("libRS_internal.so");
-  ns.CreateLink("default").AddSharedLib(
+  ns.GetLink("rs").AddSharedLib("libRS_internal.so");
+  ns.GetLink("default").AddSharedLib(
       {"@{LLNDK_LIBRARIES:}", "@{SANITIZER_RUNTIME_LIBRARIES:}"});
-  ns.CreateLink("vndk").AddSharedLib("@{VNDK_SAMEPROCESS_LIBRARIES:}");
-  ns.CreateLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
+  ns.GetLink("vndk").AddSharedLib("@{VNDK_SAMEPROCESS_LIBRARIES:}");
+  ns.GetLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
 
   return ns;
 }
 }  // namespace contents
 }  // namespace linkerconfig
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/contents/namespace/system.cc b/contents/namespace/system.cc
index 2d92af7..44b4b97 100644
--- a/contents/namespace/system.cc
+++ b/contents/namespace/system.cc
@@ -28,15 +28,15 @@
   ns.AddSearchPath("/@{SYSTEM_EXT:system_ext}/${LIB}", AsanPath::WITH_DATA_ASAN);
   ns.AddSearchPath("/@{PRODUCT:product}/${LIB}", AsanPath::WITH_DATA_ASAN);
 
-  ns.CreateLink("art").AddSharedLib(
+  ns.GetLink("art").AddSharedLib(
       {"libdexfile_external.so",
        "libdexfile_external.so",
        "libnativebridge.so",
        "libnativehelper.so",
        "libnativeloader.so",
        "libandroidicu.so",
-       // TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are
-       // kept for app compat.
+       // TODO(b/120786417 or b/134659294): libicuuc.so
+       // and libicui18n.so are kept for app compat.
        "libicui18n.so",
        "libicuuc.so",
        "@{SANITIZER_RUNTIME_LIBRARIES}"});
diff --git a/contents/namespace/systemdefault.cc b/contents/namespace/systemdefault.cc
index d704c48..4ad2910 100644
--- a/contents/namespace/systemdefault.cc
+++ b/contents/namespace/systemdefault.cc
@@ -106,10 +106,9 @@
     BuildPermittedPath(ns);
   }
 
-  ns.CreateLink("art").AddSharedLib(is_legacy ? kLibsFromArtLegacy
-                                              : kLibsFromArt);
-  ns.CreateLink("resolv").AddSharedLib("libnetd_resolv.so");
-  ns.CreateLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
+  ns.GetLink("art").AddSharedLib(is_legacy ? kLibsFromArtLegacy : kLibsFromArt);
+  ns.GetLink("resolv").AddSharedLib("libnetd_resolv.so");
+  ns.GetLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
 
   return ns;
 }
diff --git a/contents/namespace/unrestricteddefault.cc b/contents/namespace/unrestricteddefault.cc
index d608a6d..9c7899d 100644
--- a/contents/namespace/unrestricteddefault.cc
+++ b/contents/namespace/unrestricteddefault.cc
@@ -48,9 +48,9 @@
   ns.AddSearchPath("/odm/${LIB}", AsanPath::WITH_DATA_ASAN);
   ns.AddSearchPath("/vendor/${LIB}", AsanPath::WITH_DATA_ASAN);
 
-  ns.CreateLink("art").AddSharedLib(kLibsFromArt);
-  ns.CreateLink("resolv").AddSharedLib("libnetd_resolv.so");
-  ns.CreateLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
+  ns.GetLink("art").AddSharedLib(kLibsFromArt);
+  ns.GetLink("resolv").AddSharedLib("libnetd_resolv.so");
+  ns.GetLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
 
   return ns;
 }
diff --git a/contents/namespace/vendordefault.cc b/contents/namespace/vendordefault.cc
index 43ccace..6e92ae7 100644
--- a/contents/namespace/vendordefault.cc
+++ b/contents/namespace/vendordefault.cc
@@ -40,16 +40,16 @@
   ns.AddPermittedPath("/vendor", AsanPath::WITH_DATA_ASAN);
   ns.AddPermittedPath("/system/vendor", AsanPath::NONE);
 
-  ns.CreateLink("art").AddSharedLib("@{SANITIZER_RUNTIME_LIBRARIES}");
-  ns.CreateLink("system").AddSharedLib(
+  ns.GetLink("art").AddSharedLib("@{SANITIZER_RUNTIME_LIBRARIES}");
+  ns.GetLink("system").AddSharedLib(
       {"@{LLNDK_LIBRARIES}", "@{SANITIZER_RUNTIME_LIBRARIES}"});
-  ns.CreateLink("vndk").AddSharedLib(
+  ns.GetLink("vndk").AddSharedLib(
       {"@{VNDK_SAMEPROCESS_LIBRARIES}", "@{VNDK_CORE_LIBRARIES}"});
   if (android::linkerconfig::modules::IsVndkInSystemNamespace()) {
-    ns.CreateLink("vndk_in_system")
+    ns.GetLink("vndk_in_system")
         .AddSharedLib("@{VNDK_USING_CORE_VARIANT_LIBRARIES}");
   }
-  ns.CreateLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
+  ns.GetLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
 
   return ns;
 }
diff --git a/contents/namespace/vndk.cc b/contents/namespace/vndk.cc
index 71108ea..f43409e 100644
--- a/contents/namespace/vndk.cc
+++ b/contents/namespace/vndk.cc
@@ -53,22 +53,22 @@
                         AsanPath::WITH_DATA_ASAN);
   }
 
-  ns.CreateLink(is_system_section ? "default" : "system")
+  ns.GetLink(is_system_section ? "default" : "system")
       .AddSharedLib({"@{LLNDK_LIBRARIES}", "@{SANITIZER_RUNTIME_LIBRARIES}"});
-  ns.CreateLink("art").AddSharedLib("@{SANITIZER_RUNTIME_LIBRARIES}");
+  ns.GetLink("art").AddSharedLib("@{SANITIZER_RUNTIME_LIBRARIES}");
 
   if (is_system_section) {
-    ns.CreateLink("sphal", true);
+    ns.GetLink("sphal").AllowAllSharedLibs();
   } else {
-    ns.CreateLink("default", true);
+    ns.GetLink("default").AllowAllSharedLibs();
 
     if (android::linkerconfig::modules::IsVndkInSystemNamespace()) {
-      ns.CreateLink("vndk_in_system")
+      ns.GetLink("vndk_in_system")
           .AddSharedLib("@{VNDK_USING_CORE_VARIANT_LIBRARIES}");
     }
   }
 
-  ns.CreateLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
+  ns.GetLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
 
   return ns;
 }
diff --git a/contents/namespace/vndkinsystem.cc b/contents/namespace/vndkinsystem.cc
index 21e2bd5..b8c5ae6 100644
--- a/contents/namespace/vndkinsystem.cc
+++ b/contents/namespace/vndkinsystem.cc
@@ -36,11 +36,11 @@
     ns.AddWhitelisted("@{VNDK_USING_CORE_VARIANT_LIBRARIES}");
   }
 
-  ns.CreateLink("system").AddSharedLib(
+  ns.GetLink("system").AddSharedLib(
       {"@{LLNDK_LIBRARIES}", "@{SANITIZER_RUNTIME_LIBRARIES}"});
-  ns.CreateLink("vndk", true);
-  ns.CreateLink("art").AddSharedLib("@{SANITIZER_RUNTIME_LIBRARIES}");
-  ns.CreateLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
+  ns.GetLink("vndk").AllowAllSharedLibs();
+  ns.GetLink("art").AddSharedLib("@{SANITIZER_RUNTIME_LIBRARIES}");
+  ns.GetLink("neuralnetworks").AddSharedLib("libneuralnetworks.so");
 
   return ns;
 }
diff --git a/modules/include/linkerconfig/link.h b/modules/include/linkerconfig/link.h
index 25d9dd4..13c4093 100644
--- a/modules/include/linkerconfig/link.h
+++ b/modules/include/linkerconfig/link.h
@@ -27,40 +27,36 @@
 namespace modules {
 class Link {
  public:
-  Link(std::string origin_namespace, std::string target_namespace,
-       bool allow_all_shared_libs = false)
+  Link(std::string origin_namespace, std::string target_namespace)
       : origin_namespace_(std::move(origin_namespace)),
-        target_namespace_(std::move(target_namespace)),
-        allow_all_shared_libs_(allow_all_shared_libs) {
+        target_namespace_(std::move(target_namespace)) {
+    allow_all_shared_libs_ = false;
   }
   Link(const Link&) = delete;
   Link(Link&&) = default;
 
   template <typename T, typename... Args>
   void AddSharedLib(T&& lib_name, Args&&... lib_names);
-  void AddSharedLib(std::vector<std::string> lib_names);
+  void AddSharedLib(const std::vector<std::string>& lib_names);
+  void AllowAllSharedLibs();
   void WriteConfig(ConfigWriter& writer);
 
  private:
   const std::string origin_namespace_;
   const std::string target_namespace_;
-  const bool allow_all_shared_libs_;
   std::vector<std::string> shared_libs_;
+  bool allow_all_shared_libs_;
 };
 
 template <typename T, typename... Args>
 void Link::AddSharedLib(T&& lib_name, Args&&... lib_names) {
-  if (allow_all_shared_libs_) {
-    LOG(WARNING) << "Tried to add shared libraries to link from "
-                 << origin_namespace_ << " to " << target_namespace_
-                 << "while this link is allow_all_shared_libs";
-    return;
-  }
-  shared_libs_.push_back(std::forward<T>(lib_name));
-  if constexpr (sizeof...(Args) > 0) {
-    AddSharedLib(std::forward<Args>(lib_names)...);
+  if (!allow_all_shared_libs_) {
+    shared_libs_.push_back(std::forward<T>(lib_name));
+    if constexpr (sizeof...(Args) > 0) {
+      AddSharedLib(std::forward<Args>(lib_names)...);
+    }
   }
 }
 }  // namespace modules
 }  // namespace linkerconfig
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/modules/include/linkerconfig/namespace.h b/modules/include/linkerconfig/namespace.h
index fbd6b2e..9640b57 100644
--- a/modules/include/linkerconfig/namespace.h
+++ b/modules/include/linkerconfig/namespace.h
@@ -89,8 +89,11 @@
   //    namespace.xxx.asan.permitted.paths += /system/${LIB}
   void AddPermittedPath(const std::string& path,
                         AsanPath path_from_asan = AsanPath::SAME_PATH);
-  Link& CreateLink(const std::string& target_namespace,
-                   bool allow_all_shared_libs = false);
+
+  // Returns a link from this namespace to the given one. If one already exists
+  // it is returned, otherwise one is created.
+  Link& GetLink(const std::string& target_namespace);
+
   void WriteConfig(ConfigWriter& writer);
   void AddWhitelisted(const std::string& path);
 
@@ -115,4 +118,4 @@
 };
 }  // namespace modules
 }  // namespace linkerconfig
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/modules/link.cc b/modules/link.cc
index 70a32ad..19569ae 100644
--- a/modules/link.cc
+++ b/modules/link.cc
@@ -19,26 +19,40 @@
 namespace android {
 namespace linkerconfig {
 namespace modules {
+
+void Link::AddSharedLib(const std::vector<std::string>& lib_names) {
+  if (!allow_all_shared_libs_) {
+    shared_libs_.insert(shared_libs_.end(), lib_names.begin(), lib_names.end());
+  }
+}
+
+void Link::AllowAllSharedLibs() {
+  if (!allow_all_shared_libs_) {
+    shared_libs_.clear();
+    allow_all_shared_libs_ = true;
+  }
+}
+
 void Link::WriteConfig(ConfigWriter& writer) {
   writer.SetPrefix("namespace." + origin_namespace_ + ".link." +
                    target_namespace_);
   if (allow_all_shared_libs_) {
     writer.WriteLine(".allow_all_shared_libs = true");
-  } else {
+  } else if (!shared_libs_.empty()) {
     bool is_first = true;
 
     for (auto& lib_name : shared_libs_) {
-      writer.WriteLine(".shared_libs %s %s",
-                       is_first ? "=" : "+=", lib_name.c_str());
+      writer.WriteLine(
+          ".shared_libs %s %s", is_first ? "=" : "+=", lib_name.c_str());
       is_first = false;
     }
+  } else {
+    LOG(WARNING) << "Ignored empty shared libs link from " << origin_namespace_
+                 << " to " << target_namespace_;
   }
   writer.ResetPrefix();
 }
 
-void Link::AddSharedLib(std::vector<std::string> lib_names) {
-  shared_libs_.insert(shared_libs_.end(), lib_names.begin(), lib_names.end());
-}
 }  // namespace modules
 }  // namespace linkerconfig
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/modules/namespace.cc b/modules/namespace.cc
index bf98976..7588c84 100644
--- a/modules/namespace.cc
+++ b/modules/namespace.cc
@@ -50,17 +50,10 @@
   }
 }
 
-Link& Namespace::CreateLink(const std::string& target_namespace,
-                            bool allow_all_shared_libs) {
-  Link new_link(name_, target_namespace, allow_all_shared_libs);
-
-  if (links_.find(target_namespace) != links_.end()) {
-    LOG(INFO) << "Link to " << target_namespace
-              << " already exists. Overwriting link.";
-  }
-
-  links_.emplace(target_namespace, std::move(new_link));
-  return links_.find(target_namespace)->second;
+Link& Namespace::GetLink(const std::string& target_namespace) {
+  auto iter =
+      links_.try_emplace(target_namespace, name_, target_namespace).first;
+  return iter->second;
 }
 
 void Namespace::WriteConfig(ConfigWriter& writer) {
@@ -165,4 +158,4 @@
 }
 }  // namespace modules
 }  // namespace linkerconfig
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/modules/tests/link_test.cc b/modules/tests/link_test.cc
index a467ba4..c73e533 100644
--- a/modules/tests/link_test.cc
+++ b/modules/tests/link_test.cc
@@ -29,7 +29,8 @@
   android::linkerconfig::modules::ConfigWriter writer;
 
   auto link = std::make_shared<android::linkerconfig::modules::Link>(
-      "originalNamespace", "targetNamespace", true);
+      "originalNamespace", "targetNamespace");
+  link->AllowAllSharedLibs();
 
   link->WriteConfig(writer);
   auto config_text = writer.ToString();
@@ -49,4 +50,4 @@
   auto config_text = writer.ToString();
 
   ASSERT_EQ(config_text, kSharedLibsExpectedResult);
-}
\ No newline at end of file
+}
diff --git a/modules/tests/modules_testbase.h b/modules/tests/modules_testbase.h
index 7eca5a7..22f791a 100644
--- a/modules/tests/modules_testbase.h
+++ b/modules/tests/modules_testbase.h
@@ -36,9 +36,9 @@
                                           bool is_visible, std::string target_1,
                                           std::string target_2) {
   Namespace ns = CreateNamespaceWithPaths(name, is_isolated, is_visible);
-  auto& link = ns.CreateLink(target_1, false);
+  auto& link = ns.GetLink(target_1);
   link.AddSharedLib("lib1.so", "lib2.so", "lib3.so");
 
-  ns.CreateLink(target_2, true);
+  ns.GetLink(target_2).AllowAllSharedLibs();
   return ns;
-}
\ No newline at end of file
+}