Merge "Add tests for pthread TLS leak."
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 846cb88..7b16cc3 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -78,19 +78,39 @@
 static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
 
 #if defined(__LP64__)
-static const char* const kSystemLibDir     = "/system/lib64";
-static const char* const kVendorLibDir     = "/vendor/lib64";
-static const char* const kAsanSystemLibDir = "/data/lib64";
-static const char* const kAsanVendorLibDir = "/data/vendor/lib64";
+static const char* const kSystemLibDir           = "/system/lib64";
+static const char* const kSystemNdkLibDir       = "/system/lib64/ndk";
+static const char* const kSystemVndkLibDir       = "/system/lib64/vndk";
+static const char* const kSystemVndkExtLibDir    = "/system/lib64/vndk-ext";
+static const char* const kVendorSpHalLibDir      = "/vendor/lib64/sameprocess";
+static const char* const kVendorLibDir           = "/vendor/lib64";
+static const char* const kAsanSystemLibDir       = "/data/lib64";
+static const char* const kAsanSystemNdkLibDir       = "/data/lib64/ndk";
+static const char* const kAsanSystemVndkLibDir       = "/data/lib64/vndk";
+static const char* const kAsanSystemVndkExtLibDir    = "/data/lib64/vndk-ext";
+static const char* const kAsanVendorSpHalLibDir      = "/data/vendor/lib64/sameprocess";
+static const char* const kAsanVendorLibDir       = "/data/vendor/lib64";
 #else
-static const char* const kSystemLibDir     = "/system/lib";
-static const char* const kVendorLibDir     = "/vendor/lib";
-static const char* const kAsanSystemLibDir = "/data/lib";
-static const char* const kAsanVendorLibDir = "/data/vendor/lib";
+static const char* const kSystemLibDir           = "/system/lib";
+static const char* const kSystemNdkLibDir       = "/system/lib/ndk";
+static const char* const kSystemVndkLibDir       = "/system/lib/vndk";
+static const char* const kSystemVndkExtLibDir    = "/system/lib/vndk-ext";
+static const char* const kVendorSpHalLibDir      = "/vendor/lib/sameprocess";
+static const char* const kVendorLibDir           = "/vendor/lib";
+static const char* const kAsanSystemLibDir       = "/data/lib";
+static const char* const kAsanSystemNdkLibDir       = "/data/lib/ndk";
+static const char* const kAsanSystemVndkLibDir       = "/data/lib/vndk";
+static const char* const kAsanSystemVndkExtLibDir    = "/data/lib/vndk-ext";
+static const char* const kAsanVendorSpHalLibDir      = "/data/vendor/lib/sameprocess";
+static const char* const kAsanVendorLibDir       = "/data/vendor/lib";
 #endif
 
 static const char* const kDefaultLdPaths[] = {
   kSystemLibDir,
+  kSystemNdkLibDir,
+  kSystemVndkExtLibDir,
+  kSystemVndkLibDir,
+  kVendorSpHalLibDir,
   kVendorLibDir,
   nullptr
 };
@@ -98,6 +118,14 @@
 static const char* const kAsanDefaultLdPaths[] = {
   kAsanSystemLibDir,
   kSystemLibDir,
+  kAsanSystemNdkLibDir,
+  kSystemNdkLibDir,
+  kAsanSystemVndkExtLibDir,
+  kSystemVndkExtLibDir,
+  kAsanSystemVndkLibDir,
+  kSystemVndkLibDir,
+  kAsanVendorSpHalLibDir,
+  kVendorSpHalLibDir,
   kAsanVendorLibDir,
   kVendorLibDir,
   nullptr
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 6601dc1..fe3a6fb 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -81,29 +81,9 @@
 
   std::string origin = dirname(get_realpath());
   // FIXME: add $LIB and $PLATFORM.
-  std::pair<std::string, std::string> substs[] = {{"ORIGIN", origin}};
+  std::vector<std::pair<std::string, std::string>> params = {{"ORIGIN", origin}};
   for (auto&& s : runpaths) {
-    size_t pos = 0;
-    while (pos < s.size()) {
-      pos = s.find("$", pos);
-      if (pos == std::string::npos) break;
-      for (const auto& subst : substs) {
-        const std::string& token = subst.first;
-        const std::string& replacement = subst.second;
-        if (s.substr(pos + 1, token.size()) == token) {
-          s.replace(pos, token.size() + 1, replacement);
-          // -1 to compensate for the ++pos below.
-          pos += replacement.size() - 1;
-          break;
-        } else if (s.substr(pos + 1, token.size() + 2) == "{" + token + "}") {
-          s.replace(pos, token.size() + 3, replacement);
-          pos += replacement.size() - 1;
-          break;
-        }
-      }
-      // Skip $ in case it did not match any of the known substitutions.
-      ++pos;
-    }
+    format_string(&s, params);
   }
 
   resolve_paths(runpaths, &dt_runpath_);
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index 6df5f6d..5bf88e7 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -36,6 +36,30 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+void format_string(std::string* str, const std::vector<std::pair<std::string, std::string>>& params) {
+  size_t pos = 0;
+  while (pos < str->size()) {
+    pos = str->find("$", pos);
+    if (pos == std::string::npos) break;
+    for (const auto& param : params) {
+      const std::string& token = param.first;
+      const std::string& replacement = param.second;
+      if (str->substr(pos + 1, token.size()) == token) {
+        str->replace(pos, token.size() + 1, replacement);
+        // -1 to compensate for the ++pos below.
+        pos += replacement.size() - 1;
+        break;
+      } else if (str->substr(pos + 1, token.size() + 2) == "{" + token + "}") {
+        str->replace(pos, token.size() + 3, replacement);
+        pos += replacement.size() - 1;
+        break;
+      }
+    }
+    // Skip $ in case it did not match any of the known substitutions.
+    ++pos;
+  }
+}
+
 std::string dirname(const char* path) {
   const char* last_slash = strrchr(path, '/');
 
diff --git a/linker/linker_utils.h b/linker/linker_utils.h
index 5881688..740d04b 100644
--- a/linker/linker_utils.h
+++ b/linker/linker_utils.h
@@ -34,6 +34,8 @@
 
 extern const char* const kZipFileSeparator;
 
+void format_string(std::string* str, const std::vector<std::pair<std::string, std::string>>& params);
+
 bool file_is_in_dir(const std::string& file, const std::string& dir);
 bool file_is_under_dir(const std::string& file, const std::string& dir);
 bool normalize_path(const char* path, std::string* normalized_path);
diff --git a/linker/tests/linker_utils_test.cpp b/linker/tests/linker_utils_test.cpp
index 0cfdf40..dce223a 100644
--- a/linker/tests/linker_utils_test.cpp
+++ b/linker/tests/linker_utils_test.cpp
@@ -34,6 +34,13 @@
 
 #include "../linker_utils.h"
 
+TEST(linker_utils, format_string) {
+  std::vector<std::pair<std::string, std::string>> params = {{ "LIB", "lib32"}, { "SDKVER", "42"}};
+  std::string str_smoke = "LIB$LIB${LIB${SDKVER}SDKVER$TEST$";
+  format_string(&str_smoke, params);
+  ASSERT_EQ("LIBlib32${LIB42SDKVER$TEST$", str_smoke);
+}
+
 TEST(linker_utils, normalize_path_smoke) {
   std::string output;
   ASSERT_TRUE(normalize_path("/../root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));