diff options
57 files changed, 616 insertions, 378 deletions
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk index 775443bfef..03e68ae93c 100644 --- a/build/Android.common_path.mk +++ b/build/Android.common_path.mk @@ -74,7 +74,7 @@ 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. -TEST_CORE_JARS := core-oj core-libart core-simple +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) diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index e610bb11b7..6885946c40 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -422,6 +422,8 @@ ifneq ($(ART_TEST_ANDROID_ROOT),) ART_GTEST_TARGET_ANDROID_ROOT := $(ART_TEST_ANDROID_ROOT) endif +ART_GTEST_TARGET_ANDROID_RUNTIME_ROOT := '/apex/com.android.runtime' + # Define a make rule for a target device gtest. # $(1): gtest name - the name of the test we're building such as leb128_test. # $(2): path relative to $OUT to the test binary @@ -452,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) @@ -472,7 +477,9 @@ $$(gtest_rule): test-art-target-sync $(hide) $(ADB) shell $$(PRIVATE_MAYBE_CHROOT_COMMAND) chmod 755 $$(PRIVATE_TARGET_EXE) $(hide) $$(call ART_TEST_SKIP,$$@) && \ ($(ADB) shell "$$(PRIVATE_MAYBE_CHROOT_COMMAND) env $(GCOV_ENV) LD_LIBRARY_PATH=$(4) \ - ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) $$(PRIVATE_TARGET_EXE) \ + ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \ + ANDROID_RUNTIME_ROOT=$(ART_GTEST_TARGET_ANDROID_RUNTIME_ROOT) \ + $$(PRIVATE_TARGET_EXE) \ && touch $$(PRIVATE_GTEST_WITNESS)" \ && ($(ADB) pull $$(PRIVATE_GTEST_WITNESS) /tmp/ && $$(call ART_TEST_PASSED,$$@)) \ || $$(call ART_TEST_FAILED,$$@)) @@ -717,6 +724,7 @@ ART_TEST_TARGET_GTEST$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES := ART_TEST_TARGET_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES := ART_TEST_TARGET_GTEST_RULES := ART_GTEST_TARGET_ANDROID_ROOT := +ART_GTEST_TARGET_ANDROID_RUNTIME_ROOT := ART_GTEST_class_linker_test_DEX_DEPS := ART_GTEST_class_table_test_DEX_DEPS := ART_GTEST_compiler_driver_test_DEX_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/driver/compiler_options.h b/compiler/driver/compiler_options.h index 17a779c965..a8f246dcab 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -39,6 +39,10 @@ namespace verifier { class VerifierDepsTest; } // namespace verifier +namespace linker { +class Arm64RelativePatcherTest; +} // namespace linker + class DexFile; enum class InstructionSet; class InstructionSetFeatures; @@ -450,6 +454,7 @@ class CompilerOptions final { friend class CommonCompilerTest; friend class jit::JitCompiler; friend class verifier::VerifierDepsTest; + friend class linker::Arm64RelativePatcherTest; template <class Base> friend bool ReadCompilerOptions(Base& map, CompilerOptions* options, std::string* error_msg); 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/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index bbf167d615..9e2fd9ef84 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -885,7 +885,8 @@ CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph, location_builder_(graph, this), instruction_visitor_(graph, this), move_resolver_(graph->GetAllocator(), this), - assembler_(graph->GetAllocator()), + assembler_(graph->GetAllocator(), + compiler_options.GetInstructionSetFeatures()->AsArm64InstructionSetFeatures()), uint32_literals_(std::less<uint32_t>(), graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), uint64_literals_(std::less<uint64_t>(), diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index f186191a0f..b5a7c137f6 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -823,6 +823,33 @@ TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) { InternalCodeAllocator code_allocator; codegen.Finalize(&code_allocator); } + +// Check that ART ISA Features are propagated to VIXL for arm64 (using cortex-a75 as example). +TEST_F(CodegenTest, ARM64IsaVIXLFeaturesA75) { + OverrideInstructionSetFeatures(InstructionSet::kArm64, "cortex-a75"); + HGraph* graph = CreateGraph(); + arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_); + vixl::CPUFeatures* features = codegen.GetVIXLAssembler()->GetCPUFeatures(); + + EXPECT_TRUE(features->Has(vixl::CPUFeatures::kCRC32)); + EXPECT_TRUE(features->Has(vixl::CPUFeatures::kDotProduct)); + EXPECT_TRUE(features->Has(vixl::CPUFeatures::kFPHalf)); + EXPECT_TRUE(features->Has(vixl::CPUFeatures::kAtomics)); +} + +// Check that ART ISA Features are propagated to VIXL for arm64 (using cortex-a53 as example). +TEST_F(CodegenTest, ARM64IsaVIXLFeaturesA53) { + OverrideInstructionSetFeatures(InstructionSet::kArm64, "cortex-a53"); + HGraph* graph = CreateGraph(); + arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_); + vixl::CPUFeatures* features = codegen.GetVIXLAssembler()->GetCPUFeatures(); + + EXPECT_TRUE(features->Has(vixl::CPUFeatures::kCRC32)); + EXPECT_FALSE(features->Has(vixl::CPUFeatures::kDotProduct)); + EXPECT_FALSE(features->Has(vixl::CPUFeatures::kFPHalf)); + EXPECT_FALSE(features->Has(vixl::CPUFeatures::kAtomics)); +} + #endif #ifdef ART_ENABLE_CODEGEN_mips 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/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc index c83fd4404a..d7ade058a4 100644 --- a/compiler/utils/arm64/assembler_arm64.cc +++ b/compiler/utils/arm64/assembler_arm64.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "arch/arm64/instruction_set_features_arm64.h" #include "assembler_arm64.h" #include "entrypoints/quick/quick_entrypoints.h" #include "heap_poisoning.h" @@ -31,6 +32,37 @@ namespace arm64 { #define ___ vixl_masm_. #endif +// Sets vixl::CPUFeatures according to ART instruction set features. +static void SetVIXLCPUFeaturesFromART(vixl::aarch64::MacroAssembler* vixl_masm_, + const Arm64InstructionSetFeatures* art_features) { + // Retrieve already initialized default features of vixl. + vixl::CPUFeatures* features = vixl_masm_->GetCPUFeatures(); + + DCHECK(features->Has(vixl::CPUFeatures::kFP)); + DCHECK(features->Has(vixl::CPUFeatures::kNEON)); + DCHECK(art_features != nullptr); + if (art_features->HasCRC()) { + features->Combine(vixl::CPUFeatures::kCRC32); + } + if (art_features->HasDotProd()) { + features->Combine(vixl::CPUFeatures::kDotProduct); + } + if (art_features->HasFP16()) { + features->Combine(vixl::CPUFeatures::kFPHalf); + } + if (art_features->HasLSE()) { + features->Combine(vixl::CPUFeatures::kAtomics); + } +} + +Arm64Assembler::Arm64Assembler(ArenaAllocator* allocator, + const Arm64InstructionSetFeatures* art_features) + : Assembler(allocator) { + if (art_features != nullptr) { + SetVIXLCPUFeaturesFromART(&vixl_masm_, art_features); + } +} + void Arm64Assembler::FinalizeCode() { ___ FinalizeCode(); } diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h index 74537dd5a3..fdecab8251 100644 --- a/compiler/utils/arm64/assembler_arm64.h +++ b/compiler/utils/arm64/assembler_arm64.h @@ -37,6 +37,9 @@ #pragma GCC diagnostic pop namespace art { + +class Arm64InstructionSetFeatures; + namespace arm64 { #define MEM_OP(...) vixl::aarch64::MemOperand(__VA_ARGS__) @@ -63,7 +66,8 @@ enum StoreOperandType { class Arm64Assembler final : public Assembler { public: - explicit Arm64Assembler(ArenaAllocator* allocator) : Assembler(allocator) {} + explicit Arm64Assembler( + ArenaAllocator* allocator, const Arm64InstructionSetFeatures* features = nullptr); virtual ~Arm64Assembler() {} diff --git a/compiler/utils/assembler_test_base.h b/compiler/utils/assembler_test_base.h index 778a01566c..5fa0b3cd39 100644 --- a/compiler/utils/assembler_test_base.h +++ b/compiler/utils/assembler_test_base.h @@ -59,12 +59,12 @@ class AssemblerTestInfrastructure { disassembler_cmd_name_(disasm), disassembler_parameters_(disasm_params) { // Fake a runtime test for ScratchFile - CommonRuntimeTest::SetUpAndroidData(android_data_); + CommonRuntimeTest::SetUpAndroidDataDir(android_data_); } virtual ~AssemblerTestInfrastructure() { // We leave temporaries in case this failed so we can debug issues. - CommonRuntimeTest::TearDownAndroidData(android_data_, false); + CommonRuntimeTest::TearDownAndroidDataDir(android_data_, false); tmpnam_ = ""; } diff --git a/dex2oat/linker/arm64/relative_patcher_arm64_test.cc b/dex2oat/linker/arm64/relative_patcher_arm64_test.cc index f242ae286b..9e91c6568a 100644 --- a/dex2oat/linker/arm64/relative_patcher_arm64_test.cc +++ b/dex2oat/linker/arm64/relative_patcher_arm64_test.cc @@ -177,6 +177,13 @@ class Arm64RelativePatcherTest : public RelativePatcherTest { OptimizingUnitTestHelper helper; HGraph* graph = helper.CreateGraph(); CompilerOptions compiler_options; + + // Set isa to arm64. + compiler_options.instruction_set_ = instruction_set_; + compiler_options.instruction_set_features_ = + InstructionSetFeatures::FromBitmap(instruction_set_, instruction_set_features_->AsBitmap()); + CHECK(compiler_options.instruction_set_features_->Equals(instruction_set_features_.get())); + arm64::CodeGeneratorARM64 codegen(graph, compiler_options); ArenaVector<uint8_t> code(helper.GetAllocator()->Adapter()); codegen.EmitThunkCode(patch, &code, debug_name); diff --git a/imgdiag/imgdiag_test.cc b/imgdiag/imgdiag_test.cc index c789fd78d6..739d9b8329 100644 --- a/imgdiag/imgdiag_test.cc +++ b/imgdiag/imgdiag_test.cc @@ -91,8 +91,8 @@ class ImgDiagTest : public CommonRuntimeTest { // Run imgdiag --image-diff-pid=$image_diff_pid and wait until it's done with a 0 exit code. std::vector<std::string> exec_argv = { file_path, - "--image-diff-pid=" + PidToString(image_diff_pid), - "--zygote-diff-pid=" + PidToString(image_diff_pid), + "--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", @@ -109,12 +109,6 @@ class ImgDiagTest : public CommonRuntimeTest { } private: - std::string PidToString(pid_t pid) { - std::stringstream sstream; - sstream << pid; - return sstream.str(); - } - std::string runtime_args_image_; std::string boot_image_location_; }; diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc index b055bb45aa..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> @@ -110,49 +111,59 @@ void ScratchFile::Unlink() { CHECK_EQ(0, unlink_result); } -void CommonArtTestImpl::SetUpAndroidRoot() { +void CommonArtTestImpl::SetUpAndroidRootEnvVars() { if (IsHost()) { - // $ANDROID_ROOT is set on the device, but not necessarily on the host. - // But it needs to be set so that icu4c can find its locale data. - const char* android_root_from_env = getenv("ANDROID_ROOT"); - if (android_root_from_env == nullptr) { - // Use ANDROID_HOST_OUT for ANDROID_ROOT if it is set. - const char* android_host_out = getenv("ANDROID_HOST_OUT"); - if (android_host_out != nullptr) { - setenv("ANDROID_ROOT", android_host_out, 1); - } else { - // Build it from ANDROID_BUILD_TOP or cwd - std::string root; - const char* android_build_top = getenv("ANDROID_BUILD_TOP"); - if (android_build_top != nullptr) { - root += android_build_top; - } else { - // Not set by build server, so default to current directory - char* cwd = getcwd(nullptr, 0); - setenv("ANDROID_BUILD_TOP", cwd, 1); - root += cwd; - free(cwd); - } + // Make sure that ANDROID_BUILD_TOP is set. If not, set it from CWD. + const char* android_build_top_from_env = getenv("ANDROID_BUILD_TOP"); + if (android_build_top_from_env == nullptr) { + // Not set by build server, so default to current directory. + char* cwd = getcwd(nullptr, 0); + setenv("ANDROID_BUILD_TOP", cwd, 1); + free(cwd); + android_build_top_from_env = getenv("ANDROID_BUILD_TOP"); + } + + const char* android_host_out_from_env = getenv("ANDROID_HOST_OUT"); + if (android_host_out_from_env == nullptr) { + // Not set by build server, so default to the usual value of + // ANDROID_HOST_OUT. + std::string android_host_out = android_build_top_from_env; #if defined(__linux__) - root += "/out/host/linux-x86"; + android_host_out += "/out/host/linux-x86"; #elif defined(__APPLE__) - root += "/out/host/darwin-x86"; + android_host_out += "/out/host/darwin-x86"; #else #error unsupported OS #endif - setenv("ANDROID_ROOT", root.c_str(), 1); - } + setenv("ANDROID_HOST_OUT", android_host_out.c_str(), 1); + android_host_out_from_env = getenv("ANDROID_HOST_OUT"); } - setenv("LD_LIBRARY_PATH", ":", 0); // Required by java.lang.System.<clinit>. - // Not set by build server, so default - if (getenv("ANDROID_HOST_OUT") == nullptr) { - setenv("ANDROID_HOST_OUT", getenv("ANDROID_ROOT"), 1); + // Environment variable ANDROID_ROOT is set on the device, but not + // necessarily on the host. + const char* android_root_from_env = getenv("ANDROID_ROOT"); + if (android_root_from_env == nullptr) { + // Use ANDROID_HOST_OUT for ANDROID_ROOT. + setenv("ANDROID_ROOT", android_host_out_from_env, 1); + android_root_from_env = getenv("ANDROID_ROOT"); + } + + // Environment variable ANDROID_RUNTIME_ROOT is set on the device, but not + // necessarily on the host. It needs to be set so that various libraries + // like icu4c can find their data files. + const char* android_runtime_root_from_env = getenv("ANDROID_RUNTIME_ROOT"); + if (android_runtime_root_from_env == nullptr) { + // Use ${ANDROID_HOST_OUT}/com.android.runtime for ANDROID_RUNTIME_ROOT. + std::string android_runtime_root = android_host_out_from_env; + android_runtime_root += "/com.android.runtime"; + setenv("ANDROID_RUNTIME_ROOT", android_runtime_root.c_str(), 1); } + + setenv("LD_LIBRARY_PATH", ":", 0); // Required by java.lang.System.<clinit>. } } -void CommonArtTestImpl::SetUpAndroidData(std::string& android_data) { +void CommonArtTestImpl::SetUpAndroidDataDir(std::string& android_data) { // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of dalvik-cache if (IsHost()) { const char* tmpdir = getenv("TMPDIR"); @@ -172,15 +183,16 @@ void CommonArtTestImpl::SetUpAndroidData(std::string& android_data) { } void CommonArtTestImpl::SetUp() { - SetUpAndroidRoot(); - SetUpAndroidData(android_data_); + SetUpAndroidRootEnvVars(); + SetUpAndroidDataDir(android_data_); dalvik_cache_.append(android_data_.c_str()); dalvik_cache_.append("/dalvik-cache"); int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700); ASSERT_EQ(mkdir_result, 0); } -void CommonArtTestImpl::TearDownAndroidData(const std::string& android_data, bool fail_on_error) { +void CommonArtTestImpl::TearDownAndroidDataDir(const std::string& android_data, + bool fail_on_error) { if (fail_on_error) { ASSERT_EQ(rmdir(android_data.c_str()), 0); } else { @@ -295,7 +307,7 @@ void CommonArtTestImpl::TearDown() { ClearDirectory(dalvik_cache_.c_str()); int rmdir_cache_result = rmdir(dalvik_cache_.c_str()); ASSERT_EQ(0, rmdir_cache_result); - TearDownAndroidData(android_data_, true); + TearDownAndroidDataDir(android_data_, true); dalvik_cache_.clear(); } @@ -323,6 +335,9 @@ std::vector<std::string> CommonArtTestImpl::GetLibCoreDexFileNames() { "core-oj", "core-libart", "core-simple", + "conscrypt", + "okhttp", + "bouncycastle", }; std::vector<std::string> result; @@ -355,14 +370,7 @@ std::vector<std::string> CommonArtTestImpl::GetLibCoreDexLocations() { std::string CommonArtTestImpl::GetClassPathOption(const char* option, const std::vector<std::string>& class_path) { - std::string option_string = option; - const char* separator = ""; - for (const std::string& core_dex_file_name : class_path) { - option_string += separator; - option_string += core_dex_file_name; - separator = ":"; - } - return option_string; + 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 5c2ae82f7d..3e2340f0a7 100644 --- a/libartbase/base/common_art_test.h +++ b/libartbase/base/common_art_test.h @@ -85,13 +85,16 @@ class CommonArtTestImpl { CommonArtTestImpl() = default; virtual ~CommonArtTestImpl() = default; - static void SetUpAndroidRoot(); + // Set up ANDROID_BUILD_TOP, ANDROID_HOST_OUT, ANDROID_ROOT and ANDROID_RUNTIME_ROOT + // environment variables using sensible defaults if not already set. + static void SetUpAndroidRootEnvVars(); + // Set up the ANDROID_DATA environment variable, creating the directory if required. // Note: setting up ANDROID_DATA may create a temporary directory. If this is used in a // non-derived class, be sure to also call the corresponding tear-down below. - static void SetUpAndroidData(std::string& android_data); + static void SetUpAndroidDataDir(std::string& android_data); - static void TearDownAndroidData(const std::string& android_data, bool fail_on_error); + static void TearDownAndroidDataDir(const std::string& android_data, bool fail_on_error); // Gets the paths of the libcore dex files. static std::vector<std::string> GetLibCoreDexFileNames(); diff --git a/libartbase/base/hiddenapi_flags.h b/libartbase/base/hiddenapi_flags.h index 9ea01d7f3b..8c1ffd5739 100644 --- a/libartbase/base/hiddenapi_flags.h +++ b/libartbase/base/hiddenapi_flags.h @@ -44,11 +44,12 @@ class ApiList { // The max release code implicitly includes all maintenance releases, // e.g. GreylistMaxO is accessible to targetSdkVersion <= 27 (O_MR1). kGreylistMaxO = 3, + kGreylistMaxP = 4, // Special values kInvalid = static_cast<uint32_t>(-1), kMinValue = kWhitelist, - kMaxValue = kGreylistMaxO, + kMaxValue = kGreylistMaxP, }; static constexpr const char* kNames[] = { @@ -56,6 +57,7 @@ class ApiList { "greylist", "blacklist", "greylist-max-o", + "greylist-max-p", }; static constexpr const char* kInvalidName = "invalid"; @@ -65,6 +67,7 @@ class ApiList { /* greylist */ SdkVersion::kMax, /* blacklist */ SdkVersion::kMin, /* greylist-max-o */ SdkVersion::kO_MR1, + /* greylist-max-p */ SdkVersion::kP, }; static ApiList MinValue() { return ApiList(Value::kMinValue); } @@ -79,6 +82,7 @@ class ApiList { static ApiList Greylist() { return ApiList(Value::kGreylist); } static ApiList Blacklist() { return ApiList(Value::kBlacklist); } static ApiList GreylistMaxO() { return ApiList(Value::kGreylistMaxO); } + static ApiList GreylistMaxP() { return ApiList(Value::kGreylistMaxP); } static ApiList Invalid() { return ApiList(Value::kInvalid); } // Decodes ApiList from dex hiddenapi flags. diff --git a/libartbase/base/sdk_version.h b/libartbase/base/sdk_version.h index 4372e5a02f..e2dbc502dc 100644 --- a/libartbase/base/sdk_version.h +++ b/libartbase/base/sdk_version.h @@ -33,7 +33,6 @@ enum class SdkVersion : uint32_t { kO = 26u, kO_MR1 = 27u, kP = 28u, - kP_MR1 = 29u, kMax = std::numeric_limits<uint32_t>::max(), }; diff --git a/libartbase/base/unix_file/random_access_file_test.h b/libartbase/base/unix_file/random_access_file_test.h index dbe6ca948f..178f89d5a5 100644 --- a/libartbase/base/unix_file/random_access_file_test.h +++ b/libartbase/base/unix_file/random_access_file_test.h @@ -35,11 +35,11 @@ class RandomAccessFileTest : public testing::Test { virtual RandomAccessFile* MakeTestFile() = 0; virtual void SetUp() { - art::CommonArtTest::SetUpAndroidData(android_data_); + art::CommonArtTest::SetUpAndroidDataDir(android_data_); } virtual void TearDown() { - art::CommonArtTest::TearDownAndroidData(android_data_, true); + art::CommonArtTest::TearDownAndroidDataDir(android_data_, true); } std::string GetTmpPath(const std::string& name) { diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index cabb758912..6ca4e3846c 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -1427,11 +1427,6 @@ void Redefiner::ClassRedefinition::UpdateMethods(art::ObjPtr<art::mirror::Class> method.SetCodeItemOffset(dex_file_->FindCodeItemOffset(class_def, dex_method_idx)); // Clear all the intrinsics related flags. method.SetNotIntrinsic(); - // Disable hiddenapi checks when accessing this method. - // Redefining hiddenapi flags is unsupported for the same reasons as redefining - // access flags. Moreover, ArtMethod loses pointer to the old dex file, so just - // disable the checks completely for consistency. - method.SetAccessFlags(method.GetAccessFlags() | art::kAccPublicApi); } } @@ -1450,11 +1445,6 @@ void Redefiner::ClassRedefinition::UpdateFields(art::ObjPtr<art::mirror::Class> CHECK(new_field_id != nullptr); // We only need to update the index since the other data in the ArtField cannot be updated. field.SetDexFieldIndex(dex_file_->GetIndexForFieldId(*new_field_id)); - // Disable hiddenapi checks when accessing this method. - // Redefining hiddenapi flags is unsupported for the same reasons as redefining - // access flags. Moreover, ArtField loses pointer to the old dex file, so just - // disable the checks completely for consistency. - field.SetAccessFlags(field.GetAccessFlags() | art::kAccPublicApi); } } } @@ -1469,15 +1459,25 @@ void Redefiner::ClassRedefinition::UpdateClass( UpdateMethods(mclass, class_def); UpdateFields(mclass); + art::ObjPtr<art::mirror::ClassExt> ext(mclass->GetExtData()); + CHECK(!ext.IsNull()); + ext->SetOriginalDexFile(original_dex_file); + + // If this is the first time the class is being redefined, store + // the native DexFile pointer and initial ClassDef index in ClassExt. + // This preserves the pointer for hiddenapi access checks which need + // to read access flags from the initial DexFile. + if (ext->GetPreRedefineDexFile() == nullptr) { + ext->SetPreRedefineDexFile(&mclass->GetDexFile()); + ext->SetPreRedefineClassDefIndex(mclass->GetDexClassDefIndex()); + } + // Update the class fields. // Need to update class last since the ArtMethod gets its DexFile from the class (which is needed // to call GetReturnTypeDescriptor and GetParameterTypeList above). mclass->SetDexCache(new_dex_cache.Ptr()); mclass->SetDexClassDefIndex(dex_file_->GetIndexForClassDef(class_def)); mclass->SetDexTypeIndex(dex_file_->GetIndexForTypeId(*dex_file_->FindTypeId(class_sig_.c_str()))); - art::ObjPtr<art::mirror::ClassExt> ext(mclass->GetExtData()); - CHECK(!ext.IsNull()); - ext->SetOriginalDexFile(original_dex_file); // Notify the jit that all the methods in this class were redefined. Need to do this last since // the jit relies on the dex_file_ being correct (for native methods at least) to find the method 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/class_linker_test.cc b/runtime/class_linker_test.cc index 56fdd06ff2..fe45b9e1f0 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -611,6 +611,10 @@ struct ClassExtOffsets : public CheckOffsets<mirror::ClassExt> { addOffset(OFFSETOF_MEMBER(mirror::ClassExt, obsolete_dex_caches_), "obsoleteDexCaches"); addOffset(OFFSETOF_MEMBER(mirror::ClassExt, obsolete_methods_), "obsoleteMethods"); addOffset(OFFSETOF_MEMBER(mirror::ClassExt, original_dex_file_), "originalDexFile"); + addOffset(OFFSETOF_MEMBER(mirror::ClassExt, pre_redefine_class_def_index_), + "preRedefineClassDefIndex"); + addOffset(OFFSETOF_MEMBER(mirror::ClassExt, pre_redefine_dex_file_ptr_), + "preRedefineDexFilePtr"); addOffset(OFFSETOF_MEMBER(mirror::ClassExt, verify_error_), "verifyError"); } }; 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/hidden_api.cc b/runtime/hidden_api.cc index 6cdba73c30..e0939ddbdb 100644 --- a/runtime/hidden_api.cc +++ b/runtime/hidden_api.cc @@ -21,7 +21,10 @@ #include "art_field-inl.h" #include "art_method-inl.h" #include "base/dumpable.h" +#include "class_root.h" #include "dex/class_accessor-inl.h" +#include "dex/dex_file_loader.h" +#include "mirror/class_ext.h" #include "scoped_thread_state_change.h" #include "thread-inl.h" #include "well_known_classes.h" @@ -93,6 +96,24 @@ MemberSignature::MemberSignature(ArtMethod* method) { type_ = kMethod; } +MemberSignature::MemberSignature(const ClassAccessor::Field& field) { + const DexFile& dex_file = field.GetDexFile(); + const DexFile::FieldId& field_id = dex_file.GetFieldId(field.GetIndex()); + class_name_ = dex_file.GetFieldDeclaringClassDescriptor(field_id); + member_name_ = dex_file.GetFieldName(field_id); + type_signature_ = dex_file.GetFieldTypeDescriptor(field_id); + type_ = kField; +} + +MemberSignature::MemberSignature(const ClassAccessor::Method& method) { + const DexFile& dex_file = method.GetDexFile(); + const DexFile::MethodId& method_id = dex_file.GetMethodId(method.GetIndex()); + class_name_ = dex_file.GetMethodDeclaringClassDescriptor(method_id); + member_name_ = dex_file.GetMethodName(method_id); + type_signature_ = dex_file.GetMethodSignature(method_id).ToString(); + type_ = kMethod; +} + inline std::vector<const char*> MemberSignature::GetSignatureParts() const { if (type_ == kField) { return { class_name_.c_str(), "->", member_name_.c_str(), ":", type_signature_.c_str() }; @@ -137,6 +158,17 @@ void MemberSignature::WarnAboutAccess(AccessMethod access_method, hiddenapi::Api << Dumpable<MemberSignature>(*this) << " (" << list << ", " << access_method << ")"; } +bool MemberSignature::Equals(const MemberSignature& other) { + return type_ == other.type_ && + class_name_ == other.class_name_ && + member_name_ == other.member_name_ && + type_signature_ == other.type_signature_; +} + +bool MemberSignature::MemberNameAndTypeMatch(const MemberSignature& other) { + return member_name_ == other.member_name_ && type_signature_ == other.type_signature_; +} + #ifdef ART_TARGET_ANDROID // Convert an AccessMethod enum to a value for logging from the proto enum. // This method may look odd (the enum values are current the same), but it @@ -238,63 +270,88 @@ static ALWAYS_INLINE void MaybeWhitelistMember(Runtime* runtime, T* member) static constexpr uint32_t kNoDexFlags = 0u; static constexpr uint32_t kInvalidDexFlags = static_cast<uint32_t>(-1); -uint32_t GetDexFlags(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<mirror::Class> declaring_class = field->GetDeclaringClass(); - DCHECK(declaring_class != nullptr) << "Fields always have a declaring class"; - - const DexFile::ClassDef* class_def = declaring_class->GetClassDef(); - if (class_def == nullptr) { - return kNoDexFlags; - } +static ALWAYS_INLINE uint32_t GetMemberDexIndex(ArtField* field) { + return field->GetDexFieldIndex(); +} - uint32_t flags = kInvalidDexFlags; - DCHECK(!AreValidDexFlags(flags)); +static ALWAYS_INLINE uint32_t GetMemberDexIndex(ArtMethod* method) + REQUIRES_SHARED(Locks::mutator_lock_) { + // Use the non-obsolete method to avoid DexFile mismatch between + // the method index and the declaring class. + return method->GetNonObsoleteMethod()->GetDexMethodIndex(); +} - ClassAccessor accessor(declaring_class->GetDexFile(), - *class_def, - /* parse_hiddenapi_class_data= */ true); - auto fn_visit = [&](const ClassAccessor::Field& dex_field) { - if (dex_field.GetIndex() == field->GetDexFieldIndex()) { - flags = dex_field.GetHiddenapiFlags(); - } - }; +static void VisitMembers(const DexFile& dex_file, + const DexFile::ClassDef& class_def, + const std::function<void(const ClassAccessor::Field&)>& fn_visit) { + ClassAccessor accessor(dex_file, class_def, /* parse_hiddenapi_class_data= */ true); accessor.VisitFields(fn_visit, fn_visit); +} - CHECK_NE(flags, kInvalidDexFlags) << "Could not find flags for field " << field->PrettyField(); - DCHECK(AreValidDexFlags(flags)); - return flags; +static void VisitMembers(const DexFile& dex_file, + const DexFile::ClassDef& class_def, + const std::function<void(const ClassAccessor::Method&)>& fn_visit) { + ClassAccessor accessor(dex_file, class_def, /* parse_hiddenapi_class_data= */ true); + accessor.VisitMethods(fn_visit, fn_visit); } -uint32_t GetDexFlags(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<mirror::Class> declaring_class = method->GetDeclaringClass(); - if (declaring_class.IsNull()) { - DCHECK(method->IsRuntimeMethod()); - return kNoDexFlags; - } +template<typename T> +uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) { + static_assert(std::is_same<T, ArtField>::value || std::is_same<T, ArtMethod>::value); + using AccessorType = typename std::conditional<std::is_same<T, ArtField>::value, + ClassAccessor::Field, ClassAccessor::Method>::type; - const DexFile::ClassDef* class_def = declaring_class->GetClassDef(); - if (class_def == nullptr) { + ObjPtr<mirror::Class> declaring_class = member->GetDeclaringClass(); + if (declaring_class.IsNull()) { return kNoDexFlags; } uint32_t flags = kInvalidDexFlags; DCHECK(!AreValidDexFlags(flags)); - // Use the non-obsolete method to avoid DexFile mismatch between - // the method index and the declaring class. - uint32_t method_index = method->GetNonObsoleteMethod()->GetDexMethodIndex(); - - ClassAccessor accessor(declaring_class->GetDexFile(), - *class_def, - /* parse_hiddenapi_class_data= */ true); - auto fn_visit = [&](const ClassAccessor::Method& dex_method) { - if (dex_method.GetIndex() == method_index) { - flags = dex_method.GetHiddenapiFlags(); + // Check if the declaring class has ClassExt allocated. If it does, check if + // the pre-JVMTI redefine dex file has been set to determine if the declaring + // class has been JVMTI-redefined. + ObjPtr<mirror::ClassExt> ext(declaring_class->GetExtData()); + const DexFile* original_dex = ext.IsNull() ? nullptr : ext->GetPreRedefineDexFile(); + if (LIKELY(original_dex == nullptr)) { + // Class is not redefined. Find the class def, iterate over its members and + // find the entry corresponding to this `member`. + const DexFile::ClassDef* class_def = declaring_class->GetClassDef(); + if (class_def == nullptr) { + flags = kNoDexFlags; + } else { + uint32_t member_index = GetMemberDexIndex(member); + auto fn_visit = [&](const AccessorType& dex_member) { + if (dex_member.GetIndex() == member_index) { + flags = dex_member.GetHiddenapiFlags(); + } + }; + VisitMembers(declaring_class->GetDexFile(), *class_def, fn_visit); } - }; - accessor.VisitMethods(fn_visit, fn_visit); + } else { + // Class was redefined using JVMTI. We have a pointer to the original dex file + // and the class def index of this class in that dex file, but the field/method + // indices are lost. Iterate over all members of the class def and find the one + // corresponding to this `member` by name and type string comparison. + // This is obviously very slow, but it is only used when non-exempt code tries + // to access a hidden member of a JVMTI-redefined class. + uint16_t class_def_idx = ext->GetPreRedefineClassDefIndex(); + DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16); + const DexFile::ClassDef& original_class_def = original_dex->GetClassDef(class_def_idx); + MemberSignature member_signature(member); + auto fn_visit = [&](const AccessorType& dex_member) { + MemberSignature cur_signature(dex_member); + if (member_signature.MemberNameAndTypeMatch(cur_signature)) { + DCHECK(member_signature.Equals(cur_signature)); + flags = dex_member.GetHiddenapiFlags(); + } + }; + VisitMembers(*original_dex, original_class_def, fn_visit); + } - CHECK_NE(flags, kInvalidDexFlags) << "Could not find flags for method " << method->PrettyMethod(); + CHECK_NE(flags, kInvalidDexFlags) << "Could not find hiddenapi flags for " + << Dumpable<MemberSignature>(MemberSignature(member)); DCHECK(AreValidDexFlags(flags)); return flags; } @@ -356,6 +413,8 @@ bool ShouldDenyAccessToMemberImpl(T* member, } // Need to instantiate this. +template uint32_t GetDexFlags<ArtField>(ArtField* member); +template uint32_t GetDexFlags<ArtMethod>(ArtMethod* member); template bool ShouldDenyAccessToMemberImpl<ArtField>(ArtField* member, hiddenapi::ApiList api_list, AccessMethod access_method); diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h index eea58e9880..614154c7a0 100644 --- a/runtime/hidden_api.h +++ b/runtime/hidden_api.h @@ -137,9 +137,14 @@ class MemberSignature { public: explicit MemberSignature(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); explicit MemberSignature(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); + explicit MemberSignature(const ClassAccessor::Field& field); + explicit MemberSignature(const ClassAccessor::Method& method); void Dump(std::ostream& os) const; + bool Equals(const MemberSignature& other); + bool MemberNameAndTypeMatch(const MemberSignature& other); + // Performs prefix match on this member. Since the full member signature is // composed of several parts, we match each part in turn (rather than // building the entire thing in memory and performing a simple prefix match) @@ -160,11 +165,8 @@ class MemberSignature { // Locates hiddenapi flags for `field` in the corresponding dex file. // NB: This is an O(N) operation, linear with the number of members in the class def. -uint32_t GetDexFlags(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); - -// Locates hiddenapi flags for `method` in the corresponding dex file. -// NB: This is an O(N) operation, linear with the number of members in the class def. -uint32_t GetDexFlags(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); +template<typename T> +uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_); template<typename T> bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method) diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc index 520dc6d935..595f0779e2 100644 --- a/runtime/hidden_api_test.cc +++ b/runtime/hidden_api_test.cc @@ -103,12 +103,14 @@ TEST_F(HiddenApiTest, CheckGetActionFromRuntimeFlags) { runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDisabled); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Whitelist()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Greylist()), false); + ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::GreylistMaxP()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::GreylistMaxO()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blacklist()), false); runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kJustWarn); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Whitelist()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Greylist()), false); + ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::GreylistMaxP()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::GreylistMaxO()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blacklist()), false); @@ -117,6 +119,7 @@ TEST_F(HiddenApiTest, CheckGetActionFromRuntimeFlags) { static_cast<uint32_t>(hiddenapi::ApiList::GreylistMaxO().GetMaxAllowedSdkVersion())); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Whitelist()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Greylist()), false); + ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::GreylistMaxP()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::GreylistMaxO()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blacklist()), true); @@ -125,6 +128,16 @@ TEST_F(HiddenApiTest, CheckGetActionFromRuntimeFlags) { static_cast<uint32_t>(hiddenapi::ApiList::GreylistMaxO().GetMaxAllowedSdkVersion()) + 1); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Whitelist()), false); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Greylist()), false); + ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::GreylistMaxP()), false); + ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::GreylistMaxO()), true); + ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blacklist()), true); + + runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); + runtime_->SetTargetSdkVersion( + static_cast<uint32_t>(hiddenapi::ApiList::GreylistMaxP().GetMaxAllowedSdkVersion()) + 1); + ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Whitelist()), false); + ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Greylist()), false); + ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::GreylistMaxP()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::GreylistMaxO()), true); ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blacklist()), true); } 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/mirror/class_ext.cc b/runtime/mirror/class_ext.cc index 67126307dc..146adc978c 100644 --- a/runtime/mirror/class_ext.cc +++ b/runtime/mirror/class_ext.cc @@ -119,5 +119,17 @@ void ClassExt::SetOriginalDexFile(ObjPtr<Object> bytes) { SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ClassExt, original_dex_file_), bytes); } +void ClassExt::SetPreRedefineClassDefIndex(uint16_t index) { + DCHECK(!Runtime::Current()->IsActiveTransaction()); + SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ClassExt, pre_redefine_class_def_index_), + static_cast<int32_t>(index)); +} + +void ClassExt::SetPreRedefineDexFile(const DexFile* dex_file) { + DCHECK(!Runtime::Current()->IsActiveTransaction()); + SetField64<false>(OFFSET_OF_OBJECT_MEMBER(ClassExt, pre_redefine_dex_file_ptr_), + static_cast<int64_t>(reinterpret_cast<uintptr_t>(dex_file))); +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/class_ext.h b/runtime/mirror/class_ext.h index 612fd0f256..126f94a61d 100644 --- a/runtime/mirror/class_ext.h +++ b/runtime/mirror/class_ext.h @@ -64,6 +64,20 @@ class MANAGED ClassExt : public Object { void SetOriginalDexFile(ObjPtr<Object> bytes) REQUIRES_SHARED(Locks::mutator_lock_); + uint16_t GetPreRedefineClassDefIndex() REQUIRES_SHARED(Locks::mutator_lock_) { + return static_cast<uint16_t>( + GetField32(OFFSET_OF_OBJECT_MEMBER(ClassExt, pre_redefine_class_def_index_))); + } + + void SetPreRedefineClassDefIndex(uint16_t index) REQUIRES_SHARED(Locks::mutator_lock_); + + const DexFile* GetPreRedefineDexFile() REQUIRES_SHARED(Locks::mutator_lock_) { + return reinterpret_cast<const DexFile*>(static_cast<uintptr_t>( + GetField64(OFFSET_OF_OBJECT_MEMBER(ClassExt, pre_redefine_dex_file_ptr_)))); + } + + void SetPreRedefineDexFile(const DexFile* dex_file) REQUIRES_SHARED(Locks::mutator_lock_); + void SetObsoleteArrays(ObjPtr<PointerArray> methods, ObjPtr<ObjectArray<DexCache>> dex_caches) REQUIRES_SHARED(Locks::mutator_lock_); @@ -88,6 +102,10 @@ class MANAGED ClassExt : public Object { // The saved verification error of this class. HeapReference<Object> verify_error_; + // Native pointer to DexFile and ClassDef index of this class before it was JVMTI-redefined. + int64_t pre_redefine_dex_file_ptr_; + int32_t pre_redefine_class_def_index_; + friend struct art::ClassExtOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassExt); }; 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/parsed_options_test.cc b/runtime/parsed_options_test.cc index 9e5d9abe3b..705cc6c5e2 100644 --- a/runtime/parsed_options_test.cc +++ b/runtime/parsed_options_test.cc @@ -26,7 +26,7 @@ namespace art { class ParsedOptionsTest : public ::testing::Test { public: static void SetUpTestCase() { - CommonRuntimeTest::SetUpAndroidRoot(); + CommonRuntimeTest::SetUpAndroidRootEnvVars(); } }; 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/sigchainlib/Android.bp b/sigchainlib/Android.bp index a151d7a6bc..1d5ec2b10d 100644 --- a/sigchainlib/Android.bp +++ b/sigchainlib/Android.bp @@ -16,7 +16,6 @@ cc_library { name: "libsigchain", - cpp_std: "gnu++17", host_supported: true, defaults: ["art_defaults"], diff --git a/test/924-threads/src/art/Test924.java b/test/924-threads/src/art/Test924.java index e8e97817b7..e97c9c6b35 100644 --- a/test/924-threads/src/art/Test924.java +++ b/test/924-threads/src/art/Test924.java @@ -27,6 +27,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.time.Instant; public class Test924 { public static void run() throws Exception { @@ -109,6 +110,7 @@ public class Test924 { final CountDownLatch cdl4 = new CountDownLatch(1); final CountDownLatch cdl5 = new CountDownLatch(1); final Holder h = new Holder(); + final long ALMOST_INFINITE = 100000000; // 1.1 days! final NativeWaiter w = new NativeWaiter(); Runnable r = new Runnable() { @Override @@ -121,7 +123,7 @@ public class Test924 { cdl2.countDown(); synchronized(cdl2) { - cdl2.wait(1000); // Wait a second. + cdl2.wait(ALMOST_INFINITE); } cdl3_1.await(); @@ -131,7 +133,9 @@ public class Test924 { } cdl4.countDown(); - Thread.sleep(1000); + try { + Thread.sleep(ALMOST_INFINITE); + } catch (InterruptedException e) { } cdl5.countDown(); while (!h.flag) { @@ -152,18 +156,20 @@ public class Test924 { // Waiting. cdl1.await(); - Thread.yield(); - Thread.sleep(100); - printThreadState(t); + // This is super inconsistent so just wait for the desired state for up to 5 minutes then give + // up and continue + final int WAITING_INDEF = 0x191; + waitForState(t, WAITING_INDEF); synchronized(cdl1) { cdl1.notifyAll(); } // Timed waiting. cdl2.await(); - Thread.yield(); - Thread.sleep(100); - printThreadState(t); + // This is super inconsistent so just wait for the desired state for up to 5 minutes then give + // up and continue + final int WAITING_TIMED = 0x1a1; + waitForState(t, WAITING_TIMED); synchronized(cdl2) { cdl2.notifyAll(); } @@ -185,14 +191,16 @@ public class Test924 { // Sleeping. cdl4.await(); - Thread.yield(); - Thread.sleep(100); - printThreadState(t); + // This is super inconsistent so just wait for the desired state for up to 5 minutes then give + // up and continue + final int WAITING_SLEEP = 0xe1; + waitForState(t, WAITING_SLEEP); + t.interrupt(); // Running. cdl5.await(); Thread.yield(); - Thread.sleep(100); + Thread.sleep(1000); printThreadState(t); h.flag = true; @@ -204,11 +212,26 @@ public class Test924 { // Dying. t.join(); Thread.yield(); - Thread.sleep(100); + Thread.sleep(1000); printThreadState(t); } + private static void waitForState(Thread t, int desired) throws Exception { + Thread.yield(); + Thread.sleep(1000); + // This is super inconsistent so just wait for the desired state for up to 5 minutes then give + // up and continue + int state; + Instant deadline = Instant.now().plusSeconds(60 * 5); + while ((state = getThreadState(t)) != desired && deadline.isAfter(Instant.now())) { + Thread.yield(); + Thread.sleep(100); + Thread.yield(); + } + printThreadState(state); + } + private static void doAllThreadsTests() { Thread[] threads = getAllThreads(); List<Thread> threadList = new ArrayList<>(Arrays.asList(threads)); diff --git a/test/999-redefine-hiddenapi/src-redefine/gen.sh b/test/999-redefine-hiddenapi/src-redefine/gen.sh index b5e2aea0bb..f92d79784b 100755 --- a/test/999-redefine-hiddenapi/src-redefine/gen.sh +++ b/test/999-redefine-hiddenapi/src-redefine/gen.sh @@ -23,16 +23,10 @@ CLASS="art/Test999" (cd "$TMP" && \ javac -d "${TMP}" "$DIR/${CLASS}.java" && \ d8 --output . "$TMP/${CLASS}.class" && - hiddenapi encode --input-dex="$TMP/classes.dex" \ - --output-dex="$TMP/classes-hiddenapi.dex" \ - --api-flags="$DIR/../hiddenapi-flags.csv" \ - --no-force-assign-all) echo ' private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(' base64 "${TMP}/${CLASS}.class" | sed -E 's/^/ "/' | sed ':a;N;$!ba;s/\n/" +\n/g' | sed -E '$ s/$/");/' echo ' private static final byte[] DEX_BYTES = Base64.getDecoder().decode(' base64 "${TMP}/classes.dex" | sed -E 's/^/ "/' | sed ':a;N;$!ba;s/\n/" +\n/g' | sed -E '$ s/$/");/' -echo ' private static final byte[] DEX_BYTES_HIDDEN = Base64.getDecoder().decode(' -base64 "${TMP}/classes-hiddenapi.dex" | sed -E 's/^/ "/' | sed ':a;N;$!ba;s/\n/" +\n/g' | sed -E '$ s/$/");/' rm -rf "$TMP" diff --git a/test/999-redefine-hiddenapi/src/Main.java b/test/999-redefine-hiddenapi/src/Main.java index 4627b4fd22..3d9bbda801 100644 --- a/test/999-redefine-hiddenapi/src/Main.java +++ b/test/999-redefine-hiddenapi/src/Main.java @@ -31,53 +31,33 @@ public class Main { // Find the test class in boot class loader and verify that its members are hidden. Class<?> klass = Class.forName("art.Test999", true, BOOT_CLASS_LOADER); - assertMethodIsHidden(true, klass, "before redefinition"); - assertFieldIsHidden(true, klass, "before redefinition"); + assertFieldIsHidden(klass, "before redefinition"); + assertMethodIsHidden(klass, "before redefinition"); // Redefine the class using JVMTI. Use dex file without hiddenapi flags. art.Redefinition.setTestConfiguration(art.Redefinition.Config.COMMON_REDEFINE); art.Redefinition.doCommonClassRedefinition(klass, CLASS_BYTES, DEX_BYTES); - // Verify that the class members are not hidden anymore. - assertMethodIsHidden(false, klass, "after first redefinition"); - assertFieldIsHidden(false, klass, "after first redefinition"); - - // Redefine the class using JVMTI, this time with a dex file with hiddenapi flags. - art.Redefinition.setTestConfiguration(art.Redefinition.Config.COMMON_REDEFINE); - art.Redefinition.doCommonClassRedefinition(klass, CLASS_BYTES, DEX_BYTES_HIDDEN); - - // Verify that the class members are still accessible. - assertMethodIsHidden(false, klass, "after second redefinition"); - assertFieldIsHidden(false, klass, "after second redefinition"); + // Verify that the class members are still hidden. + assertFieldIsHidden(klass, "after first redefinition"); + assertMethodIsHidden(klass, "after first redefinition"); } - private static void assertMethodIsHidden(boolean expectedHidden, Class<?> klass, String msg) { + private static void assertMethodIsHidden(Class<?> klass, String msg) { try { klass.getDeclaredMethod("foo"); - if (expectedHidden) { - // Unexpected. Should have thrown NoSuchMethodException. - throw new RuntimeException("Method should not be accessible " + msg); - } + // Unexpected. Should have thrown NoSuchMethodException. + throw new RuntimeException("Method should not be accessible " + msg); } catch (NoSuchMethodException ex) { - if (!expectedHidden) { - // Unexpected. Should not have thrown NoSuchMethodException. - throw new RuntimeException("Method should be accessible " + msg); - } } } - private static void assertFieldIsHidden(boolean expectedHidden, Class<?> klass, String msg) { + private static void assertFieldIsHidden(Class<?> klass, String msg) { try { klass.getDeclaredField("bar"); - if (expectedHidden) { - // Unexpected. Should have thrown NoSuchFieldException. - throw new RuntimeException("Field should not be accessible " + msg); - } + // Unexpected. Should have thrown NoSuchFieldException. + throw new RuntimeException("Field should not be accessible " + msg); } catch (NoSuchFieldException ex) { - if (!expectedHidden) { - // Unexpected. Should not have thrown NoSuchFieldException. - throw new RuntimeException("Field should be accessible " + msg); - } } } @@ -127,21 +107,4 @@ public class Main { "AAAABAAAAAIAAADkAAAABQAAAAQAAAD0AAAABgAAAAEAAAAUAQAAASAAAAIAAAA0AQAAAyAAAAIA" + "AAB0AQAAARAAAAEAAACAAQAAAiAAABAAAACGAQAAACAAAAEAAACgAgAAAxAAAAEAAACwAgAAABAA" + "AAEAAAC0AgAA"); - private static final byte[] DEX_BYTES_HIDDEN = Base64.getDecoder().decode( - "ZGV4CjAzNQDsgG5ufKulToQpDF+P4dsgeOkgfzzH+5l4AwAAcAAAAHhWNBIAAAAAAAAAAMACAAAQ" + - "AAAAcAAAAAcAAACwAAAAAgAAAMwAAAACAAAA5AAAAAQAAAD0AAAAAQAAABQBAABEAgAANAEAAIYB" + - "AACOAQAAlwEAAJoBAACpAQAAwAEAANQBAADoAQAA/AEAAAoCAAANAgAAEQIAABYCAAAbAgAAIAIA" + - "ACkCAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAJAAAACQAAAAYAAAAAAAAACgAAAAYAAACAAQAA" + - "AQAAAAsAAAAFAAIADQAAAAEAAAAAAAAAAQAAAAwAAAACAAEADgAAAAMAAAAAAAAAAQAAAAEAAAAD" + - "AAAAAAAAAAgAAAAAAAAAoAIAAAAAAAACAAEAAQAAAHQBAAAIAAAAcBADAAEAEwBAAFkQAAAOAAMA" + - "AQACAAAAeQEAAAgAAABiAAEAGgEBAG4gAgAQAA4AEwAOQAAVAA54AAAAAQAAAAQABjxpbml0PgAH" + - "R29vZGJ5ZQABSQANTGFydC9UZXN0OTk5OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9s" + - "YW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0" + - "OTk5LmphdmEAAVYAAlZMAANiYXIAA2ZvbwADb3V0AAdwcmludGxuAHV+fkQ4eyJjb21waWxhdGlv" + - "bi1tb2RlIjoiZGVidWciLCJtaW4tYXBpIjoxLCJzaGEtMSI6ImQyMmFiNGYxOWI3NTYxNDQ3NTI4" + - "NTdjYTg2YjJjZWU0ZGQ5Y2ExNjYiLCJ2ZXJzaW9uIjoiMS40LjktZGV2In0AAAEBAQABAIGABLQC" + - "AQHUAgAAAAALAAAACAAAAAIAAgAPAAAAAAAAAAEAAAAAAAAAAQAAABAAAABwAAAAAgAAAAcAAACw" + - "AAAAAwAAAAIAAADMAAAABAAAAAIAAADkAAAABQAAAAQAAAD0AAAABgAAAAEAAAAUAQAAASAAAAIA" + - "AAA0AQAAAyAAAAIAAAB0AQAAARAAAAEAAACAAQAAAiAAABAAAACGAQAAACAAAAEAAACgAgAAAxAA" + - "AAEAAACwAgAAAPAAAAEAAAC0AgAAABAAAAEAAADAAgAA"); } diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index ca860e245d..5d07601005 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -50,6 +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 # 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 5fede0ed6b..4e5152b135 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -9,6 +9,7 @@ msg() { } ANDROID_ROOT="/system" +ANDROID_RUNTIME_ROOT="/apex/com.android.runtime" ARCHITECTURES_32="(arm|x86|mips|none)" ARCHITECTURES_64="(arm64|x86_64|mips64|none)" ARCHITECTURES_PATTERN="${ARCHITECTURES_32}" @@ -209,7 +210,8 @@ while true; do shift elif [ "x$1" = "x--host" ]; then HOST="y" - ANDROID_ROOT="$ANDROID_HOST_OUT" + ANDROID_ROOT="${ANDROID_HOST_OUT}" + ANDROID_RUNTIME_ROOT="${ANDROID_HOST_OUT}/com.android.runtime" shift elif [ "x$1" = "x--bionic" ]; then BIONIC="y" @@ -539,7 +541,7 @@ if [ "$USE_JVM" = "y" ]; then exit fi -bpath_modules="core-oj core-libart core-simple" +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 @@ -917,6 +919,7 @@ if [ "$HOST" = "n" ]; then export ANDROID_ADDITIONAL_PUBLIC_LIBRARIES=$PUBLIC_LIBS && \ export DEX_LOCATION=$DEX_LOCATION && \ export ANDROID_ROOT=$ANDROID_ROOT && \ + export ANDROID_RUNTIME_ROOT=$ANDROID_RUNTIME_ROOT && \ export ANDROID_LOG_TAGS=$ANDROID_LOG_TAGS && \ rm -rf ${DEX_LOCATION}/dalvik-cache/ && \ mkdir -p ${mkdir_locations} && \ @@ -961,6 +964,7 @@ else export ANDROID_DATA="$DEX_LOCATION" export ANDROID_ROOT="${ANDROID_ROOT}" + export ANDROID_RUNTIME_ROOT="${ANDROID_RUNTIME_ROOT}" export LD_LIBRARY_PATH="${ANDROID_ROOT}/${LIBRARY_DIRECTORY}:${ANDROID_ROOT}/${TEST_DIRECTORY}" export DYLD_LIBRARY_PATH="${ANDROID_ROOT}/${LIBRARY_DIRECTORY}:${ANDROID_ROOT}/${TEST_DIRECTORY}" export PATH="$PATH:${ANDROID_ROOT}/bin" @@ -261,6 +261,7 @@ function run_art() { # Run dalvikvm. verbose_run ANDROID_DATA="$ANDROID_DATA" \ ANDROID_ROOT="$ANDROID_ROOT" \ + ANDROID_RUNTIME_ROOT="$ANDROID_RUNTIME_ROOT" \ LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ PATH="$ANDROID_ROOT/bin:$PATH" \ LD_USE_LOAD_BIAS=1 \ @@ -386,6 +387,7 @@ done PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)" ANDROID_ROOT=$PROG_DIR/.. +ANDROID_RUNTIME_ROOT=$ANDROID_ROOT/com.android.runtime ART_BINARY_PATH=$ANDROID_ROOT/bin/$ART_BINARY if [ ! -x "$ART_BINARY_PATH" ]; then diff --git a/tools/bootjars.sh b/tools/bootjars.sh index ecd7084d17..ad6ee6b058 100755 --- a/tools/bootjars.sh +++ b/tools/bootjars.sh @@ -73,7 +73,7 @@ if [[ $core_jars_only == y ]]; then # 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" + core_jars_list="core-oj core-libart core-simple conscrypt okhttp bouncycastle" core_jars_suffix= if [[ $mode == target ]]; then core_jars_suffix=-testdex diff --git a/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java b/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java index 621ee11fa7..6305185471 100644 --- a/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java +++ b/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java @@ -62,13 +62,14 @@ public class Class2Greylist { public static final String FLAG_GREYLIST = "greylist"; public static final String FLAG_BLACKLIST = "blacklist"; public static final String FLAG_GREYLIST_MAX_O = "greylist-max-o"; + public static final String FLAG_GREYLIST_MAX_P = "greylist-max-p"; private static final Map<Integer, String> TARGET_SDK_TO_LIST_MAP; static { Map<Integer, String> map = new HashMap<>(); map.put(null, FLAG_GREYLIST); map.put(26, FLAG_GREYLIST_MAX_O); - map.put(28, FLAG_GREYLIST); + map.put(28, FLAG_GREYLIST_MAX_P); TARGET_SDK_TO_LIST_MAP = Collections.unmodifiableMap(map); } 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/common/common.py b/tools/common/common.py index b728e8d927..6206dfb118 100755 --- a/tools/common/common.py +++ b/tools/common/common.py @@ -299,11 +299,13 @@ class HostTestEnv(ITestEnv): os.mkdir(arch_cache_path) lib = 'lib64' if x64 else 'lib' android_root = GetEnvVariableOrError('ANDROID_HOST_OUT') + android_runtime_root = android_root + '/com.android.runtime' library_path = android_root + '/' + lib path = android_root + '/bin' self._shell_env = os.environ.copy() self._shell_env['ANDROID_DATA'] = self._env_path self._shell_env['ANDROID_ROOT'] = android_root + self._shell_env['ANDROID_RUNTIME_ROOT'] = android_runtime_root self._shell_env['LD_LIBRARY_PATH'] = library_path self._shell_env['DYLD_LIBRARY_PATH'] = library_path self._shell_env['PATH'] = (path + ':' + self._shell_env['PATH']) 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", |