/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "testing.h" #include #include #include "android-base/file.h" #include "android-base/stringprintf.h" #include "android-base/strings.h" #include "base/file_utils.h" #include "base/globals.h" #include "base/os.h" namespace art { namespace testing { std::string GetAndroidBuildTop() { CHECK(IsHost()); std::string android_build_top; // Look at how we were invoked to find the expected directory. std::string argv; if (android::base::ReadFileToString("/proc/self/cmdline", &argv)) { // /proc/self/cmdline is the programs 'argv' with elements delimited by '\0'. std::filesystem::path path(argv.substr(0, argv.find('\0'))); path = std::filesystem::absolute(path); // Walk up until we find the one of the well-known directories. for (; path.parent_path() != path; path = path.parent_path()) { // We are running tests from out/host/linux-x86 on developer machine. if (path.filename() == std::filesystem::path("linux-x86")) { android_build_top = path.parent_path().parent_path().parent_path(); break; } // We are running tests from testcases (extracted from zip) on tradefed. // The first path is for remote runs and the second path for local runs. if (path.filename() == std::filesystem::path("testcases") || path.filename().string().starts_with("host_testcases")) { android_build_top = path.append("art_common"); break; } } } CHECK(!android_build_top.empty()); // Check that the expected directory matches the environment variable. const char* android_build_top_from_env = getenv("ANDROID_BUILD_TOP"); android_build_top = std::filesystem::path(android_build_top).string(); CHECK(!android_build_top.empty()); if (android_build_top_from_env != nullptr) { if (std::filesystem::weakly_canonical(android_build_top).string() != std::filesystem::weakly_canonical(android_build_top_from_env).string()) { android_build_top = android_build_top_from_env; } } else { setenv("ANDROID_BUILD_TOP", android_build_top.c_str(), /*overwrite=*/0); } if (android_build_top.back() != '/') { android_build_top += '/'; } return android_build_top; } std::string GetAndroidHostOut() { CHECK(IsHost()); // Check that the expected directory matches the environment variable. // ANDROID_HOST_OUT is set by envsetup or unset and is the full path to host binaries/libs const char* android_host_out_from_env = getenv("ANDROID_HOST_OUT"); // OUT_DIR is a user-settable ENV_VAR that controls where soong puts build artifacts. It can // either be relative to ANDROID_BUILD_TOP or a concrete path. const char* android_out_dir = getenv("OUT_DIR"); // Take account of OUT_DIR setting. if (android_out_dir == nullptr) { android_out_dir = "out"; } std::string android_host_out; if (android_out_dir[0] == '/') { android_host_out = (std::filesystem::path(android_out_dir) / "host" / "linux-x86").string(); } else { android_host_out = (std::filesystem::path(GetAndroidBuildTop()) / android_out_dir / "host" / "linux-x86") .string(); } std::filesystem::path expected(android_host_out); if (android_host_out_from_env != nullptr) { std::filesystem::path from_env(std::filesystem::weakly_canonical(android_host_out_from_env)); if (std::filesystem::weakly_canonical(expected).string() != from_env.string()) { LOG(WARNING) << "Execution path (" << expected << ") not below ANDROID_HOST_OUT (" << from_env << ")! Using env-var."; expected = from_env; } } else { setenv("ANDROID_HOST_OUT", android_host_out.c_str(), /*overwrite=*/0); } return expected.string(); } std::string GetHostBootClasspathInstallRoot() { CHECK(IsHost()); std::string build_install_root = GetAndroidHostOut() + "/testcases/art_common/out/host/linux-x86"; // Look for the `apex` subdirectory as a discriminator to check the location. if (OS::DirectoryExists((build_install_root + "/apex").c_str())) { // This is the path where "m art-host-tests" installs support files for host // tests, so use it when the tests are run in a build tree (which is the // case when testing locally). return build_install_root; } if (OS::DirectoryExists((GetAndroidRoot() + "/apex").c_str())) { // This is the location for host tests in CI when the files are unzipped // from art-host-tests.zip. return GetAndroidRoot(); } LOG(ERROR) << "Neither location has a boot classpath (forgot \"m art-host-tests\"?): " << build_install_root << " or " << GetAndroidRoot(); return ""; } static std::string GetDexFileName(const std::string& jar_prefix, const std::string& prefix) { const char* apexPath = (jar_prefix == "conscrypt") ? kAndroidConscryptApexDefaultPath : (jar_prefix == "core-icu4j" ? kAndroidI18nApexDefaultPath : kAndroidArtApexDefaultPath); return android::base::StringPrintf( "%s%s/javalib/%s.jar", prefix.c_str(), apexPath, jar_prefix.c_str()); } static std::vector GetPrefixedDexFileNames(const std::string& prefix, const std::vector& modules) { std::vector result; result.reserve(modules.size()); for (const std::string& module : modules) { result.push_back(GetDexFileName(module, prefix)); } return result; } std::vector GetLibCoreModuleNames(bool core_only) { // Note: This must start with the CORE_IMG_JARS in Android.common_path.mk because that's what we // use for compiling the boot.art image. It may contain additional modules from TEST_CORE_JARS. // CORE_IMG_JARS modules. std::vector modules{ "core-oj", "core-libart", "okhttp", "bouncycastle", "apache-xml", }; // Additional modules. if (!core_only) { modules.push_back("core-icu4j"); modules.push_back("conscrypt"); } return modules; } std::vector GetLibCoreDexFileNames(const std::vector& modules) { return GetPrefixedDexFileNames(kIsTargetBuild ? "" : GetHostBootClasspathInstallRoot(), modules); } std::vector GetLibCoreDexFileNames(const std::string& prefix, bool core_only) { std::vector modules = GetLibCoreModuleNames(core_only); return GetPrefixedDexFileNames(prefix, modules); } std::vector GetLibCoreDexLocations(const std::vector& modules) { std::string prefix = ""; if (IsHost()) { std::string android_root = GetAndroidRoot(); std::string build_top = GetAndroidBuildTop(); CHECK(android_root.starts_with(build_top)) << " android_root=" << android_root << " build_top=" << build_top; prefix = android_root.substr(build_top.size()); } return GetPrefixedDexFileNames(prefix, modules); } std::vector GetLibCoreDexLocations(bool core_only) { std::vector modules = GetLibCoreModuleNames(core_only); return GetLibCoreDexLocations(modules); } std::string GetClassPathOption(const char* option, const std::vector& class_path) { return option + android::base::Join(class_path, ':'); } } // namespace testing } // namespace art