diff options
author | 2023-07-26 11:24:10 +0100 | |
---|---|---|
committer | 2023-07-26 16:46:11 +0000 | |
commit | 9dcdda055c4e17476b00a6929d8f114c6a686c22 (patch) | |
tree | d605b464e42779a2041e327096924487574ad5aa | |
parent | 35cca3e296346277422aaee030edced697e09319 (diff) |
Update generate-boot-image to support host.
We'll use it to generate the boot image for target Golem.
Bug: 290583827
Test: out/host/linux-x86/bin/generate-boot-image64 --output-dir=out/x86_64/target/product/armv8/apex/art_boot_images/javalib --compiler-filter=speed --use-profile=false --dex2oat-bin=out/host/linux-x86/bin/dex2oat64 --android-root=out/x86_64/target/product/armv8/system --instruction-set=arm64
Change-Id: I80f9cacb60dcc0bfa3a5d463d4ff391c1d974c42
-rw-r--r-- | libartbase/base/common_art_test.cc | 21 | ||||
-rw-r--r-- | libartbase/base/common_art_test.h | 4 | ||||
-rw-r--r-- | libartbase/base/testing.cc | 21 | ||||
-rw-r--r-- | libartbase/base/testing.h | 14 | ||||
-rw-r--r-- | test/generate-boot-image/Android.bp | 2 | ||||
-rw-r--r-- | test/generate-boot-image/generate-boot-image.cc | 178 |
6 files changed, 188 insertions, 52 deletions
diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc index e83cc0d967..0692bf8c20 100644 --- a/libartbase/base/common_art_test.cc +++ b/libartbase/base/common_art_test.cc @@ -448,28 +448,25 @@ std::vector<std::string> CommonArtTestImpl::GetLibCoreModuleNames() const { std::vector<std::string> CommonArtTestImpl::GetLibCoreDexFileNames( const std::vector<std::string>& modules) const { - return art::testing::GetLibCoreDexFileNames(modules); + return art::testing::GetLibCoreDexFileNames(kIsTargetBuild ? "" : GetAndroidRoot(), modules); } std::vector<std::string> CommonArtTestImpl::GetLibCoreDexFileNames() const { std::vector<std::string> modules = GetLibCoreModuleNames(); - return art::testing::GetLibCoreDexFileNames(modules); + return art::testing::GetLibCoreDexFileNames(kIsTargetBuild ? "" : GetAndroidRoot(), modules); } std::vector<std::string> CommonArtTestImpl::GetLibCoreDexLocations( const std::vector<std::string>& modules) const { - std::vector<std::string> result = GetLibCoreDexFileNames(modules); + std::string prefix = ""; if (IsHost()) { - // Strip the ANDROID_BUILD_TOP directory including the directory separator '/'. - std::string prefix = GetAndroidBuildTop(); - for (std::string& location : result) { - CHECK_GT(location.size(), prefix.size()); - CHECK_EQ(location.compare(0u, prefix.size(), prefix), 0) - << " prefix=" << prefix << " location=" << location; - location.erase(0u, prefix.size()); - } + std::string android_root = GetAndroidRoot(); + std::string build_top = GetAndroidBuildTop(); + CHECK(android::base::StartsWith(android_root, build_top)) + << " android_root=" << android_root << " build_top=" << build_top; + prefix = android_root.substr(build_top.size()); } - return result; + return art::testing::GetLibCoreDexFileNames(prefix, modules); } std::vector<std::string> CommonArtTestImpl::GetLibCoreDexLocations() const { diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h index 9a1e84eabf..1e39716417 100644 --- a/libartbase/base/common_art_test.h +++ b/libartbase/base/common_art_test.h @@ -157,10 +157,10 @@ class CommonArtTestImpl { // Gets the paths of the libcore dex files. std::vector<std::string> GetLibCoreDexFileNames() const; - // Gets the locations of the libcore dex files for given modules. + // Gets the on-host or on-device locations of the libcore dex files for given modules. std::vector<std::string> GetLibCoreDexLocations(const std::vector<std::string>& modules) const; - // Gets the locations of the libcore dex files. + // Gets the on-host or on-device locations of the libcore dex files. std::vector<std::string> GetLibCoreDexLocations() const; static std::string GetClassPathOption(const char* option, diff --git a/libartbase/base/testing.cc b/libartbase/base/testing.cc index c260be7bfb..3cd2836876 100644 --- a/libartbase/base/testing.cc +++ b/libartbase/base/testing.cc @@ -26,8 +26,7 @@ namespace testing { namespace { -std::string GetDexFileName(const std::string& jar_prefix, bool host) { - std::string prefix(host ? GetAndroidRoot() : ""); +std::string GetDexFileName(const std::string& jar_prefix, const std::string& prefix) { const char* apexPath = (jar_prefix == "conscrypt") ? kAndroidConscryptApexDefaultPath : @@ -60,18 +59,28 @@ std::vector<std::string> GetLibCoreModuleNames(bool core_only) { return modules; } -std::vector<std::string> GetLibCoreDexFileNames(const std::vector<std::string>& modules) { +std::vector<std::string> GetLibCoreDexFileNames(const std::string& prefix, + const std::vector<std::string>& modules) { std::vector<std::string> result; result.reserve(modules.size()); for (const std::string& module : modules) { - result.push_back(GetDexFileName(module, !kIsTargetBuild)); + result.push_back(GetDexFileName(module, prefix)); } return result; } -std::vector<std::string> GetLibCoreDexFileNames(bool core_only) { +std::vector<std::string> GetLibCoreDexFileNames(const std::string& prefix, bool core_only) { std::vector<std::string> modules = GetLibCoreModuleNames(core_only); - return GetLibCoreDexFileNames(modules); + return GetLibCoreDexFileNames(prefix, modules); +} + +std::vector<std::string> GetLibCoreDexLocations(const std::vector<std::string>& modules) { + return GetLibCoreDexFileNames(/*prefix=*/"", modules); +} + +std::vector<std::string> GetLibCoreDexLocations(bool core_only) { + std::vector<std::string> modules = GetLibCoreModuleNames(core_only); + return GetLibCoreDexLocations(modules); } } // namespace testing diff --git a/libartbase/base/testing.h b/libartbase/base/testing.h index 65bd3f6058..88d0aee6e0 100644 --- a/libartbase/base/testing.h +++ b/libartbase/base/testing.h @@ -25,16 +25,26 @@ namespace art { namespace testing { +// Note: "libcore" here means art + conscrypt + icu. + // Gets the names of the libcore modules. // If `core_only` is true, only returns the names of CORE_IMG_JARS in Android.common_path.mk. std::vector<std::string> GetLibCoreModuleNames(bool core_only = false); // Gets the paths of the libcore dex files for given modules. -std::vector<std::string> GetLibCoreDexFileNames(const std::vector<std::string>& modules); +std::vector<std::string> GetLibCoreDexFileNames(const std::string& prefix, + const std::vector<std::string>& modules); // Gets the paths of the libcore dex files. // If `core_only` is true, only returns the filenames of CORE_IMG_JARS in Android.common_path.mk. -std::vector<std::string> GetLibCoreDexFileNames(bool core_only = false); +std::vector<std::string> GetLibCoreDexFileNames(const std::string& prefix, bool core_only = false); + +// Gets the on-device locations of the libcore dex files for given modules. +std::vector<std::string> GetLibCoreDexLocations(const std::vector<std::string>& modules); + +// Gets the on-device locations of the libcore dex files. +// If `core_only` is true, only returns the filenames of CORE_IMG_JARS in Android.common_path.mk. +std::vector<std::string> GetLibCoreDexLocations(bool core_only = false); } // namespace testing } // namespace art diff --git a/test/generate-boot-image/Android.bp b/test/generate-boot-image/Android.bp index e03aade347..00ce3d328a 100644 --- a/test/generate-boot-image/Android.bp +++ b/test/generate-boot-image/Android.bp @@ -28,7 +28,7 @@ art_cc_binary { defaults: [ "art_defaults", ], - host_supported: false, + host_supported: true, compile_multilib: "both", multilib: { lib32: { diff --git a/test/generate-boot-image/generate-boot-image.cc b/test/generate-boot-image/generate-boot-image.cc index 1b3eccf0e5..64390c3163 100644 --- a/test/generate-boot-image/generate-boot-image.cc +++ b/test/generate-boot-image/generate-boot-image.cc @@ -14,31 +14,91 @@ * limitations under the License. */ -/** A commandline tool to generate a primary boot image for testing. */ - #include <sys/stat.h> #include <sysexits.h> #include <algorithm> #include <cstdlib> +#include <iostream> #include <string> #include <vector> +#include "android-base/parsebool.h" #include "android-base/stringprintf.h" #include "android-base/strings.h" #include "arch/instruction_set.h" #include "base/file_utils.h" #include "base/globals.h" +#include "base/macros.h" #include "base/os.h" #include "base/testing.h" namespace art { +namespace gbi { namespace { +using ::android::base::ConsumePrefix; +using ::android::base::ConsumeSuffix; using ::android::base::Join; +using ::android::base::ParseBool; +using ::android::base::ParseBoolResult; using ::android::base::StringPrintf; using ::art::testing::GetLibCoreDexFileNames; +using ::art::testing::GetLibCoreDexLocations; + +constexpr const char* kUsage = R"( +A commandline tool to generate a primary boot image for testing. + +Usage: generate-boot-image --output-dir=OUTPUT_DIR [OPTIONS]... + +Supported options: + --help: Print this text. + --output-dir=OUTPUT_DIR: The directory to output the boot image. Required. + --compiler-filter=COMPILER_FILTER: The compiler filter option to pass to dex2oat. Default: verify + --use-profile=true|false: If true, use a profile. Default: true + --dex2oat-bin=DEX2OAT_BIN: The path to the dex2oat binary. Required when running on host. Default + on target: /apex/com.android.art/bin/dex2oat{32,64,32d,64d} + --android-root=ANDROID_ROOT: The root directory to search for bootclasspath jars. The file + structure under the root must be in the form of: + /apex + /com.android.art + /javalib + /core-oj.jar + ... + /com.android.i18n + /javalib + ... + /com.android.conscrypt + /javalib + ... + Required when running on host. Default on target: / + --profile-file=PROFILE_FILE: The path to the profile file. Required when running on host and + --use-profile is true. Default on target: /apex/com.android.art/etc/boot-image.prof + --instruction-set=ISA: The instruction set option to pass to dex2oat. Required when running on + host. The default on target is based on the ISA of this binary. + --core-only=true|false: If true, only compile ART jars. Otherwise, also compile core-icu4j and + conscrypt. Default: true +)"; + +struct Options { + std::string output_dir = ""; + // Set the compiler filter to `verify` by default to make test preparation + // faster. + std::string compiler_filter = "verify"; + bool use_profile = true; + std::string dex2oat_bin = ""; + std::string android_root = ""; + std::string profile_file = ""; + std::string instruction_set = ""; + bool core_only = true; +}; + +[[noreturn]] void Usage(const std::string& message) { + LOG(ERROR) << message << '\n'; + std::cerr << message << "\n" << kUsage << "\n"; + exit(EX_USAGE); +} std::string GetCompilerExecutable() { std::string compiler_executable = GetArtBinDir() + "/dex2oat"; @@ -64,23 +124,30 @@ std::string BuildCommand(const std::vector<std::string>& args) { return command; } -int GenerateBootImage(const std::string& dir, const std::string& compiler_filter) { - std::string isa = GetInstructionSetString(kRuntimeISA); - +int GenerateBootImage(const Options& options) { std::vector<std::string> args; - args.push_back(GetCompilerExecutable()); + args.push_back(options.dex2oat_bin); - std::vector<std::string> dex_files = GetLibCoreDexFileNames(/*core_only=*/true); + std::vector<std::string> dex_files = + GetLibCoreDexFileNames(options.android_root, options.core_only); + std::vector<std::string> dex_locations = GetLibCoreDexLocations(options.core_only); args.push_back("--runtime-arg"); args.push_back("-Xbootclasspath:" + Join(dex_files, ":")); + args.push_back("--runtime-arg"); + args.push_back("-Xbootclasspath-locations:" + Join(dex_locations, ":")); for (const std::string& file : dex_files) { args.push_back("--dex-file=" + file); } + for (const std::string& location : dex_locations) { + args.push_back("--dex-location=" + location); + } - args.push_back("--instruction-set=" + isa); + args.push_back("--instruction-set=" + options.instruction_set); args.push_back(StringPrintf("--base=0x%08x", ART_BASE_ADDRESS)); - args.push_back("--compiler-filter=" + compiler_filter); - args.push_back(StringPrintf("--profile-file=%s/etc/boot-image.prof", GetArtRoot().c_str())); + args.push_back("--compiler-filter=" + options.compiler_filter); + if (options.use_profile) { + args.push_back("--profile-file=" + options.profile_file); + } args.push_back("--avoid-storing-invocation"); args.push_back("--generate-debug-info"); args.push_back("--generate-build-id"); @@ -88,7 +155,7 @@ int GenerateBootImage(const std::string& dir, const std::string& compiler_filter args.push_back("--strip"); args.push_back("--android-root=out/empty"); - std::string path = StringPrintf("%s/%s", dir.c_str(), isa.c_str()); + std::string path = ART_FORMAT("{}/{}", options.output_dir, options.instruction_set); if (!OS::DirectoryExists(path.c_str())) { CHECK_EQ(mkdir(path.c_str(), S_IRWXU), 0); } @@ -102,32 +169,85 @@ int GenerateBootImage(const std::string& dir, const std::string& compiler_filter return exit_code; } -} // namespace -} // namespace art - -int main(int argc, char** argv) { +int Main(int argc, char** argv) { android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); - std::string dir = ""; - // Set the compiler filter to `verify` by default to make test preparation - // faster. - std::string compiler_filter = "verify"; + Options options; for (int i = 1; i < argc; i++) { std::string_view arg{argv[i]}; - if (android::base::ConsumePrefix(&arg, "--output-dir=")) { - dir = arg; - } else if (android::base::ConsumePrefix(&arg, "--compiler-filter=")) { - compiler_filter = arg; + if (arg == "--help") { + std::cerr << kUsage << "\n"; + exit(0); + } else if (ConsumePrefix(&arg, "--output-dir=")) { + options.output_dir = arg; + } else if (ConsumePrefix(&arg, "--compiler-filter=")) { + options.compiler_filter = arg; + } else if (ConsumePrefix(&arg, "--use-profile=")) { + ParseBoolResult result = ParseBool(arg); + if (result == ParseBoolResult::kError) { + Usage(ART_FORMAT("Unrecognized --use-profile value: '{}'", arg)); + } + options.use_profile = result == ParseBoolResult::kTrue; + } else if (ConsumePrefix(&arg, "--dex2oat-bin=")) { + options.dex2oat_bin = arg; + } else if (ConsumePrefix(&arg, "--android-root=")) { + ConsumeSuffix(&arg, "/"); + options.android_root = arg; + } else if (ConsumePrefix(&arg, "--profile-file=")) { + options.profile_file = arg; + } else if (ConsumePrefix(&arg, "--instruction-set=")) { + options.instruction_set = arg; + } else if (ConsumePrefix(&arg, "--core-only=")) { + ParseBoolResult result = ParseBool(arg); + if (result == ParseBoolResult::kError) { + Usage(ART_FORMAT("Unrecognized --core-only value: '{}'", arg)); + } + options.core_only = result == ParseBoolResult::kTrue; } else { - LOG(ERROR) << android::base::StringPrintf("Unrecognized argument: '%s'", argv[i]); - exit(EX_USAGE); + Usage(ART_FORMAT("Unrecognized argument: '{}'", argv[i])); } } - if (dir.empty()) { - LOG(ERROR) << "--output-dir must be specified"; - exit(EX_USAGE); + if (options.output_dir.empty()) { + Usage("--output-dir must be specified"); } - return art::GenerateBootImage(dir, compiler_filter); + if (options.dex2oat_bin.empty()) { + if (kIsTargetBuild) { + options.dex2oat_bin = GetCompilerExecutable(); + } else { + Usage("--dex2oat-bin must be specified when running on host"); + } + } + + if (options.android_root.empty()) { + if (!kIsTargetBuild) { + Usage("--android-root must be specified when running on host"); + } + } + + if (options.use_profile && options.profile_file.empty()) { + if (kIsTargetBuild) { + options.profile_file = ART_FORMAT("{}/etc/boot-image.prof", GetArtRoot()); + } else { + Usage("--profile-file must be specified when running on host and --use-profile is true"); + } + } + + if (options.instruction_set.empty()) { + if (kIsTargetBuild) { + options.instruction_set = GetInstructionSetString(kRuntimeISA); + } else { + Usage("--instruction-set must be specified when running on host"); + } + } + + return GenerateBootImage(options); } + +} // namespace + +} // namespace gbi +} // namespace art + +int main(int argc, char** argv) { return art::gbi::Main(argc, argv); } |