diff options
42 files changed, 423 insertions, 302 deletions
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk index 96d3648ff6..03e68ae93c 100644 --- a/build/Android.common_path.mk +++ b/build/Android.common_path.mk @@ -74,18 +74,21 @@ HOST_CORE_IMG_LOCATION := $(HOST_OUT_JAVA_LIBRARIES)/core.art TARGET_CORE_IMG_LOCATION := $(ART_TARGET_TEST_OUT)/core.art # Jar files for core.art. -HOST_CORE_DEX_LOCATIONS := $(foreach jar,$(HOST_CORE_JARS), $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar) +TEST_CORE_JARS := core-oj core-libart core-simple conscrypt okhttp bouncycastle +HOST_TEST_CORE_JARS := $(addsuffix -hostdex,$(TEST_CORE_JARS)) +TARGET_TEST_CORE_JARS := $(addsuffix -testdex,$(TEST_CORE_JARS)) +HOST_CORE_DEX_LOCATIONS := $(foreach jar,$(HOST_TEST_CORE_JARS), $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar) ifeq ($(ART_TEST_ANDROID_ROOT),) -TARGET_CORE_DEX_LOCATIONS := $(foreach jar,$(TARGET_CORE_JARS),/$(DEXPREOPT_BOOT_JAR_DIR)/$(jar).jar) +TARGET_CORE_DEX_LOCATIONS := $(foreach jar,$(TARGET_TEST_CORE_JARS),/$(DEXPREOPT_BOOT_JAR_DIR)/$(jar).jar) else -TARGET_CORE_DEX_LOCATIONS := $(foreach jar,$(TARGET_CORE_JARS),$(ART_TEST_ANDROID_ROOT)/framework/$(jar).jar) +TARGET_CORE_DEX_LOCATIONS := $(foreach jar,$(TARGET_TEST_CORE_JARS),$(ART_TEST_ANDROID_ROOT)/framework/$(jar).jar) endif -HOST_CORE_DEX_FILES := $(foreach jar,$(HOST_CORE_JARS), $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar) -TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_CORE_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar) +HOST_CORE_DEX_FILES := $(foreach jar,$(HOST_TEST_CORE_JARS), $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar) +TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_TEST_CORE_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar) -ART_HOST_DEX_DEPENDENCIES := $(foreach jar,$(HOST_CORE_JARS),$(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar) -ART_TARGET_DEX_DEPENDENCIES := $(foreach jar,$(TARGET_CORE_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar) +ART_HOST_DEX_DEPENDENCIES := $(foreach jar,$(HOST_TEST_CORE_JARS),$(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar) +ART_TARGET_DEX_DEPENDENCIES := $(foreach jar,$(TARGET_TEST_CORE_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar) ART_CORE_SHARED_LIBRARIES := libjavacore libopenjdk libopenjdkjvm libopenjdkjvmti ART_CORE_SHARED_DEBUG_LIBRARIES := libopenjdkd libopenjdkjvmd libopenjdkjvmtid diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk index 17d0232c04..d8014bd55f 100644 --- a/build/Android.common_test.mk +++ b/build/Android.common_test.mk @@ -129,7 +129,7 @@ define build-art-test-dex LOCAL_DEX_PREOPT := false LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_test.mk $(4) LOCAL_MODULE_TAGS := tests - LOCAL_JAVA_LIBRARIES := $(TARGET_CORE_JARS) + LOCAL_JAVA_LIBRARIES := $(TARGET_TEST_CORE_JARS) LOCAL_MODULE_PATH := $(3) LOCAL_DEX_PREOPT_IMAGE_LOCATION := $(TARGET_CORE_IMG_OUT) ifneq ($(wildcard $(LOCAL_PATH)/$(2)/main.list),) @@ -145,7 +145,7 @@ define build-art-test-dex LOCAL_NO_STANDARD_LIBRARIES := true LOCAL_DEX_PREOPT := false LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_test.mk $(4) - LOCAL_JAVA_LIBRARIES := $(HOST_CORE_JARS) + LOCAL_JAVA_LIBRARIES := $(HOST_TEST_CORE_JARS) LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_LOCATION) ifneq ($(wildcard $(LOCAL_PATH)/$(2)/main.list),) LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(LOCAL_PATH)/$(2)/main.list --minimal-main-dex diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 9a5e26b178..6885946c40 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -454,7 +454,10 @@ define define-art-gtest-rule-target $$($(3)TARGET_OUT_SHARED_LIBRARIES)/libopenjdkd.so \ $$(TARGET_OUT_JAVA_LIBRARIES)/core-libart-testdex.jar \ $$(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar \ - $$(TARGET_OUT_JAVA_LIBRARIES)/core-simple-testdex.jar + $$(TARGET_OUT_JAVA_LIBRARIES)/core-simple-testdex.jar \ + $$(TARGET_OUT_JAVA_LIBRARIES)/conscrypt-testdex.jar \ + $$(TARGET_OUT_JAVA_LIBRARIES)/okhttp-testdex.jar \ + $$(TARGET_OUT_JAVA_LIBRARIES)/bouncycastle-testdex.jar ART_TEST_TARGET_GTEST_DEPENDENCIES += $$(gtest_deps) diff --git a/build/apex/Android.bp b/build/apex/Android.bp index 159e5c1992..f1a21e8428 100644 --- a/build/apex/Android.bp +++ b/build/apex/Android.bp @@ -72,6 +72,13 @@ apex_key { private_key: "com.android.runtime.pem", } +prebuilt_etc { + name: "com.android.runtime.ld.config.txt", + src: "ld.config.txt", + filename: "ld.config.txt", + installable: false, +} + // TODO: Introduce `apex_defaults` to factor common parts of `apex` // module definitions below? @@ -97,9 +104,8 @@ apex { binaries: [], } }, + prebuilts: ["com.android.runtime.ld.config.txt"], key: "com.android.runtime.key", - // TODO: Also package a `ld.config.txt` config file (to be placed in `etc/`). - // ... } // "Debug" version of the Runtime APEX module (containing both release and @@ -126,7 +132,6 @@ apex { binaries: art_tools_binaries, } }, + prebuilts: ["com.android.runtime.ld.config.txt"], key: "com.android.runtime.key", - // TODO: Also package a `ld.config.txt` config file (to be placed in `etc/`). - // ... } diff --git a/build/apex/ld.config.txt b/build/apex/ld.config.txt new file mode 100644 index 0000000000..ac4d1eb81f --- /dev/null +++ b/build/apex/ld.config.txt @@ -0,0 +1 @@ +# TODO: Write me. diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc index 71422d48a5..baf8643e9b 100644 --- a/compiler/debug/elf_debug_writer.cc +++ b/compiler/debug/elf_debug_writer.cc @@ -16,8 +16,9 @@ #include "elf_debug_writer.h" -#include <vector> +#include <type_traits> #include <unordered_map> +#include <vector> #include "base/array_ref.h" #include "debug/dwarf/dwarf_constants.h" @@ -29,6 +30,7 @@ #include "debug/elf_symtab_writer.h" #include "debug/method_debug_info.h" #include "debug/xz_utils.h" +#include "elf.h" #include "linker/elf_builder.h" #include "linker/vector_output_stream.h" #include "oat.h" @@ -36,6 +38,8 @@ namespace art { namespace debug { +using ElfRuntimeTypes = std::conditional<sizeof(void*) == 4, ElfTypes32, ElfTypes64>::type; + template <typename ElfTypes> void WriteDebugInfo(linker::ElfBuilder<ElfTypes>* builder, const DebugInfo& debug_info, @@ -165,22 +169,16 @@ std::vector<uint8_t> MakeMiniDebugInfo( } } -template <typename ElfTypes> -static std::vector<uint8_t> MakeElfFileForJITInternal( +std::vector<uint8_t> MakeElfFileForJIT( InstructionSet isa, const InstructionSetFeatures* features, bool mini_debug_info, - ArrayRef<const MethodDebugInfo> method_infos) { - CHECK_GT(method_infos.size(), 0u); - uint64_t min_address = std::numeric_limits<uint64_t>::max(); - uint64_t max_address = 0; - for (const MethodDebugInfo& mi : method_infos) { - CHECK_EQ(mi.is_code_address_text_relative, false); - min_address = std::min(min_address, mi.code_address); - max_address = std::max(max_address, mi.code_address + mi.code_size); - } + const MethodDebugInfo& method_info) { + using ElfTypes = ElfRuntimeTypes; + CHECK_EQ(sizeof(ElfTypes::Addr), static_cast<size_t>(GetInstructionSetPointerSize(isa))); + CHECK_EQ(method_info.is_code_address_text_relative, false); DebugInfo debug_info{}; - debug_info.compiled_methods = method_infos; + debug_info.compiled_methods = ArrayRef<const MethodDebugInfo>(&method_info, 1); std::vector<uint8_t> buffer; buffer.reserve(KB); linker::VectorOutputStream out("Debug ELF file", &buffer); @@ -188,28 +186,16 @@ static std::vector<uint8_t> MakeElfFileForJITInternal( new linker::ElfBuilder<ElfTypes>(isa, features, &out)); // No program headers since the ELF file is not linked and has no allocated sections. builder->Start(false /* write_program_headers */); + builder->GetText()->AllocateVirtualMemory(method_info.code_address, method_info.code_size); if (mini_debug_info) { - if (method_infos.size() > 1) { - std::vector<uint8_t> mdi = MakeMiniDebugInfo(isa, - features, - min_address, - max_address - min_address, - /* dex_section_address */ 0, - /* dex_section_size */ 0, - debug_info); - builder->WriteSection(".gnu_debugdata", &mdi); - } else { - // The compression is great help for multiple methods but it is not worth it for a - // single method due to the overheads so skip the compression here for performance. - builder->GetText()->AllocateVirtualMemory(min_address, max_address - min_address); - WriteDebugSymbols(builder.get(), true /* mini-debug-info */, debug_info); - WriteCFISection(builder.get(), - debug_info.compiled_methods, - dwarf::DW_DEBUG_FRAME_FORMAT, - false /* write_oat_paches */); - } + // The compression is great help for multiple methods but it is not worth it for a + // single method due to the overheads so skip the compression here for performance. + WriteDebugSymbols(builder.get(), true /* mini-debug-info */, debug_info); + WriteCFISection(builder.get(), + debug_info.compiled_methods, + dwarf::DW_DEBUG_FRAME_FORMAT, + false /* write_oat_paches */); } else { - builder->GetText()->AllocateVirtualMemory(min_address, max_address - min_address); WriteDebugInfo(builder.get(), debug_info, dwarf::DW_DEBUG_FRAME_FORMAT, @@ -220,24 +206,13 @@ static std::vector<uint8_t> MakeElfFileForJITInternal( return buffer; } -std::vector<uint8_t> MakeElfFileForJIT( - InstructionSet isa, - const InstructionSetFeatures* features, - bool mini_debug_info, - ArrayRef<const MethodDebugInfo> method_infos) { - if (Is64BitInstructionSet(isa)) { - return MakeElfFileForJITInternal<ElfTypes64>(isa, features, mini_debug_info, method_infos); - } else { - return MakeElfFileForJITInternal<ElfTypes32>(isa, features, mini_debug_info, method_infos); - } -} - -template <typename ElfTypes> -static std::vector<uint8_t> WriteDebugElfFileForClassesInternal( +std::vector<uint8_t> WriteDebugElfFileForClasses( InstructionSet isa, const InstructionSetFeatures* features, const ArrayRef<mirror::Class*>& types) REQUIRES_SHARED(Locks::mutator_lock_) { + using ElfTypes = ElfRuntimeTypes; + CHECK_EQ(sizeof(ElfTypes::Addr), static_cast<size_t>(GetInstructionSetPointerSize(isa))); std::vector<uint8_t> buffer; buffer.reserve(KB); linker::VectorOutputStream out("Debug ELF file", &buffer); @@ -256,16 +231,6 @@ static std::vector<uint8_t> WriteDebugElfFileForClassesInternal( return buffer; } -std::vector<uint8_t> WriteDebugElfFileForClasses(InstructionSet isa, - const InstructionSetFeatures* features, - const ArrayRef<mirror::Class*>& types) { - if (Is64BitInstructionSet(isa)) { - return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, features, types); - } else { - return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, features, types); - } -} - // Explicit instantiations template void WriteDebugInfo<ElfTypes32>( linker::ElfBuilder<ElfTypes32>* builder, diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h index e442e0016c..8ad0c4219a 100644 --- a/compiler/debug/elf_debug_writer.h +++ b/compiler/debug/elf_debug_writer.h @@ -54,7 +54,7 @@ std::vector<uint8_t> MakeElfFileForJIT( InstructionSet isa, const InstructionSetFeatures* features, bool mini_debug_info, - ArrayRef<const MethodDebugInfo> method_infos); + const MethodDebugInfo& method_info); std::vector<uint8_t> WriteDebugElfFileForClasses( InstructionSet isa, diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h index 81ecc175b5..44f3296e90 100644 --- a/compiler/linker/elf_builder.h +++ b/compiler/linker/elf_builder.h @@ -18,6 +18,7 @@ #define ART_COMPILER_LINKER_ELF_BUILDER_H_ #include <vector> +#include <deque> #include "arch/instruction_set.h" #include "arch/mips/instruction_set_features_mips.h" @@ -357,57 +358,49 @@ class ElfBuilder final { } // Buffer symbol for this section. It will be written later. - // If the symbol's section is null, it will be considered absolute (SHN_ABS). - // (we use this in JIT to reference code which is stored outside the debug ELF file) void Add(Elf_Word name, const Section* section, Elf_Addr addr, Elf_Word size, uint8_t binding, uint8_t type) { - Elf_Word section_index; - if (section != nullptr) { - DCHECK_LE(section->GetAddress(), addr); - DCHECK_LE(addr, section->GetAddress() + section->header_.sh_size); - section_index = section->GetSectionIndex(); - } else { - section_index = static_cast<Elf_Word>(SHN_ABS); - } - Add(name, section_index, addr, size, binding, type); - } - - // Buffer symbol for this section. It will be written later. - void Add(Elf_Word name, - Elf_Word section_index, - Elf_Addr addr, - Elf_Word size, - uint8_t binding, - uint8_t type) { Elf_Sym sym = Elf_Sym(); sym.st_name = name; sym.st_value = addr; sym.st_size = size; sym.st_other = 0; - sym.st_shndx = section_index; sym.st_info = (binding << 4) + (type & 0xf); - syms_.push_back(sym); + Add(sym, section); + } + + // Buffer symbol for this section. It will be written later. + void Add(Elf_Sym sym, const Section* section) { + DCHECK(section != nullptr); + DCHECK_LE(section->GetAddress(), sym.st_value); + DCHECK_LE(sym.st_value, section->GetAddress() + section->header_.sh_size); + sym.st_shndx = section->GetSectionIndex(); // The sh_info file must be set to index one-past the last local symbol. - if (binding == STB_LOCAL) { - this->header_.sh_info = syms_.size(); + if (sym.getBinding() == STB_LOCAL) { + DCHECK_EQ(syms_.back().getBinding(), STB_LOCAL); + this->header_.sh_info = syms_.size() + 1; } + + syms_.push_back(sym); } Elf_Word GetCacheSize() { return syms_.size() * sizeof(Elf_Sym); } void WriteCachedSection() { this->Start(); - this->WriteFully(syms_.data(), syms_.size() * sizeof(Elf_Sym)); + for (; !syms_.empty(); syms_.pop_front()) { + this->WriteFully(&syms_.front(), sizeof(Elf_Sym)); + } this->End(); } private: - std::vector<Elf_Sym> syms_; // Buffered/cached content of the whole section. + std::deque<Elf_Sym> syms_; // Buffered/cached content of the whole section. }; class AbiflagsSection final : public Section { diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 1d3fcf3002..641368b87a 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -1469,7 +1469,7 @@ void OptimizingCompiler::GenerateJitDebugInfo( compiler_options.GetInstructionSet(), compiler_options.GetInstructionSetFeatures(), mini_debug_info, - ArrayRef<const debug::MethodDebugInfo>(&info, 1)); + info); MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_); AddNativeDebugInfoForJit(reinterpret_cast<const void*>(info.code_address), elf_file); diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index 97a5f2453e..92dd9328b3 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -192,24 +192,12 @@ class Dex2oatTest : public Dex2oatEnvironmentTest { } int Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) { - Runtime* runtime = Runtime::Current(); - - const std::vector<gc::space::ImageSpace*>& image_spaces = - runtime->GetHeap()->GetBootImageSpaces(); - if (image_spaces.empty()) { - *error_msg = "No image location found for Dex2Oat."; - return false; - } - std::string image_location = image_spaces[0]->GetImageLocation(); - std::vector<std::string> argv; - argv.push_back(runtime->GetCompilerExecutable()); - - if (runtime->IsJavaDebuggable()) { - argv.push_back("--debuggable"); + if (!CommonRuntimeTest::StartDex2OatCommandLine(&argv, error_msg)) { + return false; } - runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv); + Runtime* runtime = Runtime::Current(); if (!runtime->IsVerificationEnabled()) { argv.push_back("--compiler-filter=assume-verified"); } @@ -226,11 +214,6 @@ class Dex2oatTest : public Dex2oatEnvironmentTest { argv.push_back("--host"); } - argv.push_back("--boot-image=" + image_location); - - std::vector<std::string> compiler_options = runtime->GetCompilerOptions(); - argv.insert(argv.end(), compiler_options.begin(), compiler_options.end()); - argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end()); // We must set --android-root. diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index 844a72803e..6ffcef12a7 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -442,6 +442,9 @@ inline void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode, MemMap::Init(); RuntimeOptions options; + options.emplace_back(GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames()), nullptr); + options.emplace_back( + GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations()), nullptr); std::string image("-Ximage:"); image.append(helper.image_locations[0].GetFilename()); options.push_back(std::make_pair(image.c_str(), static_cast<void*>(nullptr))); diff --git a/dexoptanalyzer/dexoptanalyzer_test.cc b/dexoptanalyzer/dexoptanalyzer_test.cc index b9116f0fb8..f6fd1fb014 100644 --- a/dexoptanalyzer/dexoptanalyzer_test.cc +++ b/dexoptanalyzer/dexoptanalyzer_test.cc @@ -46,6 +46,10 @@ class DexoptAnalyzerTest : public DexoptTest { if (assume_profile_changed) { argv_str.push_back("--assume-profile-changed"); } + argv_str.push_back("--runtime-arg"); + argv_str.push_back(GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames())); + argv_str.push_back("--runtime-arg"); + argv_str.push_back(GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations())); argv_str.push_back("--image=" + GetImageLocation()); argv_str.push_back("--android-data=" + android_data_); diff --git a/imgdiag/imgdiag_test.cc b/imgdiag/imgdiag_test.cc index 73df2a2b03..739d9b8329 100644 --- a/imgdiag/imgdiag_test.cc +++ b/imgdiag/imgdiag_test.cc @@ -34,12 +34,8 @@ namespace art { -static const char* kImgDiagDiffPid = "--image-diff-pid"; -static const char* kImgDiagBootImage = "--boot-image"; static const char* kImgDiagBinaryName = "imgdiag"; -static const char* kImgDiagZygoteDiffPid = "--zygote-diff-pid"; - // from kernel <include/linux/threads.h> #define PID_MAX_LIMIT (4*1024*1024) // Upper bound. Most kernel configs will have smaller max pid. @@ -93,25 +89,15 @@ class ImgDiagTest : public CommonRuntimeTest { EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path"; // Run imgdiag --image-diff-pid=$image_diff_pid and wait until it's done with a 0 exit code. - std::string diff_pid_args; - std::string zygote_diff_pid_args; - { - std::stringstream diff_pid_args_ss; - diff_pid_args_ss << kImgDiagDiffPid << "=" << image_diff_pid; - diff_pid_args = diff_pid_args_ss.str(); - } - { - std::stringstream zygote_pid_args_ss; - zygote_pid_args_ss << kImgDiagZygoteDiffPid << "=" << image_diff_pid; - zygote_diff_pid_args = zygote_pid_args_ss.str(); - } - std::string boot_image_args = std::string(kImgDiagBootImage) + "=" + boot_image; - std::vector<std::string> exec_argv = { file_path, - diff_pid_args, - zygote_diff_pid_args, - boot_image_args + "--image-diff-pid=" + std::to_string(image_diff_pid), + "--zygote-diff-pid=" + std::to_string(image_diff_pid), + "--runtime-arg", + GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames()), + "--runtime-arg", + GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations()), + "--boot-image=" + boot_image }; return ::art::Exec(exec_argv, error_msg); diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc index 5a0b425bca..278203da23 100644 --- a/libartbase/base/common_art_test.cc +++ b/libartbase/base/common_art_test.cc @@ -24,6 +24,7 @@ #include "nativehelper/scoped_local_ref.h" #include "android-base/stringprintf.h" +#include "android-base/strings.h" #include "android-base/unique_fd.h" #include <unicode/uvernum.h> @@ -328,9 +329,48 @@ static std::string GetDexFileName(const std::string& jar_prefix, bool host) { } std::vector<std::string> CommonArtTestImpl::GetLibCoreDexFileNames() { - return std::vector<std::string>({GetDexFileName("core-oj", IsHost()), - GetDexFileName("core-libart", IsHost()), - GetDexFileName("core-simple", IsHost())}); + // Note: This must match the TEST_CORE_JARS in Android.common_path.mk + // because that's what we use for compiling the core.art image. + static const char* const kLibcoreModules[] = { + "core-oj", + "core-libart", + "core-simple", + "conscrypt", + "okhttp", + "bouncycastle", + }; + + std::vector<std::string> result; + result.reserve(arraysize(kLibcoreModules)); + for (const char* module : kLibcoreModules) { + result.push_back(GetDexFileName(module, IsHost())); + } + return result; +} + +std::vector<std::string> CommonArtTestImpl::GetLibCoreDexLocations() { + std::vector<std::string> result = GetLibCoreDexFileNames(); + if (IsHost()) { + // Strip the ANDROID_BUILD_TOP directory including the directory separator '/'. + const char* host_dir = getenv("ANDROID_BUILD_TOP"); + CHECK(host_dir != nullptr); + std::string prefix = host_dir; + CHECK(!prefix.empty()); + if (prefix.back() != '/') { + prefix += '/'; + } + for (std::string& location : result) { + CHECK_GT(location.size(), prefix.size()); + CHECK_EQ(location.compare(0u, prefix.size(), prefix), 0); + location.erase(0u, prefix.size()); + } + } + return result; +} + +std::string CommonArtTestImpl::GetClassPathOption(const char* option, + const std::vector<std::string>& class_path) { + return option + android::base::Join(class_path, ':'); } std::string CommonArtTestImpl::GetTestAndroidRoot() { diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h index 0f4800dfc5..3e2340f0a7 100644 --- a/libartbase/base/common_art_test.h +++ b/libartbase/base/common_art_test.h @@ -99,6 +99,12 @@ class CommonArtTestImpl { // Gets the paths of the libcore dex files. static std::vector<std::string> GetLibCoreDexFileNames(); + // Gets the locations of the libcore dex files. + static std::vector<std::string> GetLibCoreDexLocations(); + + static std::string GetClassPathOption(const char* option, + const std::vector<std::string>& class_path); + // Returns bin directory which contains host's prebuild tools. static std::string GetAndroidHostToolsDir(); diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h index 4ee510130b..728939f93c 100644 --- a/oatdump/oatdump_test.h +++ b/oatdump/oatdump_test.h @@ -122,6 +122,10 @@ class OatDumpTest : public CommonRuntimeTest { "-Xmx512m", "--runtime-arg", "-Xnorelocate", + "--runtime-arg", + GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames()), + "--runtime-arg", + GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations()), "--boot-image=" + GetCoreArtLocation(), "--instruction-set=" + std::string(GetInstructionSetString(kRuntimeISA)), "--dex-file=" + GetTestDexFileName(GetAppBaseName().c_str()), @@ -181,6 +185,11 @@ class OatDumpTest : public CommonRuntimeTest { expected_prefixes.push_back("IMAGE BEGIN:"); expected_prefixes.push_back("kDexCaches:"); } else if (mode == kModeOatWithBootImage) { + exec_argv.push_back("--runtime-arg"); + exec_argv.push_back(GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames())); + exec_argv.push_back("--runtime-arg"); + exec_argv.push_back( + GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations())); exec_argv.push_back("--boot-image=" + GetCoreArtLocation()); exec_argv.push_back("--instruction-set=" + std::string( GetInstructionSetString(kRuntimeISA))); diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc index 2131120a11..051db4c67e 100644 --- a/openjdkjvmti/ti_thread.cc +++ b/openjdkjvmti/ti_thread.cc @@ -91,7 +91,8 @@ struct ThreadCallback : public art::ThreadLifecycleCallback { self->GetThreadName(name); if (name != "JDWP" && name != "Signal Catcher" && - !android::base::StartsWith(name, "Jit thread pool")) { + !android::base::StartsWith(name, "Jit thread pool") && + !android::base::StartsWith(name, "Runtime worker thread")) { LOG(FATAL) << "Unexpected thread before start: " << name << " id: " << self->GetThreadId(); } diff --git a/runtime/arch/arm/instruction_set_features_arm.cc b/runtime/arch/arm/instruction_set_features_arm.cc index e97d2cbd92..58ae394fb4 100644 --- a/runtime/arch/arm/instruction_set_features_arm.cc +++ b/runtime/arch/arm/instruction_set_features_arm.cc @@ -54,7 +54,8 @@ ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromVariant( "cortex-a76", "exynos-m1", "denver", - "kryo" + "kryo", + "kryo385", }; bool has_armv8a = FindVariantInArray(arm_variants_with_armv8a, arraysize(arm_variants_with_armv8a), diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc index 7796ca7745..963c207842 100644 --- a/runtime/arch/arm64/instruction_set_features_arm64.cc +++ b/runtime/arch/arm64/instruction_set_features_arm64.cc @@ -57,10 +57,6 @@ Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant( static const char* arm64_variants_with_crc[] = { "default", "generic", - "kryo", - "exynos-m1", - "exynos-m2", - "exynos-m3", "cortex-a35", "cortex-a53", "cortex-a53.a57", @@ -71,18 +67,25 @@ Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant( "cortex-a55", "cortex-a75", "cortex-a76", + "exynos-m1", + "exynos-m2", + "exynos-m3", + "kryo", + "kryo385", }; static const char* arm64_variants_with_lse[] = { "cortex-a55", "cortex-a75", "cortex-a76", + "kryo385", }; static const char* arm64_variants_with_fp16[] = { "cortex-a55", "cortex-a75", "cortex-a76", + "kryo385", }; static const char* arm64_variants_with_dotprod[] = { @@ -124,7 +127,8 @@ Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant( "exynos-m2", "exynos-m3", "denver64", - "kryo" + "kryo", + "kryo385", }; if (!FindVariantInArray(arm64_known_variants, arraysize(arm64_known_variants), variant)) { std::ostringstream os; diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 0300fa155f..a101976a87 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -44,6 +44,7 @@ #include "dex/dex_file_loader.h" #include "dex/primitive.h" #include "gc/heap.h" +#include "gc/space/image_space.h" #include "gc_root-inl.h" #include "gtest/gtest.h" #include "handle_scope-inl.h" @@ -111,15 +112,14 @@ void CommonRuntimeTestImpl::SetUp() { std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB)); std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB)); - RuntimeOptions options; - std::string boot_class_path_string = "-Xbootclasspath"; - for (const std::string &core_dex_file_name : GetLibCoreDexFileNames()) { - boot_class_path_string += ":"; - boot_class_path_string += core_dex_file_name; - } + std::string boot_class_path_string = + GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames()); + std::string boot_class_path_locations_string = + GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations()); options.push_back(std::make_pair(boot_class_path_string, nullptr)); + options.push_back(std::make_pair(boot_class_path_locations_string, nullptr)); options.push_back(std::make_pair("-Xcheck:jni", nullptr)); options.push_back(std::make_pair(min_heap_string, nullptr)); options.push_back(std::make_pair(max_heap_string, nullptr)); @@ -386,6 +386,38 @@ void CommonRuntimeTestImpl::SetUpRuntimeOptionsForFillHeap(RuntimeOptions *optio } } +bool CommonRuntimeTestImpl::StartDex2OatCommandLine(/*out*/std::vector<std::string>* argv, + /*out*/std::string* error_msg) { + DCHECK(argv != nullptr); + DCHECK(argv->empty()); + + Runtime* runtime = Runtime::Current(); + const std::vector<gc::space::ImageSpace*>& image_spaces = + runtime->GetHeap()->GetBootImageSpaces(); + if (image_spaces.empty()) { + *error_msg = "No image location found for Dex2Oat."; + return false; + } + std::string image_location = image_spaces[0]->GetImageLocation(); + + argv->push_back(runtime->GetCompilerExecutable()); + if (runtime->IsJavaDebuggable()) { + argv->push_back("--debuggable"); + } + runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(argv); + + argv->push_back("--runtime-arg"); + argv->push_back(GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames())); + argv->push_back("--runtime-arg"); + argv->push_back(GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations())); + + argv->push_back("--boot-image=" + image_location); + + std::vector<std::string> compiler_options = runtime->GetCompilerOptions(); + argv->insert(argv->end(), compiler_options.begin(), compiler_options.end()); + return true; +} + CheckJniAbortCatcher::CheckJniAbortCatcher() : vm_(Runtime::Current()->GetJavaVM()) { vm_->SetCheckJniAbortHook(Hook, &actual_); } diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h index 0fee797015..319c7c7111 100644 --- a/runtime/common_runtime_test.h +++ b/runtime/common_runtime_test.h @@ -97,6 +97,9 @@ class CommonRuntimeTestImpl : public CommonArtTestImpl { return true; } + static bool StartDex2OatCommandLine(/*out*/std::vector<std::string>* argv, + /*out*/std::string* error_msg); + protected: // Allow subclases such as CommonCompilerTest to add extra options. virtual void SetUpRuntimeOptions(RuntimeOptions* options ATTRIBUTE_UNUSED) {} diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc index f52a0f9430..b46c93383e 100644 --- a/runtime/dexopt_test.cc +++ b/runtime/dexopt_test.cc @@ -46,26 +46,13 @@ void DexoptTest::PostRuntimeCreate() { ReserveImageSpace(); } -static std::string ImageLocation() { - Runtime* runtime = Runtime::Current(); - const std::vector<gc::space::ImageSpace*>& image_spaces = - runtime->GetHeap()->GetBootImageSpaces(); - if (image_spaces.empty()) { - return ""; - } - return image_spaces[0]->GetImageLocation(); -} - bool DexoptTest::Dex2Oat(const std::vector<std::string>& args, std::string* error_msg) { - Runtime* runtime = Runtime::Current(); - std::vector<std::string> argv; - argv.push_back(runtime->GetCompilerExecutable()); - if (runtime->IsJavaDebuggable()) { - argv.push_back("--debuggable"); + if (!CommonRuntimeTest::StartDex2OatCommandLine(&argv, error_msg)) { + return false; } - runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv); + Runtime* runtime = Runtime::Current(); if (runtime->GetHiddenApiEnforcementPolicy() != hiddenapi::EnforcementPolicy::kDisabled) { argv.push_back("--runtime-arg"); argv.push_back("-Xhidden-api-checks"); @@ -75,11 +62,6 @@ bool DexoptTest::Dex2Oat(const std::vector<std::string>& args, std::string* erro argv.push_back("--host"); } - argv.push_back("--boot-image=" + ImageLocation()); - - std::vector<std::string> compiler_options = runtime->GetCompilerOptions(); - argv.insert(argv.end(), compiler_options.begin(), compiler_options.end()); - argv.insert(argv.end(), args.begin(), args.end()); std::string command_line(android::base::Join(argv, ' ')); diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index d4275a0224..7736568620 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -2065,6 +2065,9 @@ void ConcurrentCopying::ReclaimPhase() { LOG(INFO) << "(after) num_bytes_allocated=" << heap_->num_bytes_allocated_.load(); } + + float reclaimed_bytes_ratio = static_cast<float>(freed_bytes) / num_bytes_allocated_before_gc_; + reclaimed_bytes_ratio_sum_ += reclaimed_bytes_ratio; } { @@ -2080,11 +2083,6 @@ void ConcurrentCopying::ReclaimPhase() { CheckEmptyMarkStack(); - int64_t num_bytes_allocated_after_gc = static_cast<int64_t>(heap_->GetBytesAllocated()); - int64_t diff = num_bytes_allocated_before_gc_ - num_bytes_allocated_after_gc; - auto ratio = static_cast<float>(diff) / num_bytes_allocated_before_gc_; - reclaimed_bytes_ratio_sum_ += ratio; - if (kVerboseMode) { LOG(INFO) << "GC end of ReclaimPhase"; } diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc index 8477c9de2c..46ff7dc820 100644 --- a/runtime/gc/collector/garbage_collector.cc +++ b/runtime/gc/collector/garbage_collector.cc @@ -90,6 +90,7 @@ void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) { Thread* self = Thread::Current(); uint64_t start_time = NanoTime(); uint64_t thread_cpu_start_time = ThreadCpuNanoTime(); + GetHeap()->CalculateWeightedAllocatedBytes(); Iteration* current_iteration = GetCurrentIteration(); current_iteration->Reset(gc_cause, clear_soft_references); // Note transaction mode is single-threaded and there's no asynchronous GC and this flag doesn't diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index f767360066..86135c1bc2 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -210,6 +210,9 @@ Heap::Heap(size_t initial_size, low_memory_mode_(low_memory_mode), long_pause_log_threshold_(long_pause_log_threshold), long_gc_log_threshold_(long_gc_log_threshold), + process_cpu_start_time_ns_(ProcessCpuNanoTime()), + last_process_cpu_time_ns_(process_cpu_start_time_ns_), + weighted_allocated_bytes_(0u), ignore_max_footprint_(ignore_max_footprint), zygote_creation_lock_("zygote creation lock", kZygoteCreationLock), zygote_space_(nullptr), @@ -1062,6 +1065,14 @@ void Heap::RemoveSpace(space::Space* space) { } } +void Heap::CalculateWeightedAllocatedBytes() { + uint64_t current_process_cpu_time = ProcessCpuNanoTime(); + uint64_t bytes_allocated = GetBytesAllocated(); + uint64_t weight = current_process_cpu_time - last_process_cpu_time_ns_; + weighted_allocated_bytes_ += weight * bytes_allocated; + last_process_cpu_time_ns_ = current_process_cpu_time; +} + uint64_t Heap::GetTotalGcCpuTime() { uint64_t sum = 0; for (auto* collector : garbage_collectors_) { @@ -1139,6 +1150,11 @@ void Heap::ResetGcPerformanceInfo() { for (auto* collector : garbage_collectors_) { collector->ResetMeasurements(); } + + process_cpu_start_time_ns_ = ProcessCpuNanoTime(); + last_process_cpu_time_ns_ = process_cpu_start_time_ns_; + weighted_allocated_bytes_ = 0u; + total_bytes_freed_ever_ = 0; total_objects_freed_ever_ = 0; total_wait_time_ = 0; diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index a43f3156f5..411a4469d9 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -395,8 +395,17 @@ class Heap { REQUIRES(!Locks::heap_bitmap_lock_) REQUIRES(Locks::mutator_lock_); + uint64_t GetWeightedAllocatedBytes() const { + return weighted_allocated_bytes_; + } + + void CalculateWeightedAllocatedBytes(); uint64_t GetTotalGcCpuTime(); + uint64_t GetProcessCpuStartTime() const { + return process_cpu_start_time_ns_; + } + // Set target ideal heap utilization ratio, implements // dalvik.system.VMRuntime.setTargetHeapUtilization. void SetTargetHeapUtilization(float target); @@ -1161,6 +1170,15 @@ class Heap { // If we get a GC longer than long GC log threshold, then we print out the GC after it finishes. const size_t long_gc_log_threshold_; + // Starting time of the new process; meant to be used for measuring total process CPU time. + uint64_t process_cpu_start_time_ns_; + + // Last time GC started; meant to be used to measure the duration between two GCs. + uint64_t last_process_cpu_time_ns_; + + // allocated_bytes * (current_process_cpu_time - last_process_cpu_time) + uint64_t weighted_allocated_bytes_; + // If we ignore the max footprint it lets the heap grow until it hits the heap capacity, this is // useful for benchmarking since it reduces time spent in GC to a low %. const bool ignore_max_footprint_; diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index c772bdab18..e494bd681d 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -627,16 +627,36 @@ class ImageSpace::Loader { return MemMap::Invalid(); } memcpy(map.Begin(), &image_header, sizeof(ImageHeader)); + const uint64_t start = NanoTime(); + ThreadPool* pool = Runtime::Current()->GetThreadPool(); + Thread* const self = Thread::Current(); + const size_t kMinBlocks = 2; + const bool use_parallel = pool != nullptr &&image_header.GetBlockCount() >= kMinBlocks; for (const ImageHeader::Block& block : image_header.GetBlocks(temp_map.Begin())) { - TimingLogger::ScopedTiming timing2("LZ4 decompress image", logger); - if (!block.Decompress(/*out_ptr=*/map.Begin(), /*in_ptr=*/temp_map.Begin(), error_msg)) { - if (error_msg != nullptr) { - *error_msg = "Failed to decompress image block " + *error_msg; + auto function = [&](Thread*) { + const uint64_t start2 = NanoTime(); + ScopedTrace trace("LZ4 decompress block"); + if (!block.Decompress(/*out_ptr=*/map.Begin(), + /*in_ptr=*/temp_map.Begin(), + error_msg)) { + if (error_msg != nullptr) { + *error_msg = "Failed to decompress image block " + *error_msg; + } } - return MemMap::Invalid(); + VLOG(image) << "Decompress block " << block.GetDataSize() << " -> " + << block.GetImageSize() << " in " << PrettyDuration(NanoTime() - start2); + }; + if (use_parallel) { + pool->AddTask(self, new FunctionTask(std::move(function))); + } else { + function(self); } } + if (use_parallel) { + ScopedTrace trace("Waiting for workers"); + pool->Wait(self, true, false); + } const uint64_t time = NanoTime() - start; // Add one 1 ns to prevent possible divide by 0. VLOG(image) << "Decompressing image took " << PrettyDuration(time) << " (" diff --git a/runtime/image.h b/runtime/image.h index 76fb3b70c9..9d98431183 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -116,6 +116,14 @@ class PACKED(8) ImageHeader { return storage_mode_; } + uint32_t GetDataSize() const { + return data_size_; + } + + uint32_t GetImageSize() const { + return image_size_; + } + private: // Storage method for the image, the image may be compressed. StorageMode storage_mode_ = kDefaultStorageMode; diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index 530371d4c4..0f655b94de 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -44,10 +44,6 @@ #include "thread_list.h" #include "trace.h" -#if defined(__linux__) -#include <sys/prctl.h> -#endif - #include <sys/resource.h> namespace art { @@ -59,37 +55,6 @@ static bool kAlwaysCollectNonDebuggableClasses = using android::base::StringPrintf; -static void EnableDebugger() { -#if defined(__linux__) - // To let a non-privileged gdbserver attach to this - // process, we must set our dumpable flag. - if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { - PLOG(ERROR) << "prctl(PR_SET_DUMPABLE) failed for pid " << getpid(); - } - - // Even if Yama is on a non-privileged native debugger should - // be able to attach to the debuggable app. - if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0) == -1) { - // if Yama is off prctl(PR_SET_PTRACER) returns EINVAL - don't log in this - // case since it's expected behaviour. - if (errno != EINVAL) { - PLOG(ERROR) << "prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) failed for pid " << getpid(); - } - } -#endif - // We don't want core dumps, though, so set the soft limit on core dump size - // to 0 without changing the hard limit. - rlimit rl; - if (getrlimit(RLIMIT_CORE, &rl) == -1) { - PLOG(ERROR) << "getrlimit(RLIMIT_CORE) failed for pid " << getpid(); - } else { - rl.rlim_cur = 0; - if (setrlimit(RLIMIT_CORE, &rl) == -1) { - PLOG(ERROR) << "setrlimit(RLIMIT_CORE) failed for pid " << getpid(); - } - } -} - class ClassSet { public: // The number of classes we reasonably expect to have to look at. Realistically the number is more @@ -211,9 +176,6 @@ static uint32_t EnableDebugFeatures(uint32_t runtime_flags) { } Dbg::SetJdwpAllowed((runtime_flags & DEBUG_ENABLE_JDWP) != 0); - if ((runtime_flags & DEBUG_ENABLE_JDWP) != 0) { - EnableDebugger(); - } runtime_flags &= ~DEBUG_ENABLE_JDWP; const bool safe_mode = (runtime_flags & DEBUG_ENABLE_SAFEMODE) != 0; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index ab79b9e1a0..84526f3332 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -34,6 +34,7 @@ #include <cstdio> #include <cstdlib> #include <limits> +#include <thread> #include <vector> #include "android-base/strings.h" @@ -278,7 +279,6 @@ Runtime::Runtime() // Initially assume we perceive jank in case the process state is never updated. process_state_(kProcessStateJankPerceptible), zygote_no_threads_(false), - process_cpu_start_time_(ProcessCpuNanoTime()), verifier_logging_threshold_ms_(100) { static_assert(Runtime::kCalleeSaveSize == static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType), "Unexpected size"); @@ -322,20 +322,26 @@ Runtime::~Runtime() { } if (dump_gc_performance_on_shutdown_) { - process_cpu_end_time_ = ProcessCpuNanoTime(); + heap_->CalculateWeightedAllocatedBytes(); + uint64_t process_cpu_end_time = ProcessCpuNanoTime(); ScopedLogSeverity sls(LogSeverity::INFO); // This can't be called from the Heap destructor below because it // could call RosAlloc::InspectAll() which needs the thread_list // to be still alive. heap_->DumpGcPerformanceInfo(LOG_STREAM(INFO)); - uint64_t process_cpu_time = process_cpu_end_time_ - process_cpu_start_time_; + uint64_t process_cpu_time = process_cpu_end_time - heap_->GetProcessCpuStartTime(); uint64_t gc_cpu_time = heap_->GetTotalGcCpuTime(); float ratio = static_cast<float>(gc_cpu_time) / process_cpu_time; LOG_STREAM(INFO) << "GC CPU time " << PrettyDuration(gc_cpu_time) << " out of process CPU time " << PrettyDuration(process_cpu_time) << " (" << ratio << ")" << "\n"; + float weighted_allocated_bytes = + static_cast<float>(heap_->GetWeightedAllocatedBytes()) / process_cpu_time; + LOG_STREAM(INFO) << "Weighted bytes allocated over CPU time: " + << " (" << PrettySize(weighted_allocated_bytes) << ")" + << "\n"; } if (jit_ != nullptr) { @@ -388,6 +394,11 @@ Runtime::~Runtime() { jit_->DeleteThreadPool(); } + // Thread pools must be deleted before the runtime shuts down to avoid hanging. + if (thread_pool_ != nullptr) { + thread_pool_.reset(); + } + // Make sure our internal threads are dead before we start tearing down things they're using. GetRuntimeCallbacks()->StopDebugger(); delete signal_catcher_; @@ -910,6 +921,15 @@ void Runtime::InitNonZygoteOrPostFork( jit_->CreateThreadPool(); } + if (thread_pool_ == nullptr) { + constexpr size_t kStackSize = 64 * KB; + constexpr size_t kMaxRuntimeWorkers = 4u; + const size_t num_workers = + std::min(static_cast<size_t>(std::thread::hardware_concurrency()), kMaxRuntimeWorkers); + thread_pool_.reset(new ThreadPool("Runtime", num_workers, /*create_peers=*/false, kStackSize)); + thread_pool_->StartWorkers(Thread::Current()); + } + // Create the thread pools. heap_->CreateThreadPool(); // Reset the gc performance data at zygote fork so that the GCs diff --git a/runtime/runtime.h b/runtime/runtime.h index 0ccc7b79bf..c74647e465 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -99,6 +99,7 @@ class SignalCatcher; class StackOverflowHandler; class SuspensionHandler; class ThreadList; +class ThreadPool; class Trace; struct TraceConfig; class Transaction; @@ -789,6 +790,10 @@ class Runtime { return verifier_logging_threshold_ms_; } + ThreadPool* GetThreadPool() { + return thread_pool_.get(); + } + private: static void InitPlatformSignalHandlers(); @@ -882,6 +887,9 @@ class Runtime { // Shared linear alloc for now. std::unique_ptr<LinearAlloc> linear_alloc_; + // Thread pool + std::unique_ptr<ThreadPool> thread_pool_; + // The number of spins that are done before thread suspension is used to forcibly inflate. size_t max_spins_before_thin_lock_inflation_; MonitorList* monitor_list_; @@ -1101,9 +1109,6 @@ class Runtime { MemMap protected_fault_page_; - uint64_t process_cpu_start_time_; - uint64_t process_cpu_end_time_; - uint32_t verifier_logging_threshold_ms_; DISALLOW_COPY_AND_ASSIGN(Runtime); diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc index 8723c99706..0f96510e86 100644 --- a/runtime/thread_pool.cc +++ b/runtime/thread_pool.cc @@ -123,7 +123,10 @@ void ThreadPool::RemoveAllTasks(Thread* self) { tasks_.clear(); } -ThreadPool::ThreadPool(const char* name, size_t num_threads, bool create_peers) +ThreadPool::ThreadPool(const char* name, + size_t num_threads, + bool create_peers, + size_t worker_stack_size) : name_(name), task_queue_lock_("task queue lock"), task_queue_condition_("task queue condition", task_queue_lock_), @@ -137,15 +140,13 @@ ThreadPool::ThreadPool(const char* name, size_t num_threads, bool create_peers) creation_barier_(num_threads + 1), max_active_workers_(num_threads), create_peers_(create_peers) { - Thread* self = Thread::Current(); while (GetThreadCount() < num_threads) { const std::string worker_name = StringPrintf("%s worker thread %zu", name_.c_str(), GetThreadCount()); - threads_.push_back( - new ThreadPoolWorker(this, worker_name, ThreadPoolWorker::kDefaultStackSize)); + threads_.push_back(new ThreadPoolWorker(this, worker_name, worker_stack_size)); } // Wait for all of the threads to attach. - creation_barier_.Wait(self); + creation_barier_.Wait(Thread::Current()); } void ThreadPool::SetMaxActiveWorkers(size_t threads) { diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h index 98a1193e72..fee009b7c0 100644 --- a/runtime/thread_pool.h +++ b/runtime/thread_pool.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_THREAD_POOL_H_ #include <deque> +#include <functional> #include <vector> #include "barrier.h" @@ -48,6 +49,18 @@ class SelfDeletingTask : public Task { } }; +class FunctionTask : public SelfDeletingTask { + public: + explicit FunctionTask(std::function<void(Thread*)>&& func) : func_(std::move(func)) {} + + void Run(Thread* self) override { + func_(self); + } + + private: + std::function<void(Thread*)> func_; +}; + class ThreadPoolWorker { public: static const size_t kDefaultStackSize = 1 * MB; @@ -110,7 +123,10 @@ class ThreadPool { // If create_peers is true, all worker threads will have a Java peer object. Note that if the // pool is asked to do work on the current thread (see Wait), a peer may not be available. Wait // will conservatively abort if create_peers and do_work are true. - ThreadPool(const char* name, size_t num_threads, bool create_peers = false); + ThreadPool(const char* name, + size_t num_threads, + bool create_peers = false, + size_t worker_stack_size = ThreadPoolWorker::kDefaultStackSize); virtual ~ThreadPool(); // Wait for all tasks currently on queue to get completed. If the pool has been stopped, only diff --git a/test/118-noimage-dex2oat/run b/test/118-noimage-dex2oat/run index d68b0a0b2c..d1b9725628 100644 --- a/test/118-noimage-dex2oat/run +++ b/test/118-noimage-dex2oat/run @@ -31,39 +31,26 @@ if [[ "${flags}" == *--no-relocate* ]] ; then exit 1 fi -if [[ $@ == *--host* ]]; then - framework="${ANDROID_HOST_OUT}/framework" - bpath_suffix="-hostdex" -else - framework="/system/framework" - bpath_suffix="" -fi -bpath="${framework}/core-libart${bpath_suffix}.jar" -bpath="${bpath}:${framework}/conscrypt${bpath_suffix}.jar" -bpath="${bpath}:${framework}/okhttp${bpath_suffix}.jar" -bpath="${bpath}:${framework}/bouncycastle${bpath_suffix}.jar" -bpath_arg="--runtime-option -Xbootclasspath:${bpath}" - # Make sure we can run without an oat file. echo "Run -Xnoimage-dex2oat" -${RUN} ${flags} ${bpath_arg} --runtime-option -Xnoimage-dex2oat +${RUN} ${flags} --runtime-option -Xnoimage-dex2oat return_status1=$? # Make sure we cannot run without an oat file without fallback. echo "Run -Xnoimage-dex2oat -Xno-dex-file-fallback" -${RUN} ${flags} ${bpath_arg} --runtime-option -Xnoimage-dex2oat \ +${RUN} ${flags} --runtime-option -Xnoimage-dex2oat \ --runtime-option -Xno-dex-file-fallback return_status2=$? # Make sure we can run with the oat file. echo "Run -Ximage-dex2oat" -${RUN} ${flags} ${bpath_arg} --runtime-option -Ximage-dex2oat +${RUN} ${flags} --runtime-option -Ximage-dex2oat return_status3=$? # Make sure we can run with the default settings. echo "Run default" -${RUN} ${flags} ${bpath_arg} +${RUN} ${flags} return_status4=$? # Make sure we don't silently ignore an early failure. diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 148aea48ae..5d07601005 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -50,9 +50,9 @@ ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += libopenjdkjvmti-target libopenjdkjvmtid ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/core-libart-testdex.jar ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/core-simple-testdex.jar +ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/conscrypt-testdex.jar ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/okhttp-testdex.jar ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/bouncycastle-testdex.jar -ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/conscrypt-testdex.jar # All tests require the host executables. The tests also depend on the core images, but on # specific version depending on the compiler. diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index ac6002bcea..4e5152b135 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -541,23 +541,38 @@ if [ "$USE_JVM" = "y" ]; then exit fi - -if [ "$HAVE_IMAGE" = "n" ]; then - if [ "${HOST}" = "y" ]; then - framework="${ANDROID_HOST_OUT}/framework" - bpath_suffix="-hostdex" +bpath_modules="core-oj core-libart core-simple conscrypt okhttp bouncycastle" +if [ "${HOST}" = "y" ]; then + framework="${ANDROID_HOST_OUT}/framework" + if [ "${ANDROID_HOST_OUT:0:${#ANDROID_BUILD_TOP}+1}" = "${ANDROID_BUILD_TOP}/" ]; then + framework_location="${ANDROID_HOST_OUT:${#ANDROID_BUILD_TOP}+1}/framework" else - framework="${ANDROID_ROOT}/framework" - bpath_suffix="-testdex" + echo "error: ANDROID_BUILD_TOP/ is not a prefix of ANDROID_HOST_OUT" + echo "ANDROID_BUILD_TOP=${ANDROID_BUILD_TOP}" + echo "ANDROID_HOST_OUT=${ANDROID_HOST_OUT}" + exit fi - bpath="${framework}/core-libart${bpath_suffix}.jar" - bpath="${bpath}:${framework}/core-oj${bpath_suffix}.jar" - bpath="${bpath}:${framework}/core-simple${bpath_suffix}.jar" - bpath="${bpath}:${framework}/conscrypt${bpath_suffix}.jar" - bpath="${bpath}:${framework}/okhttp${bpath_suffix}.jar" - bpath="${bpath}:${framework}/bouncycastle${bpath_suffix}.jar" - # Pass down the bootclasspath - FLAGS="${FLAGS} -Xbootclasspath:${bpath}" + bpath_suffix="-hostdex" +else + framework="${ANDROID_ROOT}/framework" + framework_location="${ANDROID_ROOT}/framework" + bpath_suffix="-testdex" +fi +bpath="" +bpath_locations="" +bpath_separator="" +for bpath_module in ${bpath_modules}; do + bpath+="${bpath_separator}${framework}/${bpath_module}${bpath_suffix}.jar" + bpath_locations+="${bpath_separator}${framework_location}/${bpath_module}${bpath_suffix}.jar" + bpath_separator=":" +done +# Pass down the bootclasspath +FLAGS="${FLAGS} -Xbootclasspath:${bpath}" +FLAGS="${FLAGS} -Xbootclasspath-locations:${bpath_locations}" +COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xbootclasspath:${bpath}" +COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xbootclasspath-locations:${bpath_locations}" + +if [ "$HAVE_IMAGE" = "n" ]; then # Disable image dex2oat - this will forbid the runtime to patch or compile an image. FLAGS="${FLAGS} -Xnoimage-dex2oat" diff --git a/tools/bootjars.sh b/tools/bootjars.sh index dca209d580..ad6ee6b058 100755 --- a/tools/bootjars.sh +++ b/tools/bootjars.sh @@ -54,7 +54,7 @@ done if [[ $mode == target ]]; then if [[ $core_jars_only == y ]]; then - selected_env_var=TARGET_CORE_JARS + selected_env_var=TARGET_TEST_CORE_JARS else selected_env_var=PRODUCT_BOOT_JARS fi @@ -64,11 +64,31 @@ elif [[ $mode == host ]]; then echo "Error: --host does not have non-core boot jars, --core required" >&2 exit 1 fi - selected_env_var=HOST_CORE_JARS + selected_env_var=HOST_TEST_CORE_JARS intermediates_env_var=HOST_OUT_COMMON_INTERMEDIATES fi -boot_jars_list=$(get_build_var "$selected_env_var") +if [[ $core_jars_only == y ]]; then + # FIXME: The soong invocation we're using for getting the variables does not give us anything + # defined in Android.common_path.mk, otherwise we would just use HOST-/TARGET_TEST_CORE_JARS. + + # The core_jars_list must match the TEST_CORE_JARS variable in the Android.common_path.mk . + core_jars_list="core-oj core-libart core-simple conscrypt okhttp bouncycastle" + core_jars_suffix= + if [[ $mode == target ]]; then + core_jars_suffix=-testdex + elif [[ $mode == host ]]; then + core_jars_suffix=-hostdex + fi + boot_jars_list="" + boot_separator="" + for boot_module in ${core_jars_list}; do + boot_jars_list+="${boot_separator}${boot_module}${core_jars_suffix}" + boot_separator=" " + done +else + boot_jars_list=$(get_build_var "$selected_env_var") +fi # Print only the list of boot jars. if [[ $print_file_path == n ]]; then diff --git a/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeHandlerTest.java b/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeHandlerTest.java index 9d2f014e4e..9f924b2716 100644 --- a/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeHandlerTest.java +++ b/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeHandlerTest.java @@ -67,7 +67,7 @@ public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase { " @Annotation(returnType=Integer.class)", " public String method() {return null;}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, @@ -91,7 +91,7 @@ public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase { " @Annotation(returnType=Integer.class)", " public String method() {return null;}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, @@ -113,7 +113,7 @@ public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase { " @Annotation(returnType=Integer.class)", " public String method() {return null;}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, @@ -138,7 +138,7 @@ public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase { " @Annotation(returnType=Integer.class)", " public String field;", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, diff --git a/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java b/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java index 1202564948..25f284455b 100644 --- a/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java +++ b/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java @@ -74,7 +74,7 @@ public class CovariantReturnTypeMultiHandlerTest extends AnnotationHandlerTestBa " @Annotation(returnType=Long.class)", " public String method() {return null;}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of("Lannotation/Annotation$Multi;", @@ -104,7 +104,7 @@ public class CovariantReturnTypeMultiHandlerTest extends AnnotationHandlerTestBa " @Annotation(returnType=Long.class)", " public String method() {return null;}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of("Lannotation/Annotation$Multi;", diff --git a/tools/class2greylist/test/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandlerTest.java b/tools/class2greylist/test/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandlerTest.java index cdf01afe7c..dc767fe3f5 100644 --- a/tools/class2greylist/test/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandlerTest.java +++ b/tools/class2greylist/test/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandlerTest.java @@ -82,7 +82,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno", " public void method() {}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) @@ -103,7 +103,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno", " public Class() {}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) @@ -124,7 +124,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno", " public int i;", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) @@ -145,7 +145,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno(expectedSignature=\"La/b/Class;->method()V\")", " public void method() {}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) @@ -166,7 +166,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno(expectedSignature=\"La/b/Class;->nomethod()V\")", " public void method() {}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) @@ -186,7 +186,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " public void method() {}", " }", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class$Inner"), mStatus, ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) @@ -205,7 +205,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT "public class Class {", " public void method() {}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) @@ -224,7 +224,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")", " public void method(T arg) {}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)) @@ -252,7 +252,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")", " public void method(T arg) {}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)); @@ -284,7 +284,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")", " public void method(T arg) {}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)); @@ -320,7 +320,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT "package a.b;", "public class Class extends Base implements Interface {", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)); @@ -354,7 +354,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno", " public void method(T arg) {}", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Set<String> publicApis = Sets.newHashSet( "La/b/Base;->method(Ljava/lang/Object;)V", @@ -385,7 +385,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno(expectedSignature=\"La/b/Class;->field:I\")", " public volatile int field;", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler( @@ -407,7 +407,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno(expectedSignature=\"La/b/Class;->wrong:I\")", " public volatile int field;", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP)); @@ -424,7 +424,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno(maxTargetSdk=1)", " public int field;", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler( @@ -444,7 +444,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno", " public int field;", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler( @@ -464,7 +464,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno(maxTargetSdk=2)", " public int field;", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); Map<String, AnnotationHandler> handlerMap = ImmutableMap.of(ANNOTATION, createGreylistHandler( @@ -493,7 +493,7 @@ public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerT " @Anno2(maxTargetSdk=2, trackingBug=123456789)", " public int field;", "}")); - assertThat(mJavac.compile()).isTrue(); + mJavac.compile(); new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, ImmutableMap.of("Lannotation/Anno2;", createGreylistHandler(x -> true, ImmutableMap.of(2, "flag2"))) diff --git a/tools/class2greylist/test/src/com/android/javac/Javac.java b/tools/class2greylist/test/src/com/android/javac/Javac.java index 202f4121fc..94e4e49ea8 100644 --- a/tools/class2greylist/test/src/com/android/javac/Javac.java +++ b/tools/class2greylist/test/src/com/android/javac/Javac.java @@ -18,6 +18,7 @@ package com.android.javac; import com.google.common.io.Files; +import java.util.stream.Collectors; import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.JavaClass; @@ -76,15 +77,24 @@ public class Javac { return this; } - public boolean compile() { + public void compile() { + DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>(); JavaCompiler.CompilationTask task = mJavac.getTask( null, mFileMan, - null, + diagnosticCollector, null, null, mCompilationUnits); - return task.call(); + boolean result = task.call(); + if (!result) { + throw new IllegalStateException( + "Compilation failed:" + + diagnosticCollector.getDiagnostics() + .stream() + .map(Object::toString) + .collect(Collectors.joining("\n"))); + } } public InputStream getClassFile(String classname) throws IOException { diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt index a5fa332050..f97dd4fc7f 100644 --- a/tools/libcore_failures.txt +++ b/tools/libcore_failures.txt @@ -157,7 +157,6 @@ { description: "Missing resource in classpath", result: EXEC_FAILED, - modes: [device], names: ["libcore.java.util.prefs.OldAbstractPreferencesTest#testClear", "libcore.java.util.prefs.OldAbstractPreferencesTest#testExportNode", "libcore.java.util.prefs.OldAbstractPreferencesTest#testExportSubtree", @@ -187,7 +186,8 @@ "org.apache.harmony.tests.java.util.prefs.AbstractPreferencesTest#testExportSubtree", "org.apache.harmony.tests.java.util.prefs.AbstractPreferencesTest#testFlush", "org.apache.harmony.tests.java.util.prefs.AbstractPreferencesTest#testSync", - "org.apache.harmony.tests.java.util.prefs.FilePreferencesImplTest#testPutGet"] + "org.apache.harmony.tests.java.util.prefs.FilePreferencesImplTest#testPutGet"], + bug: 120526172 }, { description: "Only work with --mode=activity", |