diff options
author | 2019-04-05 18:53:58 +0100 | |
---|---|---|
committer | 2019-04-12 10:59:09 +0000 | |
commit | 50eec3d36d805874e1611e9df829b1313ef711bb (patch) | |
tree | 014971f52c9e955c686fab58a6420c5d37bec233 /libartbase/base/file_utils.cc | |
parent | dc2fbb6d9834733214c6cdedbacd526603754a74 (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.cc | 144 |
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); |