Add art::GetAndroidRuntimeRootSafe and art::GetAndroidRuntimeRoot.

Test: m test-art-host-gtest-file_utils_test
Change-Id: Ib1f188e448b46891ae6fea713a5e92f5e160f060
diff --git a/libartbase/base/file_utils.cc b/libartbase/base/file_utils.cc
index af1d2e6..3f8bf4d 100644
--- a/libartbase/base/file_utils.cc
+++ b/libartbase/base/file_utils.cc
@@ -178,6 +178,15 @@
   }
 }
 
+std::string GetAndroidRuntimeRootSafe(std::string* error_msg) {
+  const char* android_dir =
+      GetAndroidDirSafe(kAndroidRuntimeRootEnvVar, kAndroidRuntimeApexDefaultPath, error_msg);
+  return (android_dir != nullptr) ? android_dir : "";
+}
+
+std::string GetAndroidRuntimeRoot() {
+  return GetAndroidDir(kAndroidRuntimeRootEnvVar, kAndroidRuntimeApexDefaultPath);
+}
 const char* GetAndroidData() {
   return GetAndroidDir(kAndroidDataEnvVar, kAndroidDataDefaultPath);
 }
@@ -341,13 +350,10 @@
 }
 
 bool RuntimeModuleRootDistinctFromAndroidRoot() {
-  std::string error_msg;
-  std::string android_root = GetAndroidRootSafe(&error_msg);
-  const char* runtime_root =
-      GetAndroidDirSafe(kAndroidRuntimeRootEnvVar, kAndroidRuntimeApexDefaultPath, &error_msg);
-  return !android_root.empty()
-      && (runtime_root != nullptr)
-      && (android_root != std::string_view(runtime_root));
+  std::string unused_error_msg;
+  std::string android_root = GetAndroidRootSafe(&unused_error_msg);
+  std::string runtime_root = GetAndroidRuntimeRootSafe(&unused_error_msg);
+  return !android_root.empty() && !runtime_root.empty() && (android_root != runtime_root);
 }
 
 int DupCloexec(int fd) {
diff --git a/libartbase/base/file_utils.h b/libartbase/base/file_utils.h
index 1594aee..d2a0839 100644
--- a/libartbase/base/file_utils.h
+++ b/libartbase/base/file_utils.h
@@ -34,6 +34,11 @@
 // Find $ANDROID_ROOT, /system, or return an empty string.
 std::string GetAndroidRootSafe(/*out*/ std::string* error_msg);
 
+// Find $ANDROID_RUNTIME_ROOT, /apex/com.android.runtime, or abort.
+std::string GetAndroidRuntimeRoot();
+// Find $ANDROID_RUNTIME_ROOT, /apex/com.android.runtime, or return an empty string.
+std::string GetAndroidRuntimeRootSafe(/*out*/ std::string* error_msg);
+
 // Find $ANDROID_DATA, /data, or abort.
 const char* GetAndroidData();
 // Find $ANDROID_DATA, /data, or return null.
diff --git a/libartbase/base/file_utils_test.cc b/libartbase/base/file_utils_test.cc
index c917307..0a5a7a7 100644
--- a/libartbase/base/file_utils_test.cc
+++ b/libartbase/base/file_utils_test.cc
@@ -66,14 +66,14 @@
   // CommonArtTest sets ANDROID_ROOT, so expect this to be the same.
   std::string android_root = GetAndroidRootSafe(&error_msg);
   std::string android_root_env = getenv("ANDROID_ROOT");
-  EXPECT_EQ(android_root, android_root_env);
+  EXPECT_EQ(android_root, android_root_env) << error_msg;
 
   // Set ANDROID_ROOT to something else (but the directory must exist). So use dirname.
   UniqueCPtr<char> root_dup(strdup(android_root_env.c_str()));
   char* dir = dirname(root_dup.get());
   ASSERT_EQ(0, setenv("ANDROID_ROOT", dir, /* overwrite */ 1));
   std::string android_root2 = GetAndroidRootSafe(&error_msg);
-  EXPECT_STREQ(dir, android_root2.c_str());
+  EXPECT_STREQ(dir, android_root2.c_str()) << error_msg;
 
   // Set a bogus value for ANDROID_ROOT. This should be an error.
   ASSERT_EQ(0, setenv("ANDROID_ROOT", "/this/is/obviously/bogus", /* overwrite */ 1));
@@ -88,15 +88,40 @@
   UniqueCPtr<char> real_root3(realpath(android_root3.c_str(), nullptr));
 #if !defined(__BIONIC__ ) || defined(__ANDROID__)
   UniqueCPtr<char> real_root(realpath(android_root.c_str(), nullptr));
-  EXPECT_STREQ(real_root.get(), real_root3.get());
+  EXPECT_STREQ(real_root.get(), real_root3.get()) << error_msg;
 #else
-  EXPECT_STRNE(real_root3.get(), "");
+  EXPECT_STRNE(real_root3.get(), "") << error_msg;
 #endif
 
   // Reset ANDROID_ROOT, as other things may depend on it.
   ASSERT_EQ(0, setenv("ANDROID_ROOT", android_root_env.c_str(), /* overwrite */ 1));
 }
 
+TEST_F(FileUtilsTest, GetAndroidRuntimeRootSafe) {
+  std::string error_msg;
+
+  // We don't expect null returns for most cases, so don't check and let std::string crash.
+
+  // CommonArtTest sets ANDROID_RUNTIME_ROOT, so expect this to be the same.
+  std::string android_runtime_root = GetAndroidRuntimeRootSafe(&error_msg);
+  std::string android_runtime_root_env = getenv("ANDROID_RUNTIME_ROOT");
+  EXPECT_EQ(android_runtime_root, android_runtime_root_env) << error_msg;
+
+  // Set ANDROID_RUNTIME_ROOT to something else (but the directory must exist). So use dirname.
+  UniqueCPtr<char> root_dup(strdup(android_runtime_root_env.c_str()));
+  char* dir = dirname(root_dup.get());
+  ASSERT_EQ(0, setenv("ANDROID_RUNTIME_ROOT", dir, /* overwrite */ 1));
+  std::string android_runtime_root2 = GetAndroidRuntimeRootSafe(&error_msg);
+  EXPECT_STREQ(dir, android_runtime_root2.c_str()) << error_msg;
+
+  // Set a bogus value for ANDROID_RUNTIME_ROOT. This should be an error.
+  ASSERT_EQ(0, setenv("ANDROID_RUNTIME_ROOT", "/this/is/obviously/bogus", /* overwrite */ 1));
+  EXPECT_EQ(GetAndroidRuntimeRootSafe(&error_msg), "");
+
+  // Reset ANDROID_RUNTIME_ROOT, as other things may depend on it.
+  ASSERT_EQ(0, setenv("ANDROID_RUNTIME_ROOT", android_runtime_root_env.c_str(), /* overwrite */ 1));
+}
+
 TEST_F(FileUtilsTest, ReplaceFileExtension) {
   EXPECT_EQ("/directory/file.vdex", ReplaceFileExtension("/directory/file.oat", "vdex"));
   EXPECT_EQ("/.directory/file.vdex", ReplaceFileExtension("/.directory/file.oat", "vdex"));