summaryrefslogtreecommitdiff
path: root/libartbase/base/file_utils.cc
diff options
context:
space:
mode:
author Roland Levillain <rpl@google.com> 2019-04-05 18:53:58 +0100
committer Roland Levillain <rpl@google.com> 2019-04-12 10:59:09 +0000
commit50eec3d36d805874e1611e9df829b1313ef711bb (patch)
tree014971f52c9e955c686fab58a6420c5d37bec233 /libartbase/base/file_utils.cc
parentdc2fbb6d9834733214c6cdedbacd526603754a74 (diff)
Adjust the dladdr-based introspection logic used in art::GetAndroidRootSafe.
This logic originally assumed that the libartbase library linked into the current binary was always located in a directory within the Android Root. This is no longer true on target since libartbase moved to the Runtime APEX; therefore we now only use that logic on host in art::GetAndroidRootSafe. Eventually we should be able to use this logic on target to find the Android Runtime Root (in art::GetAndroidRuntimeRootSafe), as libartbase is installed in the Runtime APEX. However, this is not always true at the moment, as ART gtests still install another copy of libartbase in /system/lib(64) (the Android Root) on target. Also improve the documentation of methods `art::GetAndroidRoot(Safe)` and `art::GetAndroidRuntimeRoot(Safe)`. Test: m test-art-host-gtest-file_utils_test Bug: 121117762 Bug: 129534335 Change-Id: I835207110dae0a550c06ac98ed4915241cc61c6f
Diffstat (limited to 'libartbase/base/file_utils.cc')
-rw-r--r--libartbase/base/file_utils.cc144
1 files changed, 115 insertions, 29 deletions
diff --git a/libartbase/base/file_utils.cc b/libartbase/base/file_utils.cc
index 5a112c7f9e..1a1310342c 100644
--- a/libartbase/base/file_utils.cc
+++ b/libartbase/base/file_utils.cc
@@ -94,9 +94,37 @@ bool ReadFileToString(const std::string& file_name, std::string* result) {
}
}
+// Get the "root" directory containing the "lib" directory where this instance
+// of the libartbase library (which contains `GetRootContainingLibartbase`) is
+// located:
+// - on host this "root" is normally the Android Root (e.g. something like
+// "$ANDROID_BUILD_TOP/out/host/linux-x86/");
+// - on target this "root" is normally the Android Runtime Root
+// ("/apex/com.android.runtime").
+// Return the empty string if that directory cannot be found or if this code is
+// run on Windows or macOS.
+static std::string GetRootContainingLibartbase() {
+#if !defined( _WIN32) && !defined(__APPLE__)
+ // Check where libartbase is from, and derive from there.
+ Dl_info info;
+ if (dladdr(reinterpret_cast<const void*>(&GetRootContainingLibartbase), /* out */ &info) != 0) {
+ // Make a duplicate of the fname so dirname can modify it.
+ UniqueCPtr<char> fname(strdup(info.dli_fname));
+
+ char* dir1 = dirname(fname.get()); // This is the lib directory.
+ char* dir2 = dirname(dir1); // This is the "root" directory.
+ if (OS::DirectoryExists(dir2)) {
+ std::string tmp = dir2; // Make a copy here so that fname can be released.
+ return tmp;
+ }
+ }
+#endif
+ return "";
+}
+
std::string GetAndroidRootSafe(std::string* error_msg) {
#ifdef _WIN32
- UNUSED(kAndroidRootEnvVar, kAndroidRootDefaultPath);
+ UNUSED(kAndroidRootEnvVar, kAndroidRootDefaultPath, GetRootContainingLibartbase);
*error_msg = "GetAndroidRootSafe unsupported for Windows.";
return "";
#else
@@ -104,33 +132,30 @@ std::string GetAndroidRootSafe(std::string* error_msg) {
const char* android_root_from_env = getenv(kAndroidRootEnvVar);
if (android_root_from_env != nullptr) {
if (!OS::DirectoryExists(android_root_from_env)) {
- *error_msg = StringPrintf("Failed to find ANDROID_ROOT directory %s", android_root_from_env);
+ *error_msg =
+ StringPrintf("Failed to find %s directory %s", kAndroidRootEnvVar, android_root_from_env);
return "";
}
return android_root_from_env;
}
- // Check where libart is from, and derive from there. Only do this for non-Mac.
-#ifndef __APPLE__
- {
- Dl_info info;
- if (dladdr(reinterpret_cast<const void*>(&GetAndroidRootSafe), /* out */ &info) != 0) {
- // Make a duplicate of the fname so dirname can modify it.
- UniqueCPtr<char> fname(strdup(info.dli_fname));
-
- char* dir1 = dirname(fname.get()); // This is the lib directory.
- char* dir2 = dirname(dir1); // This is the "system" directory.
- if (OS::DirectoryExists(dir2)) {
- std::string tmp = dir2; // Make a copy here so that fname can be released.
- return tmp;
- }
+ // On host, libartbase is currently installed in "$ANDROID_ROOT/lib"
+ // (e.g. something like "$ANDROID_BUILD_TOP/out/host/linux-x86/lib". Use this
+ // information to infer the location of the Android Root (on host only).
+ //
+ // Note that this could change in the future, if we decided to install ART
+ // artifacts in a different location, e.g. within a "Runtime APEX" directory.
+ if (!kIsTargetBuild) {
+ std::string root_containing_libartbase = GetRootContainingLibartbase();
+ if (!root_containing_libartbase.empty()) {
+ return root_containing_libartbase;
}
}
-#endif
// Try the default path.
if (!OS::DirectoryExists(kAndroidRootDefaultPath)) {
- *error_msg = StringPrintf("Failed to find directory %s", kAndroidRootDefaultPath);
+ *error_msg =
+ StringPrintf("Failed to find default Android Root directory %s", kAndroidRootDefaultPath);
return "";
}
return kAndroidRootDefaultPath;
@@ -162,7 +187,7 @@ static const char* GetAndroidDirSafe(const char* env_var,
}
}
if (must_exist && !OS::DirectoryExists(android_dir)) {
- *error_msg = StringPrintf("Failed to find %s directory %s", env_var, android_dir);
+ *error_msg = StringPrintf("Failed to find directory %s", android_dir);
return nullptr;
}
return android_dir;
@@ -179,16 +204,71 @@ static const char* GetAndroidDir(const char* env_var, const char* default_dir) {
}
}
+static std::string GetAndroidRuntimeRootSafe(bool must_exist, /*out*/ std::string* error_msg) {
+#ifdef _WIN32
+ UNUSED(kAndroidRuntimeRootEnvVar, kAndroidRuntimeApexDefaultPath, GetRootContainingLibartbase);
+ UNUSED(must_exist);
+ *error_msg = "GetAndroidRuntimeRootSafe unsupported for Windows.";
+ return "";
+#else
+ // Prefer ANDROID_RUNTIME_ROOT if it's set.
+ const char* android_runtime_root_from_env = getenv(kAndroidRuntimeRootEnvVar);
+ if (android_runtime_root_from_env != nullptr) {
+ if (must_exist && !OS::DirectoryExists(android_runtime_root_from_env)) {
+ *error_msg = StringPrintf("Failed to find %s directory %s",
+ kAndroidRuntimeRootEnvVar,
+ android_runtime_root_from_env);
+ return "";
+ }
+ return android_runtime_root_from_env;
+ }
+
+ // On target, libartbase is normally installed in
+ // "$ANDROID_RUNTIME_ROOT/lib(64)" (e.g. something like
+ // "/apex/com.android.runtime/lib(64)". Use this information to infer the
+ // location of the Android Runtime Root (on target only).
+ if (kIsTargetBuild) {
+ // *However*, a copy of libartbase may still be installed outside the
+ // Android Runtime Root on some occasions, as ART target gtests install
+ // their binaries and their dependencies under the Android Root, i.e.
+ // "/system" (see b/129534335). For that reason, we cannot reliably use
+ // `GetRootContainingLibartbase` to find the Android Runtime Root.
+ // (Note that this is not really a problem in practice, as Android Q devices
+ // define ANDROID_RUNTIME_ROOT in their default environment, and will
+ // instead use the logic above anyway.)
+ //
+ // TODO(b/129534335): Re-enable this logic when the only instance of
+ // libartbase on target is the one from the Runtime APEX.
+ if ((false)) {
+ std::string root_containing_libartbase = GetRootContainingLibartbase();
+ if (!root_containing_libartbase.empty()) {
+ return root_containing_libartbase;
+ }
+ }
+ }
+
+ // Try the default path.
+ if (must_exist && !OS::DirectoryExists(kAndroidRuntimeApexDefaultPath)) {
+ *error_msg = StringPrintf("Failed to find default Android Runtime Root directory %s",
+ kAndroidRuntimeApexDefaultPath);
+ return "";
+ }
+ return kAndroidRuntimeApexDefaultPath;
+#endif
+}
+
std::string GetAndroidRuntimeRootSafe(std::string* error_msg) {
- const char* android_dir = GetAndroidDirSafe(kAndroidRuntimeRootEnvVar,
- kAndroidRuntimeApexDefaultPath,
- /* must_exist= */ true,
- error_msg);
- return (android_dir != nullptr) ? android_dir : "";
+ return GetAndroidRuntimeRootSafe(/* must_exist= */ true, error_msg);
}
std::string GetAndroidRuntimeRoot() {
- return GetAndroidDir(kAndroidRuntimeRootEnvVar, kAndroidRuntimeApexDefaultPath);
+ std::string error_msg;
+ std::string ret = GetAndroidRuntimeRootSafe(&error_msg);
+ if (ret.empty()) {
+ LOG(FATAL) << error_msg;
+ UNREACHABLE();
+ }
+ return ret;
}
std::string GetAndroidDataSafe(std::string* error_msg) {
@@ -309,6 +389,16 @@ std::string ReplaceFileExtension(const std::string& filename, const std::string&
}
}
+bool LocationIsOnRuntimeModule(const char* full_path) {
+ std::string unused_error_msg;
+ std::string module_path =
+ GetAndroidRuntimeRootSafe(/* must_exist= */ kIsTargetBuild, &unused_error_msg);
+ if (module_path.empty()) {
+ return false;
+ }
+ return android::base::StartsWith(full_path, module_path);
+}
+
static bool StartsWithSlash(const char* str) {
DCHECK(str != nullptr);
return str[0] == '/';
@@ -364,10 +454,6 @@ bool LocationIsOnSystemFramework(const char* full_path) {
/* subdir= */ "/framework");
}
-bool LocationIsOnRuntimeModule(const char* full_path) {
- return IsLocationOnModule(full_path, kAndroidRuntimeRootEnvVar, kAndroidRuntimeApexDefaultPath);
-}
-
bool LocationIsOnConscryptModule(const char* full_path) {
return IsLocationOnModule(
full_path, kAndroidConscryptRootEnvVar, kAndroidConscryptApexDefaultPath);