summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.common_path.mk2
-rw-r--r--build/Android.gtest.mk12
-rw-r--r--build/apex/Android.bp13
-rw-r--r--build/apex/ld.config.txt1
-rw-r--r--compiler/debug/elf_debug_writer.cc79
-rw-r--r--compiler/debug/elf_debug_writer.h2
-rw-r--r--compiler/driver/compiler_options.h5
-rw-r--r--compiler/linker/elf_builder.h45
-rw-r--r--compiler/optimizing/code_generator_arm64.cc3
-rw-r--r--compiler/optimizing/codegen_test.cc27
-rw-r--r--compiler/optimizing/optimizing_compiler.cc2
-rw-r--r--compiler/utils/arm64/assembler_arm64.cc32
-rw-r--r--compiler/utils/arm64/assembler_arm64.h6
-rw-r--r--compiler/utils/assembler_test_base.h4
-rw-r--r--dex2oat/linker/arm64/relative_patcher_arm64_test.cc7
-rw-r--r--imgdiag/imgdiag_test.cc10
-rw-r--r--libartbase/base/common_art_test.cc94
-rw-r--r--libartbase/base/common_art_test.h9
-rw-r--r--libartbase/base/hiddenapi_flags.h6
-rw-r--r--libartbase/base/sdk_version.h1
-rw-r--r--libartbase/base/unix_file/random_access_file_test.h4
-rw-r--r--openjdkjvmti/ti_redefine.cc26
-rw-r--r--openjdkjvmti/ti_thread.cc3
-rw-r--r--runtime/arch/arm/instruction_set_features_arm.cc3
-rw-r--r--runtime/arch/arm64/instruction_set_features_arm64.cc14
-rw-r--r--runtime/class_linker_test.cc4
-rw-r--r--runtime/gc/collector/garbage_collector.cc1
-rw-r--r--runtime/gc/heap.cc16
-rw-r--r--runtime/gc/heap.h18
-rw-r--r--runtime/gc/space/image_space.cc30
-rw-r--r--runtime/hidden_api.cc143
-rw-r--r--runtime/hidden_api.h12
-rw-r--r--runtime/hidden_api_test.cc13
-rw-r--r--runtime/image.h8
-rw-r--r--runtime/mirror/class_ext.cc12
-rw-r--r--runtime/mirror/class_ext.h18
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc38
-rw-r--r--runtime/parsed_options_test.cc2
-rw-r--r--runtime/runtime.cc26
-rw-r--r--runtime/runtime.h11
-rw-r--r--runtime/thread_pool.cc11
-rw-r--r--runtime/thread_pool.h18
-rw-r--r--sigchainlib/Android.bp1
-rw-r--r--test/924-threads/src/art/Test924.java49
-rwxr-xr-xtest/999-redefine-hiddenapi/src-redefine/gen.sh6
-rw-r--r--test/999-redefine-hiddenapi/src/Main.java59
-rw-r--r--test/Android.run-test.mk3
-rwxr-xr-xtest/etc/run-test-jar8
-rw-r--r--tools/art2
-rwxr-xr-xtools/bootjars.sh2
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java3
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeHandlerTest.java8
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java4
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/UnsupportedAppUsageAnnotationHandlerTest.java36
-rw-r--r--tools/class2greylist/test/src/com/android/javac/Javac.java16
-rwxr-xr-xtools/common/common.py2
-rw-r--r--tools/libcore_failures.txt4
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"
diff --git a/tools/art b/tools/art
index fbc7992cf9..eeb7c6872f 100644
--- a/tools/art
+++ b/tools/art
@@ -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",