Merge "linker: add android_get_exported_namespace"
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index c0dcd5d..668f008 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -47,4 +47,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 3b797f7..8270fe9 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.c b/libdl/libdl.c
index f7ca3f1..1a65b67 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -94,6 +94,9 @@
 __attribute__((__weak__, visibility("default")))
 void __loader_android_dlwarning(void* obj, void (*f)(void*, const char*));
 
+__attribute__((__weak__, visibility("default")))
+struct android_namespace_t* __loader_android_get_exported_namespace(const char* name);
+
 // Proxy calls to bionic loader
 void* dlopen(const char* filename, int flag) {
   const void* caller_addr = __builtin_return_address(0);
@@ -187,3 +190,7 @@
 void android_dlwarning(void* obj, void (*f)(void*, const char*)) {
   __loader_android_dlwarning(obj, f);
 }
+
+struct android_namespace_t* android_get_exported_namespace(const char* name) {
+  return __loader_android_get_exported_namespace(name);
+}
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 245e016..a4c6483 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 3b797f7..8270fe9 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 3b797f7..8270fe9 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 3b797f7..8270fe9 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 3b797f7..8270fe9 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -46,4 +46,5 @@
     android_init_anonymous_namespace;
     android_create_namespace;
     android_link_namespaces;
+    android_get_exported_namespace;
 } LIBC_N;
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 0bc5a31..6195d40 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -214,6 +214,10 @@
   return success;
 }
 
+android_namespace_t* __android_get_exported_namespace(const char* name) {
+  return get_exported_namespace(name);
+}
+
 void __cfi_fail(uint64_t CallSiteTypeId, void* Ptr, void *DiagData, void *CallerPc) {
   CFIShadowWriter::CfiFail(CallSiteTypeId, Ptr, DiagData, CallerPc);
 }
@@ -256,9 +260,13 @@
   // 4*
   // 0000000 000111111111122222222223333 333333444444444455 555555556666666666777777777788888 888889999999999
   // 0123456 789012345678901234567890123 456789012345678901 234567890123456789012345678901234 567890123456789
-    "dlvsym\0__loader_android_dlwarning\0__loader_cfi_fail\0__loader_android_link_namespaces\0"
+    "dlvsym\0__loader_android_dlwarning\0__loader_cfi_fail\0__loader_android_link_namespaces\0__loader_androi"
+  // 5*
+  // 0000000000111111111122222 22222
+  // 0123456789012345678901234 56789
+    "d_get_exported_namespace\0"
 #if defined(__arm__)
-  // 485
+  // 525
     "__loader_dl_unwind_find_exidx\0"
 #endif
     ;
@@ -286,8 +294,9 @@
   ELFW(SYM_INITIALIZER)(407, &__android_dlwarning, 1),
   ELFW(SYM_INITIALIZER)(434, &__cfi_fail, 1),
   ELFW(SYM_INITIALIZER)(452, &__android_link_namespaces, 1),
+  ELFW(SYM_INITIALIZER)(485, &__android_get_exported_namespace, 1),
 #if defined(__arm__)
-  ELFW(SYM_INITIALIZER)(485, &__dl_unwind_find_exidx, 1),
+  ELFW(SYM_INITIALIZER)(525, &__dl_unwind_find_exidx, 1),
 #endif
 };
 
@@ -304,9 +313,9 @@
 // Note that adding any new symbols here requires stubbing them out in libdl.
 static unsigned g_libdl_buckets[1] = { 1 };
 #if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0 };
 #else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0 };
 #endif
 
 static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 11a00f7..afd990a 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -73,6 +73,7 @@
 #define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
 
 static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
+static std::unordered_map<std::string, android_namespace_t*> g_exported_namespaces;
 
 static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
 static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
@@ -3470,6 +3471,9 @@
     ns->set_permitted_paths(ns_config->permitted_paths());
 
     namespaces[ns_config->name()] = ns;
+    if (ns_config->visible()) {
+      g_exported_namespaces[ns_config->name()] = ns;
+    }
   }
 
   // 3. Establish links between namespaces
@@ -3494,3 +3498,16 @@
 
   set_application_target_sdk_version(config->target_sdk_version());
 }
+
+// This function finds a namespace exported in ld.config.txt by its name.
+// A namespace can be exported by setting .visible property to true.
+android_namespace_t* get_exported_namespace(const char* name) {
+  if (name == nullptr) {
+    return nullptr;
+  }
+  auto it = g_exported_namespaces.find(std::string(name));
+  if (it == g_exported_namespaces.end()) {
+    return nullptr;
+  }
+  return it->second;
+}
diff --git a/linker/linker.h b/linker/linker.h
index d5d4980..53dac6c 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -173,4 +173,6 @@
                      android_namespace_t* namespace_to,
                      const char* shared_lib_sonames);
 
+android_namespace_t* get_exported_namespace(const char* name);
+
 #endif
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index a12cfbe..f614ba0 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -456,6 +456,7 @@
     }
 
     ns_config->set_isolated(properties.get_bool(property_name_prefix + ".isolated"));
+    ns_config->set_visible(properties.get_bool(property_name_prefix + ".visible"));
 
     // these are affected by is_asan flag
     if (is_asan) {
diff --git a/linker/linker_config.h b/linker/linker_config.h
index 4ec8b26..6f8bffb 100644
--- a/linker/linker_config.h
+++ b/linker/linker_config.h
@@ -62,7 +62,7 @@
 class NamespaceConfig {
  public:
   explicit NamespaceConfig(const std::string& name)
-      : name_(name), isolated_(false)
+      : name_(name), isolated_(false), visible_(false)
   {}
 
   const char* name() const {
@@ -73,6 +73,10 @@
     return isolated_;
   }
 
+  bool visible() const {
+    return visible_;
+  }
+
   const std::vector<std::string>& search_paths() const {
     return search_paths_;
   }
@@ -93,6 +97,10 @@
     isolated_ = isolated;
   }
 
+  void set_visible(bool visible) {
+    visible_ = visible;
+  }
+
   void set_search_paths(std::vector<std::string>&& search_paths) {
     search_paths_ = search_paths;
   }
@@ -103,6 +111,7 @@
  private:
   const std::string name_;
   bool isolated_;
+  bool visible_;
   std::vector<std::string> search_paths_;
   std::vector<std::string> permitted_paths_;
   std::vector<NamespaceLinkConfig> namespace_links_;
diff --git a/linker/tests/linker_config_test.cpp b/linker/tests/linker_config_test.cpp
index 418cbda..5e51113 100644
--- a/linker/tests/linker_config_test.cpp
+++ b/linker/tests/linker_config_test.cpp
@@ -58,6 +58,7 @@
   "namespace.default.links = system\n"
   "namespace.default.link.system.shared_libs = libc.so:libm.so:libdl.so:libstdc++.so\n"
   "namespace.system.isolated = true\n"
+  "namespace.system.visible = true\n"
   "namespace.system.search.paths = /system/${LIB}\n"
   "namespace.system.permitted.paths = /system/${LIB}\n"
   "namespace.system.asan.search.paths = /data:/system/${LIB}\n"
@@ -137,6 +138,7 @@
   ASSERT_TRUE(default_ns_config != nullptr);
 
   ASSERT_TRUE(default_ns_config->isolated());
+  ASSERT_FALSE(default_ns_config->visible());
   ASSERT_EQ(kExpectedDefaultSearchPath, default_ns_config->search_paths());
   ASSERT_EQ(kExpectedDefaultPermittedPath, default_ns_config->permitted_paths());
 
@@ -163,6 +165,7 @@
   ASSERT_TRUE(ns_system != nullptr) << "system namespace was not found";
 
   ASSERT_TRUE(ns_system->isolated());
+  ASSERT_TRUE(ns_system->visible());
   ASSERT_EQ(kExpectedSystemSearchPath, ns_system->search_paths());
   ASSERT_EQ(kExpectedSystemPermittedPath, ns_system->permitted_paths());
 }