Try harder to support gtests with non-standard build config

One is able to set the location android builds to using the OUT_DIR
environment variable and android supports having this be a symlink.
Our gtests, however would fall over if you tried to run it using the
'm test-art-host-gtest' with anything other than OUT_DIR=out and out
as a real directory. If you broke this convention many tests would
fail because they are unable to find ANDROID_HOST_OUT.

This makes everything a little nicer by making common_art_test try to
figure out what ANDROID_HOST_OUT should be using the test binaries
location and commandline.

Test: export OUT_DIR=fast-out
      ln -s /some/other/path fast-out
      . build/envsetup.sh
      lunch aosp_walleye-userdebug
      m test-art-host-gtest

Change-Id: I67cdba43ef3050afe394cd03b14a43d309d020e2
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 1611426..568689d 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -222,6 +222,12 @@
     header_libs: [
         "libnativehelper_header_only",
     ],
+    static: {
+        whole_static_libs: ["libc++fs"],
+    },
+    shared: {
+        static_libs: ["libc++fs"],
+    },
 }
 
 art_cc_test {
diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc
index ccaa90f..3545916 100644
--- a/libartbase/base/common_art_test.cc
+++ b/libartbase/base/common_art_test.cc
@@ -20,7 +20,11 @@
 #include <dlfcn.h>
 #include <fcntl.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <cstdio>
+#include <filesystem>
+#include "android-base/file.h"
+#include "android-base/logging.h"
 #include "nativehelper/scoped_local_ref.h"
 
 #include "android-base/stringprintf.h"
@@ -126,11 +130,33 @@
     if (android_host_out_from_env == nullptr) {
       // Not set by build server, so default to the usual value of
       // ANDROID_HOST_OUT.
-      std::string android_host_out = android_build_top_from_env;
+      std::string android_host_out;
 #if defined(__linux__)
-      android_host_out += "/out/host/linux-x86";
+      // Fallback
+      android_host_out = std::string(android_build_top_from_env) + "/out/host/linux-x86";
+      // Look at how we were invoked
+      std::string argv;
+      if (android::base::ReadFileToString("/proc/self/cmdline", &argv)) {
+        // /proc/self/cmdline is the programs 'argv' with elements delimited by '\0'.
+        std::string cmdpath(argv.substr(0, argv.find('\0')));
+        std::filesystem::path path(cmdpath);
+        // If the path is relative then prepend the android_build_top_from_env to it
+        if (path.is_relative()) {
+          path = std::filesystem::path(android_build_top_from_env).append(cmdpath);
+          DCHECK(path.is_absolute()) << path;
+        }
+        // Walk up until we find the linux-x86 directory or we hit the root directory.
+        while (path.has_parent_path() && path.parent_path() != path &&
+               path.filename() != std::filesystem::path("linux-x86")) {
+          path = path.parent_path();
+        }
+        // If we found a linux-x86 directory path is now android_host_out
+        if (path.filename() == std::filesystem::path("linux-x86")) {
+          android_host_out = path.string();
+        }
+      }
 #elif defined(__APPLE__)
-      android_host_out += "/out/host/darwin-x86";
+      android_host_out = std::string(android_build_top_from_env) + "/out/host/darwin-x86";
 #else
 #error unsupported OS
 #endif