summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/compiled_method.cc32
-rw-r--r--compiler/compiled_method.h15
-rw-r--r--compiler/dex/dex_to_dex_compiler.cc5
-rw-r--r--compiler/driver/compiled_method_storage_test.cc19
-rw-r--r--compiler/driver/compiler_driver.cc2
-rw-r--r--compiler/optimizing/optimizing_compiler.cc4
-rw-r--r--dex2oat/dex2oat_test.cc11
-rw-r--r--dex2oat/linker/arm/relative_patcher_thumb2_test.cc5
-rw-r--r--dex2oat/linker/arm64/relative_patcher_arm64_test.cc5
-rw-r--r--dex2oat/linker/relative_patcher_test.h45
-rw-r--r--libartbase/arch/instruction_set.cc4
-rw-r--r--libartbase/base/sdk_version.h58
-rw-r--r--libdexfile/dex/hidden_api_access_flags.h21
-rw-r--r--libdexfile/dex/modifiers.h7
-rw-r--r--openjdkjvmti/ti_redefine.cc10
-rw-r--r--runtime/art_field.h4
-rw-r--r--runtime/art_method-inl.h154
-rw-r--r--runtime/art_method.cc60
-rw-r--r--runtime/art_method.h2
-rw-r--r--runtime/class_linker.cc100
-rw-r--r--runtime/class_linker.h10
-rw-r--r--runtime/class_loader_context.cc221
-rw-r--r--runtime/class_loader_context_test.cc311
-rw-r--r--runtime/class_root.h1
-rw-r--r--runtime/dex/dex_file_annotations.cc4
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h6
-rw-r--r--runtime/entrypoints/entrypoint_utils.cc5
-rw-r--r--runtime/gc/collector/garbage_collector.cc13
-rw-r--r--runtime/gc/collector/garbage_collector.h4
-rw-r--r--runtime/gc/heap.cc8
-rw-r--r--runtime/gc/heap.h2
-rw-r--r--runtime/hidden_api.cc92
-rw-r--r--runtime/hidden_api.h154
-rw-r--r--runtime/hidden_api_test.cc5
-rw-r--r--runtime/jit/jit_code_cache.cc20
-rw-r--r--runtime/jit/jit_code_cache.h25
-rw-r--r--runtime/jni/java_vm_ext.cc3
-rw-r--r--runtime/mirror/class.h4
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc8
-rw-r--r--runtime/parsed_options.cc2
-rw-r--r--runtime/runtime.cc13
-rw-r--r--runtime/runtime.h11
-rw-r--r--runtime/runtime_options.cc1
-rw-r--r--runtime/runtime_options.def3
-rw-r--r--runtime/verifier/method_verifier.cc16
-rw-r--r--test/674-hiddenapi/hiddenapi.cc5
-rw-r--r--test/688-shared-library/run19
-rwxr-xr-xtest/999-redefine-hiddenapi/src-redefine/gen.sh12
-rw-r--r--test/999-redefine-hiddenapi/src/Main.java84
-rwxr-xr-xtools/build_linux_bionic_tests.sh5
-rw-r--r--tools/timeout_dumper/Android.bp5
51 files changed, 1147 insertions, 488 deletions
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index 29f004cf87..ef9d919c75 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -17,21 +17,20 @@
#include "compiled_method.h"
#include "driver/compiled_method_storage.h"
-#include "driver/compiler_driver.h"
#include "utils/swap_space.h"
namespace art {
-CompiledCode::CompiledCode(CompilerDriver* compiler_driver,
+CompiledCode::CompiledCode(CompiledMethodStorage* storage,
InstructionSet instruction_set,
const ArrayRef<const uint8_t>& quick_code)
- : compiler_driver_(compiler_driver),
- quick_code_(compiler_driver_->GetCompiledMethodStorage()->DeduplicateCode(quick_code)),
+ : storage_(storage),
+ quick_code_(storage->DeduplicateCode(quick_code)),
packed_fields_(InstructionSetField::Encode(instruction_set)) {
}
CompiledCode::~CompiledCode() {
- compiler_driver_->GetCompiledMethodStorage()->ReleaseCode(quick_code_);
+ GetStorage()->ReleaseCode(quick_code_);
}
bool CompiledCode::operator==(const CompiledCode& rhs) const {
@@ -99,29 +98,29 @@ const void* CompiledCode::CodePointer(const void* code_pointer, InstructionSet i
}
}
-CompiledMethod::CompiledMethod(CompilerDriver* driver,
+CompiledMethod::CompiledMethod(CompiledMethodStorage* storage,
InstructionSet instruction_set,
const ArrayRef<const uint8_t>& quick_code,
const ArrayRef<const uint8_t>& vmap_table,
const ArrayRef<const uint8_t>& cfi_info,
const ArrayRef<const linker::LinkerPatch>& patches)
- : CompiledCode(driver, instruction_set, quick_code),
- vmap_table_(driver->GetCompiledMethodStorage()->DeduplicateVMapTable(vmap_table)),
- cfi_info_(driver->GetCompiledMethodStorage()->DeduplicateCFIInfo(cfi_info)),
- patches_(driver->GetCompiledMethodStorage()->DeduplicateLinkerPatches(patches)) {
+ : CompiledCode(storage, instruction_set, quick_code),
+ vmap_table_(storage->DeduplicateVMapTable(vmap_table)),
+ cfi_info_(storage->DeduplicateCFIInfo(cfi_info)),
+ patches_(storage->DeduplicateLinkerPatches(patches)) {
}
CompiledMethod* CompiledMethod::SwapAllocCompiledMethod(
- CompilerDriver* driver,
+ CompiledMethodStorage* storage,
InstructionSet instruction_set,
const ArrayRef<const uint8_t>& quick_code,
const ArrayRef<const uint8_t>& vmap_table,
const ArrayRef<const uint8_t>& cfi_info,
const ArrayRef<const linker::LinkerPatch>& patches) {
- SwapAllocator<CompiledMethod> alloc(driver->GetCompiledMethodStorage()->GetSwapSpaceAllocator());
+ SwapAllocator<CompiledMethod> alloc(storage->GetSwapSpaceAllocator());
CompiledMethod* ret = alloc.allocate(1);
alloc.construct(ret,
- driver,
+ storage,
instruction_set,
quick_code,
vmap_table,
@@ -129,14 +128,15 @@ CompiledMethod* CompiledMethod::SwapAllocCompiledMethod(
return ret;
}
-void CompiledMethod::ReleaseSwapAllocatedCompiledMethod(CompilerDriver* driver, CompiledMethod* m) {
- SwapAllocator<CompiledMethod> alloc(driver->GetCompiledMethodStorage()->GetSwapSpaceAllocator());
+void CompiledMethod::ReleaseSwapAllocatedCompiledMethod(CompiledMethodStorage* storage,
+ CompiledMethod* m) {
+ SwapAllocator<CompiledMethod> alloc(storage->GetSwapSpaceAllocator());
alloc.destroy(m);
alloc.deallocate(m, 1);
}
CompiledMethod::~CompiledMethod() {
- CompiledMethodStorage* storage = GetCompilerDriver()->GetCompiledMethodStorage();
+ CompiledMethodStorage* storage = GetStorage();
storage->ReleaseLinkerPatches(patches_);
storage->ReleaseCFIInfo(cfi_info_);
storage->ReleaseVMapTable(vmap_table_);
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 864ce585cf..75790c9f08 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -28,7 +28,6 @@
namespace art {
template <typename T> class ArrayRef;
-class CompilerDriver;
class CompiledMethodStorage;
template<typename T> class LengthPrefixedArray;
@@ -39,7 +38,7 @@ class LinkerPatch;
class CompiledCode {
public:
// For Quick to supply an code blob
- CompiledCode(CompilerDriver* compiler_driver,
+ CompiledCode(CompiledMethodStorage* storage,
InstructionSet instruction_set,
const ArrayRef<const uint8_t>& quick_code);
@@ -78,8 +77,8 @@ class CompiledCode {
template <typename T>
static ArrayRef<const T> GetArray(const LengthPrefixedArray<T>* array);
- CompilerDriver* GetCompilerDriver() {
- return compiler_driver_;
+ CompiledMethodStorage* GetStorage() {
+ return storage_;
}
template <typename BitFieldType>
@@ -96,7 +95,7 @@ class CompiledCode {
private:
using InstructionSetField = BitField<InstructionSet, 0u, kInstructionSetFieldSize>;
- CompilerDriver* const compiler_driver_;
+ CompiledMethodStorage* const storage_;
// Used to store the compiled code.
const LengthPrefixedArray<uint8_t>* const quick_code_;
@@ -109,7 +108,7 @@ class CompiledMethod final : public CompiledCode {
// Constructs a CompiledMethod.
// Note: Consider using the static allocation methods below that will allocate the CompiledMethod
// in the swap space.
- CompiledMethod(CompilerDriver* driver,
+ CompiledMethod(CompiledMethodStorage* storage,
InstructionSet instruction_set,
const ArrayRef<const uint8_t>& quick_code,
const ArrayRef<const uint8_t>& vmap_table,
@@ -119,14 +118,14 @@ class CompiledMethod final : public CompiledCode {
virtual ~CompiledMethod();
static CompiledMethod* SwapAllocCompiledMethod(
- CompilerDriver* driver,
+ CompiledMethodStorage* storage,
InstructionSet instruction_set,
const ArrayRef<const uint8_t>& quick_code,
const ArrayRef<const uint8_t>& vmap_table,
const ArrayRef<const uint8_t>& cfi_info,
const ArrayRef<const linker::LinkerPatch>& patches);
- static void ReleaseSwapAllocatedCompiledMethod(CompilerDriver* driver, CompiledMethod* m);
+ static void ReleaseSwapAllocatedCompiledMethod(CompiledMethodStorage* storage, CompiledMethod* m);
bool IsIntrinsic() const {
return GetPackedField<IsIntrinsicField>();
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index fe99eaa51a..04ad10c41e 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -614,7 +614,7 @@ CompiledMethod* DexToDexCompiler::CompileMethod(
instruction_set = InstructionSet::kArm;
}
CompiledMethod* ret = CompiledMethod::SwapAllocCompiledMethod(
- driver_,
+ driver_->GetCompiledMethodStorage(),
instruction_set,
ArrayRef<const uint8_t>(), // no code
ArrayRef<const uint8_t>(quicken_data), // vmap_table
@@ -665,7 +665,8 @@ void DexToDexCompiler::UnquickenConflictingMethods() {
// There is up to one compiled method for each method ref. Releasing it leaves the
// deduped data intact, this means its safe to do even when other threads might be
// compiling.
- CompiledMethod::ReleaseSwapAllocatedCompiledMethod(driver_, method);
+ CompiledMethod::ReleaseSwapAllocatedCompiledMethod(driver_->GetCompiledMethodStorage(),
+ method);
}
}
}
diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc
index 8b35bd3cb1..9fac2bc98b 100644
--- a/compiler/driver/compiled_method_storage_test.cc
+++ b/compiler/driver/compiled_method_storage_test.cc
@@ -19,24 +19,13 @@
#include <gtest/gtest.h>
#include "compiled_method-inl.h"
-#include "compiler_driver.h"
-#include "compiler_options.h"
-#include "dex/verification_results.h"
namespace art {
TEST(CompiledMethodStorage, Deduplicate) {
- CompilerOptions compiler_options;
- VerificationResults verification_results(&compiler_options);
- CompilerDriver driver(&compiler_options,
- &verification_results,
- Compiler::kOptimizing,
- /* image_classes */ nullptr,
- /* thread_count */ 1u,
- /* swap_fd */ -1);
- CompiledMethodStorage* storage = driver.GetCompiledMethodStorage();
+ CompiledMethodStorage storage(/* swap_fd */ -1);
- ASSERT_TRUE(storage->DedupeEnabled()); // The default.
+ ASSERT_TRUE(storage.DedupeEnabled()); // The default.
const uint8_t raw_code1[] = { 1u, 2u, 3u };
const uint8_t raw_code2[] = { 4u, 3u, 2u, 1u };
@@ -76,7 +65,7 @@ TEST(CompiledMethodStorage, Deduplicate) {
for (auto&& f : cfi_info) {
for (auto&& p : patches) {
compiled_methods.push_back(CompiledMethod::SwapAllocCompiledMethod(
- &driver, InstructionSet::kNone, c, v, f, p));
+ &storage, InstructionSet::kNone, c, v, f, p));
}
}
}
@@ -105,7 +94,7 @@ TEST(CompiledMethodStorage, Deduplicate) {
}
}
for (CompiledMethod* method : compiled_methods) {
- CompiledMethod::ReleaseSwapAllocatedCompiledMethod(&driver, method);
+ CompiledMethod::ReleaseSwapAllocatedCompiledMethod(&storage, method);
}
}
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 0d0a7f2b6a..77b0cea311 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -276,7 +276,7 @@ CompilerDriver::~CompilerDriver() {
compiled_methods_.Visit([this](const DexFileReference& ref ATTRIBUTE_UNUSED,
CompiledMethod* method) {
if (method != nullptr) {
- CompiledMethod::ReleaseSwapAllocatedCompiledMethod(this, method);
+ CompiledMethod::ReleaseSwapAllocatedCompiledMethod(GetCompiledMethodStorage(), method);
}
});
compiler_->UnInit();
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index fe6abd4999..1db20fcfeb 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -765,7 +765,7 @@ CompiledMethod* OptimizingCompiler::Emit(ArenaAllocator* allocator,
ScopedArenaVector<uint8_t> stack_map = codegen->BuildStackMaps(code_item_for_osr_check);
CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod(
- GetCompilerDriver(),
+ GetCompilerDriver()->GetCompiledMethodStorage(),
codegen->GetInstructionSet(),
code_allocator->GetMemory(),
ArrayRef<const uint8_t>(stack_map),
@@ -1222,7 +1222,7 @@ CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags,
ScopedArenaVector<uint8_t> stack_map = CreateJniStackMap(&stack_map_allocator,
jni_compiled_method);
return CompiledMethod::SwapAllocCompiledMethod(
- GetCompilerDriver(),
+ GetCompilerDriver()->GetCompiledMethodStorage(),
jni_compiled_method.GetInstructionSet(),
jni_compiled_method.GetCode(),
ArrayRef<const uint8_t>(stack_map),
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index baeebd9371..1fa21d51fc 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1202,6 +1202,17 @@ TEST_F(Dex2oatClassLoaderContextTest, ChainContext) {
RunTest(context.c_str(), expected_classpath_key.c_str(), true);
}
+TEST_F(Dex2oatClassLoaderContextTest, ContextWithSharedLibrary) {
+ std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
+ std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
+
+ std::string context = "PCL[" + GetTestDexFileName("Nested") + "]" +
+ "{PCL[" + GetTestDexFileName("MultiDex") + "]}";
+ std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "]" +
+ "{PCL[" + CreateClassPathWithChecksums(dex_files2) + "]}";
+ RunTest(context.c_str(), expected_classpath_key.c_str(), true);
+}
+
class Dex2oatDeterminism : public Dex2oatTest {};
TEST_F(Dex2oatDeterminism, UnloadCompile) {
diff --git a/dex2oat/linker/arm/relative_patcher_thumb2_test.cc b/dex2oat/linker/arm/relative_patcher_thumb2_test.cc
index b93e091ae6..d8cbbaf61a 100644
--- a/dex2oat/linker/arm/relative_patcher_thumb2_test.cc
+++ b/dex2oat/linker/arm/relative_patcher_thumb2_test.cc
@@ -18,6 +18,7 @@
#include "arch/arm/instruction_set_features_arm.h"
#include "base/casts.h"
+#include "driver/compiler_options.h"
#include "linker/relative_patcher_test.h"
#include "lock_word.h"
#include "mirror/array-inl.h"
@@ -196,8 +197,8 @@ class Thumb2RelativePatcherTest : public RelativePatcherTest {
/*out*/ std::string* debug_name = nullptr) {
OptimizingUnitTestHelper helper;
HGraph* graph = helper.CreateGraph();
- std::string error_msg;
- arm::CodeGeneratorARMVIXL codegen(graph, *compiler_options_);
+ CompilerOptions compiler_options;
+ arm::CodeGeneratorARMVIXL codegen(graph, compiler_options);
ArenaVector<uint8_t> code(helper.GetAllocator()->Adapter());
codegen.EmitThunkCode(patch, &code, debug_name);
return std::vector<uint8_t>(code.begin(), code.end());
diff --git a/dex2oat/linker/arm64/relative_patcher_arm64_test.cc b/dex2oat/linker/arm64/relative_patcher_arm64_test.cc
index 0fc4610909..f242ae286b 100644
--- a/dex2oat/linker/arm64/relative_patcher_arm64_test.cc
+++ b/dex2oat/linker/arm64/relative_patcher_arm64_test.cc
@@ -18,6 +18,7 @@
#include "arch/arm64/instruction_set_features_arm64.h"
#include "base/casts.h"
+#include "driver/compiler_options.h"
#include "linker/relative_patcher_test.h"
#include "lock_word.h"
#include "mirror/array-inl.h"
@@ -175,8 +176,8 @@ class Arm64RelativePatcherTest : public RelativePatcherTest {
/*out*/ std::string* debug_name = nullptr) {
OptimizingUnitTestHelper helper;
HGraph* graph = helper.CreateGraph();
- std::string error_msg;
- arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
+ CompilerOptions compiler_options;
+ arm64::CodeGeneratorARM64 codegen(graph, compiler_options);
ArenaVector<uint8_t> code(helper.GetAllocator()->Adapter());
codegen.EmitThunkCode(patch, &code, debug_name);
return std::vector<uint8_t>(code.begin(), code.end());
diff --git a/dex2oat/linker/relative_patcher_test.h b/dex2oat/linker/relative_patcher_test.h
index 56ff0ef3ca..4329ee1697 100644
--- a/dex2oat/linker/relative_patcher_test.h
+++ b/dex2oat/linker/relative_patcher_test.h
@@ -17,19 +17,17 @@
#ifndef ART_DEX2OAT_LINKER_RELATIVE_PATCHER_TEST_H_
#define ART_DEX2OAT_LINKER_RELATIVE_PATCHER_TEST_H_
+#include <gtest/gtest.h>
+
#include "arch/instruction_set.h"
#include "arch/instruction_set_features.h"
#include "base/array_ref.h"
#include "base/globals.h"
#include "base/macros.h"
-#include "common_compiler_test.h"
#include "compiled_method-inl.h"
-#include "dex/verification_results.h"
#include "dex/method_reference.h"
#include "dex/string_reference.h"
-#include "driver/compiler_driver.h"
-#include "driver/compiler_options.h"
-#include "gtest/gtest.h"
+#include "driver/compiled_method_storage.h"
#include "linker/relative_patcher.h"
#include "linker/vector_output_stream.h"
#include "oat.h"
@@ -39,10 +37,12 @@ namespace art {
namespace linker {
// Base class providing infrastructure for architecture-specific tests.
-class RelativePatcherTest : public CommonCompilerTest {
+class RelativePatcherTest : public testing::Test {
protected:
RelativePatcherTest(InstructionSet instruction_set, const std::string& variant)
- : variant_(variant),
+ : storage_(/*swap_fd=*/ -1),
+ instruction_set_(instruction_set),
+ instruction_set_features_(nullptr),
method_offset_map_(),
patcher_(nullptr),
bss_begin_(0u),
@@ -51,23 +51,29 @@ class RelativePatcherTest : public CommonCompilerTest {
patched_code_(),
output_(),
out_(nullptr) {
- // Override CommonCompilerTest's defaults.
- instruction_set_ = instruction_set;
- number_of_threads_ = 1u;
+ std::string error_msg;
+ instruction_set_features_ =
+ InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg);
+ CHECK(instruction_set_features_ != nullptr) << error_msg;
+
patched_code_.reserve(16 * KB);
}
void SetUp() override {
- OverrideInstructionSetFeatures(instruction_set_, variant_);
- CommonCompilerTest::SetUp();
-
Reset();
}
void TearDown() override {
+ thunk_provider_.Reset();
compiled_methods_.clear();
patcher_.reset();
- CommonCompilerTest::TearDown();
+ bss_begin_ = 0u;
+ string_index_to_offset_map_.clear();
+ compiled_method_refs_.clear();
+ compiled_methods_.clear();
+ patched_code_.clear();
+ output_.clear();
+ out_.reset();
}
// Reset the helper to start another test. Creating and tearing down the Runtime is expensive,
@@ -75,8 +81,8 @@ class RelativePatcherTest : public CommonCompilerTest {
void Reset() {
thunk_provider_.Reset();
method_offset_map_.map.clear();
- patcher_ = RelativePatcher::Create(compiler_options_->GetInstructionSet(),
- compiler_options_->GetInstructionSetFeatures(),
+ patcher_ = RelativePatcher::Create(instruction_set_,
+ instruction_set_features_.get(),
&thunk_provider_,
&method_offset_map_);
bss_begin_ = 0u;
@@ -99,7 +105,7 @@ class RelativePatcherTest : public CommonCompilerTest {
const ArrayRef<const LinkerPatch>& patches = ArrayRef<const LinkerPatch>()) {
compiled_method_refs_.push_back(method_ref);
compiled_methods_.emplace_back(new CompiledMethod(
- compiler_driver_.get(),
+ &storage_,
instruction_set_,
code,
/* vmap_table */ ArrayRef<const uint8_t>(),
@@ -351,7 +357,10 @@ class RelativePatcherTest : public CommonCompilerTest {
static const uint32_t kTrampolineSize = 4u;
static const uint32_t kTrampolineOffset = 0u;
- std::string variant_;
+ CompiledMethodStorage storage_;
+ InstructionSet instruction_set_;
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
+
ThunkProvider thunk_provider_;
MethodOffsetMap method_offset_map_;
std::unique_ptr<RelativePatcher> patcher_;
diff --git a/libartbase/arch/instruction_set.cc b/libartbase/arch/instruction_set.cc
index d47f9362d4..8d4fbf4422 100644
--- a/libartbase/arch/instruction_set.cc
+++ b/libartbase/arch/instruction_set.cc
@@ -133,11 +133,11 @@ static_assert(ART_FRAME_SIZE_LIMIT < kX86StackOverflowReservedBytes,
static_assert(ART_FRAME_SIZE_LIMIT < kX86_64StackOverflowReservedBytes,
"Frame size limit too large");
-} // namespace instruction_set_details
-
NO_RETURN void GetStackOverflowReservedBytesFailure(const char* error_msg) {
LOG(FATAL) << error_msg;
UNREACHABLE();
}
+} // namespace instruction_set_details
+
} // namespace art
diff --git a/libartbase/base/sdk_version.h b/libartbase/base/sdk_version.h
new file mode 100644
index 0000000000..4372e5a02f
--- /dev/null
+++ b/libartbase/base/sdk_version.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_LIBARTBASE_BASE_SDK_VERSION_H_
+#define ART_LIBARTBASE_BASE_SDK_VERSION_H_
+
+#include <cstdint>
+#include <limits>
+
+namespace art {
+
+enum class SdkVersion : uint32_t {
+ kMin = 0u,
+ kUnset = 0u,
+ kL = 21u,
+ kL_MR1 = 22u,
+ kM = 23u,
+ kN = 24u,
+ kN_MR1 = 25u,
+ kO = 26u,
+ kO_MR1 = 27u,
+ kP = 28u,
+ kP_MR1 = 29u,
+ kMax = std::numeric_limits<uint32_t>::max(),
+};
+
+inline bool IsSdkVersionSetAndMoreThan(uint32_t lhs, SdkVersion rhs) {
+ return lhs != static_cast<uint32_t>(SdkVersion::kUnset) && lhs > static_cast<uint32_t>(rhs);
+}
+
+inline bool IsSdkVersionSetAndAtLeast(uint32_t lhs, SdkVersion rhs) {
+ return lhs != static_cast<uint32_t>(SdkVersion::kUnset) && lhs >= static_cast<uint32_t>(rhs);
+}
+
+inline bool IsSdkVersionSetAndAtMost(uint32_t lhs, SdkVersion rhs) {
+ return lhs != static_cast<uint32_t>(SdkVersion::kUnset) && lhs <= static_cast<uint32_t>(rhs);
+}
+
+inline bool IsSdkVersionSetAndLessThan(uint32_t lhs, SdkVersion rhs) {
+ return lhs != static_cast<uint32_t>(SdkVersion::kUnset) && lhs < static_cast<uint32_t>(rhs);
+}
+
+} // namespace art
+
+#endif // ART_LIBARTBASE_BASE_SDK_VERSION_H_
diff --git a/libdexfile/dex/hidden_api_access_flags.h b/libdexfile/dex/hidden_api_access_flags.h
index fd5c8654c3..77bfbc99b3 100644
--- a/libdexfile/dex/hidden_api_access_flags.h
+++ b/libdexfile/dex/hidden_api_access_flags.h
@@ -48,27 +48,6 @@ enum class ApiList {
kNoList,
};
-static const int kAccFlagsShift = CTZ(kAccHiddenApiBits);
-static_assert(IsPowerOfTwo((kAccHiddenApiBits >> kAccFlagsShift) + 1),
- "kAccHiddenApiBits are not continuous");
-
-inline ApiList DecodeFromRuntime(uint32_t runtime_access_flags) {
- // This is used in the fast path, only DCHECK here.
- DCHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
- uint32_t int_value = (runtime_access_flags & kAccHiddenApiBits) >> kAccFlagsShift;
- return static_cast<ApiList>(int_value);
-}
-
-inline uint32_t EncodeForRuntime(uint32_t runtime_access_flags, ApiList value) {
- CHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
-
- uint32_t hidden_api_flags = static_cast<uint32_t>(value) << kAccFlagsShift;
- CHECK_EQ(hidden_api_flags & ~kAccHiddenApiBits, 0u);
-
- runtime_access_flags &= ~kAccHiddenApiBits;
- return runtime_access_flags | hidden_api_flags;
-}
-
inline bool AreValidFlags(uint32_t flags) {
return flags <= static_cast<uint32_t>(ApiList::kBlacklist);
}
diff --git a/libdexfile/dex/modifiers.h b/libdexfile/dex/modifiers.h
index c4ea2d39b4..114c8e63e3 100644
--- a/libdexfile/dex/modifiers.h
+++ b/libdexfile/dex/modifiers.h
@@ -52,7 +52,7 @@ static constexpr uint32_t kAccObsoleteMethod = 0x00040000; // method (ru
static constexpr uint32_t kAccSkipAccessChecks = 0x00080000; // method (runtime, not native)
// Used by a class to denote that the verifier has attempted to check it at least once.
static constexpr uint32_t kAccVerificationAttempted = 0x00080000; // class (runtime)
-static constexpr uint32_t kAccSkipHiddenApiChecks = 0x00100000; // class (runtime)
+static constexpr uint32_t kAccSkipHiddenapiChecks = 0x00100000; // class (runtime)
// This is set by the class linker during LinkInterfaceMethods. It is used by a method to represent
// that it was copied from its declaring class into another class. All methods marked kAccMiranda
// and kAccDefaultConflict will have this bit set. Any kAccDefault method contained in the methods_
@@ -84,7 +84,8 @@ static constexpr uint32_t kAccMustCountLocks = 0x04000000; // method (ru
// virtual call.
static constexpr uint32_t kAccSingleImplementation = 0x08000000; // method (runtime)
-static constexpr uint32_t kAccHiddenApiBits = 0x30000000; // field, method
+static constexpr uint32_t kAccPublicApi = 0x10000000; // field, method
+static constexpr uint32_t kAccHiddenapiBits = 0x30000000; // field, method
// Non-intrinsics: Caches whether we can use fast-path in the interpreter invokes.
// Intrinsics: These bits are part of the intrinsic ordinal.
@@ -103,7 +104,7 @@ static constexpr uint32_t kAccClassIsFinalizable = 0x80000000;
// Continuous sequence of bits used to hold the ordinal of an intrinsic method. Flags
// which overlap are not valid when kAccIntrinsic is set.
-static constexpr uint32_t kAccIntrinsicBits = kAccHiddenApiBits |
+static constexpr uint32_t kAccIntrinsicBits = kAccHiddenapiBits |
kAccSingleImplementation | kAccMustCountLocks | kAccCompileDontBother | kAccDefaultConflict |
kAccPreviouslyWarm | kAccFastInterpreterToInterpreterInvoke;
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 7cd10394d5..cabb758912 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -1427,6 +1427,11 @@ 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);
}
}
@@ -1445,6 +1450,11 @@ 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);
}
}
}
diff --git a/runtime/art_field.h b/runtime/art_field.h
index dc7f985b91..1cf7afa022 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -180,10 +180,6 @@ class ArtField final {
return (GetAccessFlags() & kAccVolatile) != 0;
}
- hiddenapi::ApiList GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_) {
- return hiddenapi::DecodeFromRuntime(GetAccessFlags());
- }
-
// Returns an instance field with this offset in the given class or null if not found.
// If kExactOffset is true then we only find the matching offset, not the field containing the
// offset.
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index d8da9129ed..f2541160ff 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -367,160 +367,6 @@ inline bool ArtMethod::HasSingleImplementation() {
return (GetAccessFlags() & kAccSingleImplementation) != 0;
}
-inline hiddenapi::ApiList ArtMethod::GetHiddenApiAccessFlags()
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (UNLIKELY(IsIntrinsic())) {
- switch (static_cast<Intrinsics>(GetIntrinsic())) {
- case Intrinsics::kSystemArrayCopyChar:
- case Intrinsics::kStringGetCharsNoCheck:
- case Intrinsics::kReferenceGetReferent:
- case Intrinsics::kMemoryPeekByte:
- case Intrinsics::kMemoryPokeByte:
- case Intrinsics::kUnsafeCASInt:
- case Intrinsics::kUnsafeCASLong:
- case Intrinsics::kUnsafeCASObject:
- case Intrinsics::kUnsafeGet:
- case Intrinsics::kUnsafeGetAndAddInt:
- case Intrinsics::kUnsafeGetAndAddLong:
- case Intrinsics::kUnsafeGetAndSetInt:
- case Intrinsics::kUnsafeGetAndSetLong:
- case Intrinsics::kUnsafeGetAndSetObject:
- case Intrinsics::kUnsafeGetLong:
- case Intrinsics::kUnsafeGetLongVolatile:
- case Intrinsics::kUnsafeGetObject:
- case Intrinsics::kUnsafeGetObjectVolatile:
- case Intrinsics::kUnsafeGetVolatile:
- case Intrinsics::kUnsafePut:
- case Intrinsics::kUnsafePutLong:
- case Intrinsics::kUnsafePutLongOrdered:
- case Intrinsics::kUnsafePutLongVolatile:
- case Intrinsics::kUnsafePutObject:
- case Intrinsics::kUnsafePutObjectOrdered:
- case Intrinsics::kUnsafePutObjectVolatile:
- case Intrinsics::kUnsafePutOrdered:
- case Intrinsics::kUnsafePutVolatile:
- case Intrinsics::kUnsafeLoadFence:
- case Intrinsics::kUnsafeStoreFence:
- case Intrinsics::kUnsafeFullFence:
- case Intrinsics::kCRC32Update:
- // These intrinsics are on the light greylist and will fail a DCHECK in
- // SetIntrinsic() if their flags change on the respective dex methods.
- // Note that the DCHECK currently won't fail if the dex methods are
- // whitelisted, e.g. in the core image (b/77733081). As a result, we
- // might print warnings but we won't change the semantics.
- return hiddenapi::ApiList::kLightGreylist;
- case Intrinsics::kStringNewStringFromBytes:
- case Intrinsics::kStringNewStringFromChars:
- case Intrinsics::kStringNewStringFromString:
- case Intrinsics::kMemoryPeekIntNative:
- case Intrinsics::kMemoryPeekLongNative:
- case Intrinsics::kMemoryPeekShortNative:
- case Intrinsics::kMemoryPokeIntNative:
- case Intrinsics::kMemoryPokeLongNative:
- case Intrinsics::kMemoryPokeShortNative:
- return hiddenapi::ApiList::kDarkGreylist;
- case Intrinsics::kVarHandleFullFence:
- case Intrinsics::kVarHandleAcquireFence:
- case Intrinsics::kVarHandleReleaseFence:
- case Intrinsics::kVarHandleLoadLoadFence:
- case Intrinsics::kVarHandleStoreStoreFence:
- case Intrinsics::kVarHandleCompareAndExchange:
- case Intrinsics::kVarHandleCompareAndExchangeAcquire:
- case Intrinsics::kVarHandleCompareAndExchangeRelease:
- case Intrinsics::kVarHandleCompareAndSet:
- case Intrinsics::kVarHandleGet:
- case Intrinsics::kVarHandleGetAcquire:
- case Intrinsics::kVarHandleGetAndAdd:
- case Intrinsics::kVarHandleGetAndAddAcquire:
- case Intrinsics::kVarHandleGetAndAddRelease:
- case Intrinsics::kVarHandleGetAndBitwiseAnd:
- case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
- case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
- case Intrinsics::kVarHandleGetAndBitwiseOr:
- case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
- case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
- case Intrinsics::kVarHandleGetAndBitwiseXor:
- case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
- case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
- case Intrinsics::kVarHandleGetAndSet:
- case Intrinsics::kVarHandleGetAndSetAcquire:
- case Intrinsics::kVarHandleGetAndSetRelease:
- case Intrinsics::kVarHandleGetOpaque:
- case Intrinsics::kVarHandleGetVolatile:
- case Intrinsics::kVarHandleSet:
- case Intrinsics::kVarHandleSetOpaque:
- case Intrinsics::kVarHandleSetRelease:
- case Intrinsics::kVarHandleSetVolatile:
- case Intrinsics::kVarHandleWeakCompareAndSet:
- case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
- case Intrinsics::kVarHandleWeakCompareAndSetPlain:
- case Intrinsics::kVarHandleWeakCompareAndSetRelease:
- // These intrinsics are on the blacklist and will fail a DCHECK in
- // SetIntrinsic() if their flags change on the respective dex methods.
- // Note that the DCHECK currently won't fail if the dex methods are
- // whitelisted, e.g. in the core image (b/77733081). Given that they are
- // exclusively VarHandle intrinsics, they should not be used outside
- // tests that do not enable hidden API checks.
- return hiddenapi::ApiList::kBlacklist;
- default:
- // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
- return hiddenapi::ApiList::kWhitelist;
- }
- } else {
- return hiddenapi::DecodeFromRuntime(GetAccessFlags());
- }
-}
-
-inline void ArtMethod::SetIntrinsic(uint32_t intrinsic) {
- // Currently we only do intrinsics for static/final methods or methods of final
- // classes. We don't set kHasSingleImplementation for those methods.
- DCHECK(IsStatic() || IsFinal() || GetDeclaringClass()->IsFinal()) <<
- "Potential conflict with kAccSingleImplementation";
- static const int kAccFlagsShift = CTZ(kAccIntrinsicBits);
- DCHECK_LE(intrinsic, kAccIntrinsicBits >> kAccFlagsShift);
- uint32_t intrinsic_bits = intrinsic << kAccFlagsShift;
- uint32_t new_value = (GetAccessFlags() & ~kAccIntrinsicBits) | kAccIntrinsic | intrinsic_bits;
- if (kIsDebugBuild) {
- uint32_t java_flags = (GetAccessFlags() & kAccJavaFlagsMask);
- bool is_constructor = IsConstructor();
- bool is_synchronized = IsSynchronized();
- bool skip_access_checks = SkipAccessChecks();
- bool is_fast_native = IsFastNative();
- bool is_critical_native = IsCriticalNative();
- bool is_copied = IsCopied();
- bool is_miranda = IsMiranda();
- bool is_default = IsDefault();
- bool is_default_conflict = IsDefaultConflicting();
- bool is_compilable = IsCompilable();
- bool must_count_locks = MustCountLocks();
- hiddenapi::ApiList hidden_api_flags = GetHiddenApiAccessFlags();
- SetAccessFlags(new_value);
- DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask));
- DCHECK_EQ(is_constructor, IsConstructor());
- DCHECK_EQ(is_synchronized, IsSynchronized());
- DCHECK_EQ(skip_access_checks, SkipAccessChecks());
- DCHECK_EQ(is_fast_native, IsFastNative());
- DCHECK_EQ(is_critical_native, IsCriticalNative());
- DCHECK_EQ(is_copied, IsCopied());
- DCHECK_EQ(is_miranda, IsMiranda());
- DCHECK_EQ(is_default, IsDefault());
- DCHECK_EQ(is_default_conflict, IsDefaultConflicting());
- DCHECK_EQ(is_compilable, IsCompilable());
- DCHECK_EQ(must_count_locks, MustCountLocks());
- // Only DCHECK that we have preserved the hidden API access flags if the
- // original method was not on the whitelist. This is because the core image
- // does not have the access flags set (b/77733081). It is fine to hard-code
- // these because (a) warnings on greylist do not change semantics, and
- // (b) only VarHandle intrinsics are blacklisted at the moment and they
- // should not be used outside tests with disabled API checks.
- if (hidden_api_flags != hiddenapi::ApiList::kWhitelist) {
- DCHECK_EQ(hidden_api_flags, GetHiddenApiAccessFlags()) << PrettyMethod();
- }
- } else {
- SetAccessFlags(new_value);
- }
-}
-
template<ReadBarrierOption kReadBarrierOption, typename RootVisitorType>
void ArtMethod::VisitRoots(RootVisitorType& visitor, PointerSize pointer_size) {
if (LIKELY(!declaring_class_.IsNull())) {
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 9bf31edd52..abfdd5547d 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -33,6 +33,7 @@
#include "dex/dex_instruction.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
+#include "hidden_api.h"
#include "interpreter/interpreter.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
@@ -682,23 +683,72 @@ bool ArtMethod::HasAnyCompiledCode() {
return GetOatMethodQuickCode(runtime->GetClassLinker()->GetImagePointerSize()) != nullptr;
}
+void ArtMethod::SetIntrinsic(uint32_t intrinsic) {
+ // Currently we only do intrinsics for static/final methods or methods of final
+ // classes. We don't set kHasSingleImplementation for those methods.
+ DCHECK(IsStatic() || IsFinal() || GetDeclaringClass()->IsFinal()) <<
+ "Potential conflict with kAccSingleImplementation";
+ static const int kAccFlagsShift = CTZ(kAccIntrinsicBits);
+ DCHECK_LE(intrinsic, kAccIntrinsicBits >> kAccFlagsShift);
+ uint32_t intrinsic_bits = intrinsic << kAccFlagsShift;
+ uint32_t new_value = (GetAccessFlags() & ~kAccIntrinsicBits) | kAccIntrinsic | intrinsic_bits;
+ if (kIsDebugBuild) {
+ uint32_t java_flags = (GetAccessFlags() & kAccJavaFlagsMask);
+ bool is_constructor = IsConstructor();
+ bool is_synchronized = IsSynchronized();
+ bool skip_access_checks = SkipAccessChecks();
+ bool is_fast_native = IsFastNative();
+ bool is_critical_native = IsCriticalNative();
+ bool is_copied = IsCopied();
+ bool is_miranda = IsMiranda();
+ bool is_default = IsDefault();
+ bool is_default_conflict = IsDefaultConflicting();
+ bool is_compilable = IsCompilable();
+ bool must_count_locks = MustCountLocks();
+ uint32_t hiddenapi_flags = hiddenapi::GetRuntimeFlags(this);
+ SetAccessFlags(new_value);
+ DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask));
+ DCHECK_EQ(is_constructor, IsConstructor());
+ DCHECK_EQ(is_synchronized, IsSynchronized());
+ DCHECK_EQ(skip_access_checks, SkipAccessChecks());
+ DCHECK_EQ(is_fast_native, IsFastNative());
+ DCHECK_EQ(is_critical_native, IsCriticalNative());
+ DCHECK_EQ(is_copied, IsCopied());
+ DCHECK_EQ(is_miranda, IsMiranda());
+ DCHECK_EQ(is_default, IsDefault());
+ DCHECK_EQ(is_default_conflict, IsDefaultConflicting());
+ DCHECK_EQ(is_compilable, IsCompilable());
+ DCHECK_EQ(must_count_locks, MustCountLocks());
+ // Only DCHECK that we have preserved the hidden API access flags if the
+ // original method was not on the whitelist. This is because the core image
+ // does not have the access flags set (b/77733081). It is fine to hard-code
+ // these because (a) warnings on greylist do not change semantics, and
+ // (b) only VarHandle intrinsics are blacklisted at the moment and they
+ // should not be used outside tests with disabled API checks.
+ if ((hiddenapi_flags & kAccHiddenapiBits) == 0) {
+ DCHECK_EQ(hiddenapi_flags, hiddenapi::GetRuntimeFlags(this)) << PrettyMethod();
+ }
+ } else {
+ SetAccessFlags(new_value);
+ }
+}
+
void ArtMethod::SetNotIntrinsic() {
if (!IsIntrinsic()) {
return;
}
- // Query the hidden API access flags of the intrinsic.
- hiddenapi::ApiList intrinsic_api_list = GetHiddenApiAccessFlags();
+ // Read the existing hiddenapi flags.
+ uint32_t hiddenapi_runtime_flags = hiddenapi::GetRuntimeFlags(this);
// Clear intrinsic-related access flags.
ClearAccessFlags(kAccIntrinsic | kAccIntrinsicBits);
// Re-apply hidden API access flags now that the method is not an intrinsic.
- SetAccessFlags(hiddenapi::EncodeForRuntime(GetAccessFlags(), intrinsic_api_list));
- DCHECK_EQ(GetHiddenApiAccessFlags(), intrinsic_api_list);
+ SetAccessFlags(GetAccessFlags() | hiddenapi_runtime_flags);
+ DCHECK_EQ(hiddenapi_runtime_flags, hiddenapi::GetRuntimeFlags(this));
}
-
void ArtMethod::CopyFrom(ArtMethod* src, PointerSize image_pointer_size) {
memcpy(reinterpret_cast<void*>(this), reinterpret_cast<const void*>(src),
Size(image_pointer_size));
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 4e3ef5366a..5bbee92c14 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -343,8 +343,6 @@ class ArtMethod final {
AddAccessFlags(kAccMustCountLocks);
}
- hiddenapi::ApiList GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_);
-
// Returns true if this method could be overridden by a default method.
bool IsOverridableByDefaultMethod() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 35379cc251..639fa7ec92 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -798,6 +798,8 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
FindSystemClass(self, "Ljava/lang/StackTraceElement;"));
SetClassRoot(ClassRoot::kJavaLangStackTraceElementArrayClass,
FindSystemClass(self, "[Ljava/lang/StackTraceElement;"));
+ SetClassRoot(ClassRoot::kJavaLangClassLoaderArrayClass,
+ FindSystemClass(self, "[Ljava/lang/ClassLoader;"));
// Create conflict tables that depend on the class linker.
runtime->FixupConflictTables();
@@ -3468,14 +3470,8 @@ void ClassLinker::LoadField(const ClassAccessor::Field& field,
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.Get());
- // Get access flags from the DexFile. If this is a boot class path class,
- // also set its runtime hidden API access flags.
- uint32_t access_flags = field.GetAccessFlags();
- if (klass->IsBootStrapClassLoaded()) {
- access_flags = hiddenapi::EncodeForRuntime(
- access_flags, static_cast<hiddenapi::ApiList>(field.GetHiddenapiFlags()));
- }
- dst->SetAccessFlags(access_flags);
+ // Get access flags from the DexFile and set hiddenapi runtime access flags.
+ dst->SetAccessFlags(field.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(field));
}
void ClassLinker::LoadMethod(const DexFile& dex_file,
@@ -3491,13 +3487,8 @@ void ClassLinker::LoadMethod(const DexFile& dex_file,
dst->SetDeclaringClass(klass.Get());
dst->SetCodeItemOffset(method.GetCodeItemOffset());
- // Get access flags from the DexFile. If this is a boot class path class,
- // also set its runtime hidden API access flags.
- uint32_t access_flags = method.GetAccessFlags();
- if (klass->IsBootStrapClassLoaded()) {
- access_flags = hiddenapi::EncodeForRuntime(
- access_flags, static_cast<hiddenapi::ApiList>(method.GetHiddenapiFlags()));
- }
+ // Get access flags from the DexFile and set hiddenapi runtime access flags.
+ uint32_t access_flags = method.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(method);
if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
// Set finalizable flag on declaring class.
@@ -9005,21 +8996,14 @@ void ClassLinker::AllocAndSetPrimitiveArrayClassRoot(Thread* self,
CheckSystemClass(self, primitive_array_class, descriptor);
}
-jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
- const std::vector<const DexFile*>& dex_files,
- jclass loader_class,
- jobject parent_loader) {
- CHECK(self->GetJniEnv()->IsSameObject(loader_class,
- WellKnownClasses::dalvik_system_PathClassLoader) ||
- self->GetJniEnv()->IsSameObject(loader_class,
- WellKnownClasses::dalvik_system_DelegateLastClassLoader));
-
- // SOAAlreadyRunnable is protected, and we need something to add a global reference.
- // We could move the jobject to the callers, but all call-sites do this...
- ScopedObjectAccessUnchecked soa(self);
+ObjPtr<mirror::ClassLoader> ClassLinker::CreateWellKnownClassLoader(
+ Thread* self,
+ const std::vector<const DexFile*>& dex_files,
+ Handle<mirror::Class> loader_class,
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries,
+ Handle<mirror::ClassLoader> parent_loader) {
- // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
- StackHandleScope<6> hs(self);
+ StackHandleScope<5> hs(self);
ArtField* dex_elements_field =
jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements);
@@ -9109,8 +9093,8 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
}
// Create the class loader..
- Handle<mirror::Class> h_loader_class = hs.NewHandle(soa.Decode<mirror::Class>(loader_class));
- Handle<mirror::Object> h_class_loader = hs.NewHandle(h_loader_class->AllocObject(self));
+ Handle<mirror::ClassLoader> h_class_loader = hs.NewHandle<mirror::ClassLoader>(
+ ObjPtr<mirror::ClassLoader>::DownCast(loader_class->AllocObject(self)));
DCHECK(h_class_loader != nullptr);
// Set DexPathList.
ArtField* path_list_field =
@@ -9126,15 +9110,59 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
"parent",
"Ljava/lang/ClassLoader;");
DCHECK(parent_field != nullptr);
+ if (parent_loader.Get() == nullptr) {
+ ScopedObjectAccessUnchecked soa(self);
+ ObjPtr<mirror::Object> boot_loader(soa.Decode<mirror::Class>(
+ WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self));
+ parent_field->SetObject<false>(h_class_loader.Get(), boot_loader);
+ } else {
+ parent_field->SetObject<false>(h_class_loader.Get(), parent_loader.Get());
+ }
- ObjPtr<mirror::Object> parent = (parent_loader != nullptr)
- ? soa.Decode<mirror::ClassLoader>(parent_loader)
- : soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
- parent_field->SetObject<false>(h_class_loader.Get(), parent);
+ ArtField* shared_libraries_field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ DCHECK(shared_libraries_field != nullptr);
+ shared_libraries_field->SetObject<false>(h_class_loader.Get(), shared_libraries.Get());
+
+ return h_class_loader.Get();
+}
+
+jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
+ const std::vector<const DexFile*>& dex_files,
+ jclass loader_class,
+ jobject parent_loader) {
+ CHECK(self->GetJniEnv()->IsSameObject(loader_class,
+ WellKnownClasses::dalvik_system_PathClassLoader) ||
+ self->GetJniEnv()->IsSameObject(loader_class,
+ WellKnownClasses::dalvik_system_DelegateLastClassLoader));
+
+ // SOAAlreadyRunnable is protected, and we need something to add a global reference.
+ // We could move the jobject to the callers, but all call-sites do this...
+ ScopedObjectAccessUnchecked soa(self);
+
+ // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
+ StackHandleScope<3> hs(self);
+
+ Handle<mirror::Class> h_loader_class =
+ hs.NewHandle<mirror::Class>(soa.Decode<mirror::Class>(loader_class));
+ Handle<mirror::ClassLoader> parent =
+ hs.NewHandle<mirror::ClassLoader>(ObjPtr<mirror::ClassLoader>::DownCast(
+ (parent_loader != nullptr)
+ ? soa.Decode<mirror::ClassLoader>(parent_loader)
+ : nullptr));
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries =
+ hs.NewHandle<mirror::ObjectArray<mirror::ClassLoader>>(nullptr);
+
+ ObjPtr<mirror::ClassLoader> loader = CreateWellKnownClassLoader(
+ self,
+ dex_files,
+ h_loader_class,
+ shared_libraries,
+ parent);
// Make it a global ref and return.
ScopedLocalRef<jobject> local_ref(
- soa.Env(), soa.Env()->AddLocalReference<jobject>(h_class_loader.Get()));
+ soa.Env(), soa.Env()->AddLocalReference<jobject>(loader));
return soa.Env()->NewGlobalRef(local_ref.get());
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index a65299a514..47931fec75 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -586,6 +586,16 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
+ // Non-GlobalRef version of CreateWellKnownClassLoader
+ ObjPtr<mirror::ClassLoader> CreateWellKnownClassLoader(
+ Thread* self,
+ const std::vector<const DexFile*>& dex_files,
+ Handle<mirror::Class> loader_class,
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries,
+ Handle<mirror::ClassLoader> parent_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Locks::dex_lock_);
+
PointerSize GetImagePointerSize() const {
return image_pointer_size_;
}
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 0bae60a886..7ca6f86fe3 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -24,11 +24,14 @@
#include "base/stl_util.h"
#include "class_linker.h"
#include "class_loader_utils.h"
+#include "class_root.h"
#include "dex/art_dex_file_loader.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "handle_scope-inl.h"
#include "jni/jni_internal.h"
+#include "mirror/object_array-alloc-inl.h"
+#include "nativehelper/scoped_local_ref.h"
#include "oat_file_assistant.h"
#include "obj_ptr-inl.h"
#include "runtime.h"
@@ -107,6 +110,39 @@ std::unique_ptr<ClassLoaderContext> ClassLoaderContext::Create(const std::string
}
}
+static size_t FindMatchingSharedLibraryCloseMarker(const std::string& spec,
+ size_t shared_library_open_index) {
+ // Counter of opened shared library marker we've encountered so far.
+ uint32_t counter = 1;
+ // The index at which we're operating in the loop.
+ uint32_t string_index = shared_library_open_index + 1;
+ size_t shared_library_close = std::string::npos;
+ while (counter != 0) {
+ shared_library_close =
+ spec.find_first_of(kClassLoaderSharedLibraryClosingMark, string_index);
+ size_t shared_library_open =
+ spec.find_first_of(kClassLoaderSharedLibraryOpeningMark, string_index);
+ if (shared_library_close == std::string::npos) {
+ // No matching closing marker. Return an error.
+ break;
+ }
+
+ if ((shared_library_open == std::string::npos) ||
+ (shared_library_close < shared_library_open)) {
+ // We have seen a closing marker. Decrement the counter.
+ --counter;
+ // Move the search index forward.
+ string_index = shared_library_close + 1;
+ } else {
+ // New nested opening marker. Increment the counter and move the search
+ // index after the marker.
+ ++counter;
+ string_index = shared_library_open + 1;
+ }
+ }
+ return shared_library_close;
+}
+
// The expected format is:
// "ClassLoaderType1[ClasspathElem1*Checksum1:ClasspathElem2*Checksum2...]{ClassLoaderType2[...]}".
// The checksum part of the format is expected only if parse_cheksums is true.
@@ -160,7 +196,9 @@ std::unique_ptr<ClassLoaderContext::ClassLoaderInfo> ClassLoaderContext::ParseCl
}
}
- if (class_loader_spec[class_loader_spec.length() - 1] == kClassLoaderSharedLibraryClosingMark) {
+ if ((class_loader_spec[class_loader_spec.length() - 1] == kClassLoaderSharedLibraryClosingMark) &&
+ (class_loader_spec[class_loader_spec.length() - 2] != kClassLoaderSharedLibraryOpeningMark)) {
+ // Non-empty list of shared libraries.
size_t start_index = class_loader_spec.find_first_of(kClassLoaderSharedLibraryOpeningMark);
if (start_index == std::string::npos) {
return nullptr;
@@ -168,8 +206,43 @@ std::unique_ptr<ClassLoaderContext::ClassLoaderInfo> ClassLoaderContext::ParseCl
std::string shared_libraries_spec =
class_loader_spec.substr(start_index + 1, class_loader_spec.length() - start_index - 2);
std::vector<std::string> shared_libraries;
- Split(shared_libraries_spec, kClassLoaderSharedLibrarySeparator, &shared_libraries);
- for (const std::string& shared_library_spec : shared_libraries) {
+ size_t cursor = 0;
+ while (cursor != shared_libraries_spec.length()) {
+ size_t shared_library_separator =
+ shared_libraries_spec.find_first_of(kClassLoaderSharedLibrarySeparator, cursor);
+ size_t shared_library_open =
+ shared_libraries_spec.find_first_of(kClassLoaderSharedLibraryOpeningMark, cursor);
+ std::string shared_library_spec;
+ if (shared_library_separator == std::string::npos) {
+ // Only one shared library, for example:
+ // PCL[...]
+ shared_library_spec =
+ shared_libraries_spec.substr(cursor, shared_libraries_spec.length() - cursor);
+ cursor = shared_libraries_spec.length();
+ } else if ((shared_library_open == std::string::npos) ||
+ (shared_library_open > shared_library_separator)) {
+ // We found a shared library without nested shared libraries, for example:
+ // PCL[...]#PCL[...]{...}
+ shared_library_spec =
+ shared_libraries_spec.substr(cursor, shared_library_separator - cursor);
+ cursor = shared_library_separator + 1;
+ } else {
+ // The shared library contains nested shared libraries. Find the matching closing shared
+ // marker for it.
+ size_t closing_marker =
+ FindMatchingSharedLibraryCloseMarker(shared_libraries_spec, shared_library_open);
+ if (closing_marker == std::string::npos) {
+ // No matching closing marker, return an error.
+ return nullptr;
+ }
+ shared_library_spec = shared_libraries_spec.substr(cursor, closing_marker + 1 - cursor);
+ cursor = closing_marker + 1;
+ if (cursor != shared_libraries_spec.length() &&
+ shared_libraries_spec[cursor] == kClassLoaderSharedLibrarySeparator) {
+ // Pass the shared library separator marker.
+ ++cursor;
+ }
+ }
std::unique_ptr<ClassLoaderInfo> shared_library(
ParseInternal(shared_library_spec, parse_checksums));
if (shared_library == nullptr) {
@@ -250,50 +323,24 @@ ClassLoaderContext::ClassLoaderInfo* ClassLoaderContext::ParseInternal(
// The class loader spec contains shared libraries. Find the matching closing
// shared library marker for it.
- // Counter of opened shared library marker we've encountered so far.
- uint32_t counter = 1;
- // The index at which we're operating in the loop.
- uint32_t string_index = first_shared_library_open + 1;
- while (counter != 0) {
- size_t shared_library_close =
- remaining.find_first_of(kClassLoaderSharedLibraryClosingMark, string_index);
- size_t shared_library_open =
- remaining.find_first_of(kClassLoaderSharedLibraryOpeningMark, string_index);
- if (shared_library_close == std::string::npos) {
- // No matching closing market. Return an error.
- LOG(ERROR) << "Invalid class loader spec: " << class_loader_spec;
- return nullptr;
- }
-
- if ((shared_library_open == std::string::npos) ||
- (shared_library_close < shared_library_open)) {
- // We have seen a closing marker. Decrement the counter.
- --counter;
- if (counter == 0) {
- // Found the matching closing marker.
- class_loader_spec = remaining.substr(0, shared_library_close + 1);
-
- // Compute the remaining string to analyze.
- if (remaining.size() == shared_library_close + 1) {
- remaining = "";
- } else if ((remaining.size() == shared_library_close + 2) ||
- (remaining.at(shared_library_close + 1) != kClassLoaderSeparator)) {
- LOG(ERROR) << "Invalid class loader spec: " << class_loader_spec;
- return nullptr;
- } else {
- remaining = remaining.substr(shared_library_close + 2,
- remaining.size() - shared_library_close - 2);
- }
- } else {
- // Move the search index forward.
- string_index = shared_library_close + 1;
- }
- } else {
- // New nested opening marker. Increment the counter and move the search
- // index after the marker.
- ++counter;
- string_index = shared_library_open + 1;
- }
+ uint32_t shared_library_close =
+ FindMatchingSharedLibraryCloseMarker(remaining, first_shared_library_open);
+ if (shared_library_close == std::string::npos) {
+ LOG(ERROR) << "Invalid class loader spec: " << class_loader_spec;
+ return nullptr;
+ }
+ class_loader_spec = remaining.substr(0, shared_library_close + 1);
+
+ // Compute the remaining string to analyze.
+ if (remaining.size() == shared_library_close + 1) {
+ remaining = "";
+ } else if ((remaining.size() == shared_library_close + 2) ||
+ (remaining.at(shared_library_close + 1) != kClassLoaderSeparator)) {
+ LOG(ERROR) << "Invalid class loader spec: " << class_loader_spec;
+ return nullptr;
+ } else {
+ remaining = remaining.substr(shared_library_close + 2,
+ remaining.size() - shared_library_close - 2);
}
}
@@ -571,20 +618,57 @@ static jclass GetClassLoaderClass(ClassLoaderContext::ClassLoaderType type) {
UNREACHABLE();
}
-static jobject CreateClassLoaderInternal(Thread* self,
- const ClassLoaderContext::ClassLoaderInfo& info)
+static ObjPtr<mirror::ClassLoader> CreateClassLoaderInternal(
+ Thread* self,
+ ScopedObjectAccess& soa,
+ const ClassLoaderContext::ClassLoaderInfo& info,
+ bool add_compilation_sources,
+ const std::vector<const DexFile*>& compilation_sources)
REQUIRES_SHARED(Locks::mutator_lock_) {
- CHECK(info.shared_libraries.empty()) << "Class loader shared library not implemented yet";
- jobject parent = nullptr;
+ StackHandleScope<3> hs(self);
+ MutableHandle<mirror::ObjectArray<mirror::ClassLoader>> libraries(
+ hs.NewHandle<mirror::ObjectArray<mirror::ClassLoader>>(nullptr));
+
+ if (!info.shared_libraries.empty()) {
+ libraries.Assign(mirror::ObjectArray<mirror::ClassLoader>::Alloc(
+ self,
+ GetClassRoot<mirror::ObjectArray<mirror::ClassLoader>>(),
+ info.shared_libraries.size()));
+ for (uint32_t i = 0; i < info.shared_libraries.size(); ++i) {
+ // We should only add the compilation sources to the first class loader.
+ libraries->Set(i,
+ CreateClassLoaderInternal(
+ self,
+ soa,
+ *info.shared_libraries[i].get(),
+ /* add_compilation_sources= */ false,
+ compilation_sources));
+ }
+ }
+
+ MutableHandle<mirror::ClassLoader> parent = hs.NewHandle<mirror::ClassLoader>(nullptr);
if (info.parent != nullptr) {
- parent = CreateClassLoaderInternal(self, *info.parent.get());
+ // We should only add the compilation sources to the first class loader.
+ parent.Assign(CreateClassLoaderInternal(
+ self, soa, *info.parent.get(), /* add_compilation_sources= */ false, compilation_sources));
}
std::vector<const DexFile*> class_path_files = MakeNonOwningPointerVector(
info.opened_dex_files);
+ if (add_compilation_sources) {
+ // For the first class loader, its classpath comes first, followed by compilation sources.
+ // This ensures that whenever we need to resolve classes from it the classpath elements
+ // come first.
+ class_path_files.insert(class_path_files.end(),
+ compilation_sources.begin(),
+ compilation_sources.end());
+ }
+ Handle<mirror::Class> loader_class = hs.NewHandle<mirror::Class>(
+ soa.Decode<mirror::Class>(GetClassLoaderClass(info.type)));
return Runtime::Current()->GetClassLinker()->CreateWellKnownClassLoader(
self,
class_path_files,
- GetClassLoaderClass(info.type),
+ loader_class,
+ libraries,
parent);
}
@@ -598,30 +682,21 @@ jobject ClassLoaderContext::CreateClassLoader(
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
if (class_loader_chain_ == nullptr) {
+ CHECK(special_shared_library_);
return class_linker->CreatePathClassLoader(self, compilation_sources);
}
// Create the class loader of the parent.
- jobject parent = nullptr;
- if (class_loader_chain_->parent != nullptr) {
- parent = CreateClassLoaderInternal(self, *class_loader_chain_->parent.get());
- }
-
- // We set up all the parents. Move on to create the first class loader.
- // Its classpath comes first, followed by compilation sources. This ensures that whenever
- // we need to resolve classes from it the classpath elements come first.
-
- std::vector<const DexFile*> first_class_loader_classpath = MakeNonOwningPointerVector(
- class_loader_chain_->opened_dex_files);
- first_class_loader_classpath.insert(first_class_loader_classpath.end(),
- compilation_sources.begin(),
- compilation_sources.end());
-
- return class_linker->CreateWellKnownClassLoader(
- self,
- first_class_loader_classpath,
- GetClassLoaderClass(class_loader_chain_->type),
- parent);
+ ObjPtr<mirror::ClassLoader> loader =
+ CreateClassLoaderInternal(self,
+ soa,
+ *class_loader_chain_.get(),
+ /* add_compilation_sources= */ true,
+ compilation_sources);
+ // Make it a global ref and return.
+ ScopedLocalRef<jobject> local_ref(
+ soa.Env(), soa.Env()->AddLocalReference<jobject>(loader));
+ return soa.Env()->NewGlobalRef(local_ref.get());
}
std::vector<const DexFile*> ClassLoaderContext::FlattenOpenedDexFiles() const {
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index f3e2ac00ba..e4aae47239 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -19,12 +19,14 @@
#include <gtest/gtest.h>
#include "android-base/strings.h"
+#include "art_field-inl.h"
#include "base/dchecked_vector.h"
#include "base/stl_util.h"
#include "class_linker.h"
#include "common_runtime_test.h"
#include "dex/dex_file.h"
#include "handle_scope-inl.h"
+#include "jni/jni_internal.h"
#include "mirror/class.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
@@ -284,6 +286,25 @@ TEST_F(ClassLoaderContextTest, ParseEnclosingSharedLibraries) {
VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 0, "s1.dex");
}
+TEST_F(ClassLoaderContextTest, ParseComplexSharedLibraries1) {
+ std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(
+ "PCL[]{PCL[s4.dex]{PCL[s5.dex]{PCL[s6.dex]}#PCL[s6.dex]}}");
+ VerifyContextSize(context.get(), 1);
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 0, "s4.dex");
+}
+
+TEST_F(ClassLoaderContextTest, ParseComplexSharedLibraries2) {
+ std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(
+ "PCL[]{PCL[s1.dex]{PCL[s2.dex]}#PCL[s2.dex]#"
+ "PCL[s3.dex]#PCL[s4.dex]{PCL[s5.dex]{PCL[s6.dex]}#PCL[s6.dex]}#PCL[s5.dex]{PCL[s6.dex]}}");
+ VerifyContextSize(context.get(), 1);
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 0, "s1.dex");
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 1, "s2.dex");
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 2, "s3.dex");
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 3, "s4.dex");
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 4, "s5.dex");
+}
+
TEST_F(ClassLoaderContextTest, ParseValidEmptyContextDLC) {
std::unique_ptr<ClassLoaderContext> context =
ClassLoaderContext::Create("DLC[]");
@@ -316,6 +337,10 @@ TEST_F(ClassLoaderContextTest, ParseInvalidValidContexts) {
ASSERT_TRUE(nullptr == ClassLoaderContext::Create("DLC[s4.dex]}"));
ASSERT_TRUE(nullptr == ClassLoaderContext::Create("DLC[s4.dex]{"));
ASSERT_TRUE(nullptr == ClassLoaderContext::Create("DLC{DLC[s4.dex]}"));
+ ASSERT_TRUE(nullptr == ClassLoaderContext::Create("PCL{##}"));
+ ASSERT_TRUE(nullptr == ClassLoaderContext::Create("PCL{PCL[s4.dex]#}"));
+ ASSERT_TRUE(nullptr == ClassLoaderContext::Create("PCL{PCL[s4.dex]##}"));
+ ASSERT_TRUE(nullptr == ClassLoaderContext::Create("PCL{PCL[s4.dex]{PCL[s3.dex]}#}"));
}
TEST_F(ClassLoaderContextTest, OpenInvalidDexFiles) {
@@ -605,6 +630,292 @@ TEST_F(ClassLoaderContextTest, CreateClassLoaderWithComplexChain) {
soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
}
+TEST_F(ClassLoaderContextTest, CreateClassLoaderWithSharedLibraries) {
+ // Setup the context.
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_a = OpenTestDexFiles("ForClassLoaderA");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_b = OpenTestDexFiles("ForClassLoaderB");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_c = OpenTestDexFiles("ForClassLoaderC");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_d = OpenTestDexFiles("ForClassLoaderD");
+
+ std::string context_spec =
+ "PCL[" + CreateClassPath(classpath_dex_a) + ":" + CreateClassPath(classpath_dex_b) + "]{" +
+ "DLC[" + CreateClassPath(classpath_dex_c) + "]#" +
+ "PCL[" + CreateClassPath(classpath_dex_d) + "]}";
+
+ std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_spec);
+ ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, ""));
+
+ // Setup the compilation sources.
+ std::vector<std::unique_ptr<const DexFile>> compilation_sources = OpenTestDexFiles("MultiDex");
+ std::vector<const DexFile*> compilation_sources_raw =
+ MakeNonOwningPointerVector(compilation_sources);
+
+ // Create the class loader.
+ jobject jclass_loader = context->CreateClassLoader(compilation_sources_raw);
+ ASSERT_TRUE(jclass_loader != nullptr);
+
+ // Verify the class loader.
+ ScopedObjectAccess soa(Thread::Current());
+
+ StackHandleScope<4> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader_1 = hs.NewHandle(
+ soa.Decode<mirror::ClassLoader>(jclass_loader));
+
+ // For the first class loader the class path dex files must come first and then the
+ // compilation sources.
+ std::vector<const DexFile*> class_loader_1_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_a);
+ for (auto& dex : classpath_dex_b) {
+ class_loader_1_dex_files.push_back(dex.get());
+ }
+ for (auto& dex : compilation_sources_raw) {
+ class_loader_1_dex_files.push_back(dex);
+ }
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_1,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_1_dex_files);
+
+ // Verify the shared libraries.
+ ArtField* field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader_1.Get());
+ ASSERT_TRUE(raw_shared_libraries != nullptr);
+
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries(
+ hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>()));
+ ASSERT_EQ(shared_libraries->GetLength(), 2);
+
+ // Verify the first shared library.
+ Handle<mirror::ClassLoader> class_loader_2 = hs.NewHandle(shared_libraries->Get(0));
+ std::vector<const DexFile*> class_loader_2_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_c);
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_2,
+ WellKnownClasses::dalvik_system_DelegateLastClassLoader,
+ class_loader_2_dex_files);
+ raw_shared_libraries = field->GetObject(class_loader_2.Get());
+ ASSERT_TRUE(raw_shared_libraries == nullptr);
+
+ // Verify the second shared library.
+ Handle<mirror::ClassLoader> class_loader_3 = hs.NewHandle(shared_libraries->Get(1));
+ std::vector<const DexFile*> class_loader_3_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_d);
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_3,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_3_dex_files);
+ raw_shared_libraries = field->GetObject(class_loader_3.Get());
+ ASSERT_TRUE(raw_shared_libraries == nullptr);
+
+ // All class loaders should have the BootClassLoader as a parent.
+ ASSERT_TRUE(class_loader_1->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+ ASSERT_TRUE(class_loader_2->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+ ASSERT_TRUE(class_loader_3->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+}
+
+TEST_F(ClassLoaderContextTest, CreateClassLoaderWithSharedLibrariesInParentToo) {
+ // Setup the context.
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_a = OpenTestDexFiles("ForClassLoaderA");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_b = OpenTestDexFiles("ForClassLoaderB");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_c = OpenTestDexFiles("ForClassLoaderC");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_d = OpenTestDexFiles("ForClassLoaderD");
+
+ std::string context_spec =
+ "PCL[" + CreateClassPath(classpath_dex_a) + "]{" +
+ "PCL[" + CreateClassPath(classpath_dex_b) + "]};" +
+ "PCL[" + CreateClassPath(classpath_dex_c) + "]{" +
+ "PCL[" + CreateClassPath(classpath_dex_d) + "]}";
+
+ std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_spec);
+ ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, ""));
+
+ // Setup the compilation sources.
+ std::vector<std::unique_ptr<const DexFile>> compilation_sources = OpenTestDexFiles("MultiDex");
+ std::vector<const DexFile*> compilation_sources_raw =
+ MakeNonOwningPointerVector(compilation_sources);
+
+ // Create the class loader.
+ jobject jclass_loader = context->CreateClassLoader(compilation_sources_raw);
+ ASSERT_TRUE(jclass_loader != nullptr);
+
+ // Verify the class loader.
+ ScopedObjectAccess soa(Thread::Current());
+
+ StackHandleScope<6> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader_1 = hs.NewHandle(
+ soa.Decode<mirror::ClassLoader>(jclass_loader));
+
+ // For the first class loader the class path dex files must come first and then the
+ // compilation sources.
+ std::vector<const DexFile*> class_loader_1_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_a);
+ for (auto& dex : compilation_sources_raw) {
+ class_loader_1_dex_files.push_back(dex);
+ }
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_1,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_1_dex_files);
+
+ // Verify its shared library.
+ ArtField* field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader_1.Get());
+ ASSERT_TRUE(raw_shared_libraries != nullptr);
+
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries(
+ hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>()));
+ ASSERT_EQ(shared_libraries->GetLength(), 1);
+
+ Handle<mirror::ClassLoader> class_loader_2 = hs.NewHandle(shared_libraries->Get(0));
+ std::vector<const DexFile*> class_loader_2_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_b);
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_2,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_2_dex_files);
+ raw_shared_libraries = field->GetObject(class_loader_2.Get());
+ ASSERT_TRUE(raw_shared_libraries == nullptr);
+
+ // Verify the parent.
+ Handle<mirror::ClassLoader> class_loader_3 = hs.NewHandle(class_loader_1->GetParent());
+ std::vector<const DexFile*> class_loader_3_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_c);
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_3,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_3_dex_files);
+
+ // Verify its shared library.
+ raw_shared_libraries = field->GetObject(class_loader_3.Get());
+ ASSERT_TRUE(raw_shared_libraries != nullptr);
+
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries_2(
+ hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>()));
+ ASSERT_EQ(shared_libraries->GetLength(), 1);
+
+ Handle<mirror::ClassLoader> class_loader_4 = hs.NewHandle(shared_libraries_2->Get(0));
+ std::vector<const DexFile*> class_loader_4_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_d);
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_4,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_4_dex_files);
+ raw_shared_libraries = field->GetObject(class_loader_4.Get());
+ ASSERT_TRUE(raw_shared_libraries == nullptr);
+
+ // Class loaders should have the BootClassLoader as a parent.
+ ASSERT_TRUE(class_loader_2->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+ ASSERT_TRUE(class_loader_3->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+ ASSERT_TRUE(class_loader_4->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+}
+
+TEST_F(ClassLoaderContextTest, CreateClassLoaderWithSharedLibrariesDependencies) {
+ // Setup the context.
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_a = OpenTestDexFiles("ForClassLoaderA");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_b = OpenTestDexFiles("ForClassLoaderB");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_c = OpenTestDexFiles("ForClassLoaderC");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_d = OpenTestDexFiles("ForClassLoaderD");
+
+ std::string context_spec =
+ "PCL[" + CreateClassPath(classpath_dex_a) + "]{" +
+ "PCL[" + CreateClassPath(classpath_dex_b) + "]{" +
+ "PCL[" + CreateClassPath(classpath_dex_c) + "]}};" +
+ "PCL[" + CreateClassPath(classpath_dex_d) + "]";
+
+ std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_spec);
+ ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, ""));
+
+ // Setup the compilation sources.
+ std::vector<std::unique_ptr<const DexFile>> compilation_sources = OpenTestDexFiles("MultiDex");
+ std::vector<const DexFile*> compilation_sources_raw =
+ MakeNonOwningPointerVector(compilation_sources);
+
+ // Create the class loader.
+ jobject jclass_loader = context->CreateClassLoader(compilation_sources_raw);
+ ASSERT_TRUE(jclass_loader != nullptr);
+
+ // Verify the class loader.
+ ScopedObjectAccess soa(Thread::Current());
+
+ StackHandleScope<6> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader_1 = hs.NewHandle(
+ soa.Decode<mirror::ClassLoader>(jclass_loader));
+
+ // For the first class loader the class path dex files must come first and then the
+ // compilation sources.
+ std::vector<const DexFile*> class_loader_1_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_a);
+ for (auto& dex : compilation_sources_raw) {
+ class_loader_1_dex_files.push_back(dex);
+ }
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_1,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_1_dex_files);
+
+ // Verify its shared library.
+ ArtField* field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader_1.Get());
+ ASSERT_TRUE(raw_shared_libraries != nullptr);
+
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries(
+ hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>()));
+ ASSERT_EQ(shared_libraries->GetLength(), 1);
+
+ Handle<mirror::ClassLoader> class_loader_2 = hs.NewHandle(shared_libraries->Get(0));
+ std::vector<const DexFile*> class_loader_2_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_b);
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_2,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_2_dex_files);
+
+ // Verify the shared library dependency of the shared library.
+ raw_shared_libraries = field->GetObject(class_loader_2.Get());
+ ASSERT_TRUE(raw_shared_libraries != nullptr);
+
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries_2(
+ hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>()));
+ ASSERT_EQ(shared_libraries_2->GetLength(), 1);
+
+ Handle<mirror::ClassLoader> class_loader_3 = hs.NewHandle(shared_libraries_2->Get(0));
+ std::vector<const DexFile*> class_loader_3_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_c);
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_3,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_3_dex_files);
+ raw_shared_libraries = field->GetObject(class_loader_3.Get());
+ ASSERT_TRUE(raw_shared_libraries == nullptr);
+
+ // Verify the parent.
+ Handle<mirror::ClassLoader> class_loader_4 = hs.NewHandle(class_loader_1->GetParent());
+ std::vector<const DexFile*> class_loader_4_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_d);
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_4,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_4_dex_files);
+ raw_shared_libraries = field->GetObject(class_loader_4.Get());
+ ASSERT_TRUE(raw_shared_libraries == nullptr);
+
+ // Class loaders should have the BootClassLoader as a parent.
+ ASSERT_TRUE(class_loader_2->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+ ASSERT_TRUE(class_loader_3->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+ ASSERT_TRUE(class_loader_4->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+}
TEST_F(ClassLoaderContextTest, RemoveSourceLocations) {
std::unique_ptr<ClassLoaderContext> context =
diff --git a/runtime/class_root.h b/runtime/class_root.h
index 1cd135f2aa..1ff48457d6 100644
--- a/runtime/class_root.h
+++ b/runtime/class_root.h
@@ -101,6 +101,7 @@ class VarHandle;
M(kLongArrayClass, "[J", mirror::PrimitiveArray<int64_t>) \
M(kShortArrayClass, "[S", mirror::PrimitiveArray<int16_t>) \
M(kJavaLangStackTraceElementArrayClass, "[Ljava/lang/StackTraceElement;", mirror::ObjectArray<mirror::StackTraceElement>) \
+ M(kJavaLangClassLoaderArrayClass, "[Ljava/lang/ClassLoader;", mirror::ObjectArray<mirror::ClassLoader>) \
M(kDalvikSystemClassExt, "Ldalvik/system/ClassExt;", mirror::ClassExt)
// Well known mirror::Class roots accessed via ClassLinker::GetClassRoots().
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index 15398672b2..6434828298 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -22,6 +22,7 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
+#include "base/sdk_version.h"
#include "class_linker-inl.h"
#include "class_root.h"
#include "dex/dex_file-inl.h"
@@ -129,8 +130,7 @@ ObjPtr<mirror::Object> CreateAnnotationMember(const ClassData& klass,
bool IsVisibilityCompatible(uint32_t actual, uint32_t expected) {
if (expected == DexFile::kDexVisibilityRuntime) {
- int32_t sdk_version = Runtime::Current()->GetTargetSdkVersion();
- if (sdk_version > 0 && sdk_version <= 23) {
+ if (IsSdkVersionSetAndAtMost(Runtime::Current()->GetTargetSdkVersion(), SdkVersion::kM)) {
return actual == DexFile::kDexVisibilityRuntime || actual == DexFile::kDexVisibilityBuild;
}
}
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 0b005e0851..2236e61d75 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -22,6 +22,7 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/enums.h"
+#include "base/sdk_version.h"
#include "class_linker-inl.h"
#include "common_throws.h"
#include "dex/dex_file.h"
@@ -94,8 +95,9 @@ inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method,
// even going back from boot image methods to the same oat file. However, this is
// not currently implemented in the compiler. Therefore crossing dex file boundary
// indicates that the inlined definition is not the same as the one used at runtime.
- bool target_sdk_pre_p = Runtime::Current()->GetTargetSdkVersion() < 28;
- LOG(target_sdk_pre_p ? WARNING : FATAL)
+ bool target_sdk_at_least_p =
+ IsSdkVersionSetAndAtLeast(Runtime::Current()->GetTargetSdkVersion(), SdkVersion::kP);
+ LOG(target_sdk_at_least_p ? FATAL : WARNING)
<< "Inlined method resolution crossed dex file boundary: from "
<< method->PrettyMethod()
<< " in " << method->GetDexFile()->GetLocation() << "/"
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 12136bf476..19498f386c 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -20,6 +20,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "base/mutex.h"
+#include "base/sdk_version.h"
#include "class_linker-inl.h"
#include "dex/dex_file-inl.h"
#include "entrypoints/entrypoint_utils-inl.h"
@@ -64,9 +65,9 @@ JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, cons
soa.Self()->AssertThreadSuspensionIsAllowable();
jobjectArray args_jobj = nullptr;
const JValue zero;
- int32_t target_sdk_version = Runtime::Current()->GetTargetSdkVersion();
+ uint32_t target_sdk_version = Runtime::Current()->GetTargetSdkVersion();
// Do not create empty arrays unless needed to maintain Dalvik bug compatibility.
- if (args.size() > 0 || (target_sdk_version > 0 && target_sdk_version <= 21)) {
+ if (args.size() > 0 || IsSdkVersionSetAndAtMost(target_sdk_version, SdkVersion::kL)) {
args_jobj = soa.Env()->NewObjectArray(args.size(), WellKnownClasses::java_lang_Object, nullptr);
if (args_jobj == nullptr) {
CHECK(soa.Self()->IsExceptionPending());
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 5e3692ea9a..0294db7b7e 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -77,8 +77,9 @@ void GarbageCollector::RegisterPause(uint64_t nano_length) {
void GarbageCollector::ResetCumulativeStatistics() {
cumulative_timings_.Reset();
- total_time_ns_ = 0;
- total_freed_objects_ = 0;
+ total_thread_cpu_time_ns_ = 0u;
+ total_time_ns_ = 0u;
+ total_freed_objects_ = 0u;
total_freed_bytes_ = 0;
MutexLock mu(Thread::Current(), pause_histogram_lock_);
pause_histogram_.Reset();
@@ -88,6 +89,7 @@ void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) {
ScopedTrace trace(android::base::StringPrintf("%s %s GC", PrettyCause(gc_cause), GetName()));
Thread* self = Thread::Current();
uint64_t start_time = NanoTime();
+ uint64_t thread_cpu_start_time = ThreadCpuNanoTime();
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
@@ -102,6 +104,8 @@ void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) {
total_freed_bytes_ += current_iteration->GetFreedBytes() +
current_iteration->GetFreedLargeObjectBytes();
uint64_t end_time = NanoTime();
+ uint64_t thread_cpu_end_time = ThreadCpuNanoTime();
+ total_thread_cpu_time_ns_ += thread_cpu_end_time - thread_cpu_start_time;
current_iteration->SetDurationNs(end_time - start_time);
if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
// The entire GC was paused, clear the fake pauses which might be in the pause times and add
@@ -159,8 +163,9 @@ void GarbageCollector::ResetMeasurements() {
pause_histogram_.Reset();
}
cumulative_timings_.Reset();
- total_time_ns_ = 0;
- total_freed_objects_ = 0;
+ total_thread_cpu_time_ns_ = 0u;
+ total_time_ns_ = 0u;
+ total_freed_objects_ = 0u;
total_freed_bytes_ = 0;
}
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index f722e8d855..2857881456 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -81,6 +81,9 @@ class GarbageCollector : public RootVisitor, public IsMarkedVisitor, public Mark
void SwapBitmaps()
REQUIRES(Locks::heap_bitmap_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
+ uint64_t GetTotalCpuTime() const {
+ return total_thread_cpu_time_ns_;
+ }
uint64_t GetTotalPausedTimeNs() REQUIRES(!pause_histogram_lock_);
int64_t GetTotalFreedBytes() const {
return total_freed_bytes_;
@@ -146,6 +149,7 @@ class GarbageCollector : public RootVisitor, public IsMarkedVisitor, public Mark
std::string name_;
// Cumulative statistics.
Histogram<uint64_t> pause_histogram_ GUARDED_BY(pause_histogram_lock_);
+ uint64_t total_thread_cpu_time_ns_;
uint64_t total_time_ns_;
uint64_t total_freed_objects_;
int64_t total_freed_bytes_;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index f0f81fc67e..e7f14c39d4 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1062,6 +1062,14 @@ void Heap::RemoveSpace(space::Space* space) {
}
}
+uint64_t Heap::GetTotalGcCpuTime() {
+ uint64_t sum = 0;
+ for (auto& collector : garbage_collectors_) {
+ sum += collector->GetTotalCpuTime();
+ }
+ return sum;
+}
+
void Heap::DumpGcPerformanceInfo(std::ostream& os) {
// Dump cumulative timings.
os << "Dumping cumulative Gc timings\n";
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index c3ee5267b5..a43f3156f5 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -395,6 +395,8 @@ class Heap {
REQUIRES(!Locks::heap_bitmap_lock_)
REQUIRES(Locks::mutator_lock_);
+ uint64_t GetTotalGcCpuTime();
+
// Set target ideal heap utilization ratio, implements
// dalvik.system.VMRuntime.setTargetHeapUtilization.
void SetTargetHeapUtilization(float target);
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index 3b7b938d50..188c5f353b 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -18,8 +18,13 @@
#include <nativehelper/scoped_local_ref.h>
+#include "art_field-inl.h"
+#include "art_method-inl.h"
#include "base/dumpable.h"
-#include "thread-current-inl.h"
+#include "base/sdk_version.h"
+#include "dex/class_accessor-inl.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
#include "well_known_classes.h"
#ifdef ART_TARGET_ANDROID
@@ -71,24 +76,19 @@ enum AccessContextFlags {
kAccessDenied = 1 << 1,
};
-static int32_t GetMaxAllowedSdkVersionForApiList(ApiList api_list) {
- SdkCodes sdk = SdkCodes::kVersionNone;
+static SdkVersion GetMaxAllowedSdkVersionForApiList(ApiList api_list) {
switch (api_list) {
case ApiList::kWhitelist:
case ApiList::kLightGreylist:
- sdk = SdkCodes::kVersionUnlimited;
- break;
+ return SdkVersion::kMax;
case ApiList::kDarkGreylist:
- sdk = SdkCodes::kVersionO_MR1;
- break;
+ return SdkVersion::kO_MR1;
case ApiList::kBlacklist:
- sdk = SdkCodes::kVersionNone;
- break;
+ return SdkVersion::kMin;
case ApiList::kNoList:
LOG(FATAL) << "Unexpected value";
UNREACHABLE();
}
- return static_cast<int32_t>(sdk);
}
MemberSignature::MemberSignature(ArtField* field) {
@@ -235,23 +235,82 @@ void MemberSignature::NotifyHiddenApiListener(AccessMethod access_method) {
}
}
-static ALWAYS_INLINE bool CanUpdateMemberAccessFlags(ArtField*) {
+static ALWAYS_INLINE bool CanUpdateRuntimeFlags(ArtField*) {
return true;
}
-static ALWAYS_INLINE bool CanUpdateMemberAccessFlags(ArtMethod* method) {
+static ALWAYS_INLINE bool CanUpdateRuntimeFlags(ArtMethod* method) {
return !method->IsIntrinsic();
}
template<typename T>
static ALWAYS_INLINE void MaybeWhitelistMember(Runtime* runtime, T* member)
REQUIRES_SHARED(Locks::mutator_lock_) {
- if (CanUpdateMemberAccessFlags(member) && runtime->ShouldDedupeHiddenApiWarnings()) {
- member->SetAccessFlags(hiddenapi::EncodeForRuntime(
- member->GetAccessFlags(), hiddenapi::ApiList::kWhitelist));
+ if (CanUpdateRuntimeFlags(member) && runtime->ShouldDedupeHiddenApiWarnings()) {
+ member->SetAccessFlags(member->GetAccessFlags() | kAccPublicApi);
}
}
+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;
+ }
+
+ uint32_t flags = kInvalidDexFlags;
+ DCHECK(!AreValidFlags(flags));
+
+ 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();
+ }
+ };
+ accessor.VisitFields(fn_visit, fn_visit);
+
+ CHECK_NE(flags, kInvalidDexFlags) << "Could not find flags for field " << field->PrettyField();
+ DCHECK(AreValidFlags(flags));
+ return flags;
+}
+
+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;
+ }
+
+ const DexFile::ClassDef* class_def = declaring_class->GetClassDef();
+ if (class_def == nullptr) {
+ return kNoDexFlags;
+ }
+
+ uint32_t flags = kInvalidDexFlags;
+ DCHECK(!AreValidFlags(flags));
+
+ 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->GetDexMethodIndex()) {
+ flags = dex_method.GetHiddenapiFlags();
+ }
+ };
+ accessor.VisitMethods(fn_visit, fn_visit);
+
+ CHECK_NE(flags, kInvalidDexFlags) << "Could not find flags for method " << method->PrettyMethod();
+ DCHECK(AreValidFlags(flags));
+ return flags;
+}
+
template<typename T>
bool ShouldDenyAccessToMemberImpl(T* member,
hiddenapi::ApiList api_list,
@@ -263,7 +322,8 @@ bool ShouldDenyAccessToMemberImpl(T* member,
const bool deny_access =
(policy == EnforcementPolicy::kEnabled) &&
- (runtime->GetTargetSdkVersion() > GetMaxAllowedSdkVersionForApiList(api_list));
+ IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(),
+ GetMaxAllowedSdkVersionForApiList(api_list));
MemberSignature member_signature(member);
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index ed00e2a892..32bae1127b 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -17,10 +17,11 @@
#ifndef ART_RUNTIME_HIDDEN_API_H_
#define ART_RUNTIME_HIDDEN_API_H_
-#include "art_field-inl.h"
-#include "art_method-inl.h"
+#include "art_field.h"
+#include "art_method.h"
#include "base/mutex.h"
#include "dex/hidden_api_access_flags.h"
+#include "intrinsics_enum.h"
#include "mirror/class-inl.h"
#include "reflection.h"
#include "runtime.h"
@@ -116,13 +117,6 @@ class ScopedHiddenApiEnforcementPolicySetting {
// Implementation details. DO NOT ACCESS DIRECTLY.
namespace detail {
-enum class SdkCodes {
- kVersionNone = std::numeric_limits<int32_t>::min(),
- kVersionUnlimited = std::numeric_limits<int32_t>::max(),
- kVersionO_MR1 = 27,
- kVersionP = 28,
-};
-
// Class to encapsulate the signature of a member (ArtField or ArtMethod). This
// is used as a helper when matching prefixes, and when logging the signature.
class MemberSignature {
@@ -164,12 +158,136 @@ class MemberSignature {
void NotifyHiddenApiListener(AccessMethod access_method);
};
+// 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>
bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_);
} // namespace detail
+// Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
+ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(const ClassAccessor::BaseItem& member) {
+ uint32_t runtime_flags = 0u;
+
+ uint32_t dex_flags = member.GetHiddenapiFlags();
+ DCHECK(AreValidFlags(dex_flags));
+
+ ApiList api_list = static_cast<hiddenapi::ApiList>(dex_flags);
+ if (api_list == ApiList::kWhitelist) {
+ runtime_flags |= kAccPublicApi;
+ }
+
+ DCHECK_EQ(runtime_flags & kAccHiddenapiBits, runtime_flags)
+ << "Runtime flags not in reserved access flags bits";
+ return runtime_flags;
+}
+
+// Extracts hiddenapi runtime flags from access flags of ArtField.
+ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtField* field)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return field->GetAccessFlags() & kAccHiddenapiBits;
+}
+
+// Extracts hiddenapi runtime flags from access flags of ArtMethod.
+// Uses hardcoded values for intrinsics.
+ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (UNLIKELY(method->IsIntrinsic())) {
+ switch (static_cast<Intrinsics>(method->GetIntrinsic())) {
+ case Intrinsics::kSystemArrayCopyChar:
+ case Intrinsics::kStringGetCharsNoCheck:
+ case Intrinsics::kReferenceGetReferent:
+ case Intrinsics::kMemoryPeekByte:
+ case Intrinsics::kMemoryPokeByte:
+ case Intrinsics::kUnsafeCASInt:
+ case Intrinsics::kUnsafeCASLong:
+ case Intrinsics::kUnsafeCASObject:
+ case Intrinsics::kUnsafeGet:
+ case Intrinsics::kUnsafeGetAndAddInt:
+ case Intrinsics::kUnsafeGetAndAddLong:
+ case Intrinsics::kUnsafeGetAndSetInt:
+ case Intrinsics::kUnsafeGetAndSetLong:
+ case Intrinsics::kUnsafeGetAndSetObject:
+ case Intrinsics::kUnsafeGetLong:
+ case Intrinsics::kUnsafeGetLongVolatile:
+ case Intrinsics::kUnsafeGetObject:
+ case Intrinsics::kUnsafeGetObjectVolatile:
+ case Intrinsics::kUnsafeGetVolatile:
+ case Intrinsics::kUnsafePut:
+ case Intrinsics::kUnsafePutLong:
+ case Intrinsics::kUnsafePutLongOrdered:
+ case Intrinsics::kUnsafePutLongVolatile:
+ case Intrinsics::kUnsafePutObject:
+ case Intrinsics::kUnsafePutObjectOrdered:
+ case Intrinsics::kUnsafePutObjectVolatile:
+ case Intrinsics::kUnsafePutOrdered:
+ case Intrinsics::kUnsafePutVolatile:
+ case Intrinsics::kUnsafeLoadFence:
+ case Intrinsics::kUnsafeStoreFence:
+ case Intrinsics::kUnsafeFullFence:
+ case Intrinsics::kCRC32Update:
+ case Intrinsics::kStringNewStringFromBytes:
+ case Intrinsics::kStringNewStringFromChars:
+ case Intrinsics::kStringNewStringFromString:
+ case Intrinsics::kMemoryPeekIntNative:
+ case Intrinsics::kMemoryPeekLongNative:
+ case Intrinsics::kMemoryPeekShortNative:
+ case Intrinsics::kMemoryPokeIntNative:
+ case Intrinsics::kMemoryPokeLongNative:
+ case Intrinsics::kMemoryPokeShortNative:
+ case Intrinsics::kVarHandleFullFence:
+ case Intrinsics::kVarHandleAcquireFence:
+ case Intrinsics::kVarHandleReleaseFence:
+ case Intrinsics::kVarHandleLoadLoadFence:
+ case Intrinsics::kVarHandleStoreStoreFence:
+ case Intrinsics::kVarHandleCompareAndExchange:
+ case Intrinsics::kVarHandleCompareAndExchangeAcquire:
+ case Intrinsics::kVarHandleCompareAndExchangeRelease:
+ case Intrinsics::kVarHandleCompareAndSet:
+ case Intrinsics::kVarHandleGet:
+ case Intrinsics::kVarHandleGetAcquire:
+ case Intrinsics::kVarHandleGetAndAdd:
+ case Intrinsics::kVarHandleGetAndAddAcquire:
+ case Intrinsics::kVarHandleGetAndAddRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseAnd:
+ case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseOr:
+ case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseXor:
+ case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
+ case Intrinsics::kVarHandleGetAndSet:
+ case Intrinsics::kVarHandleGetAndSetAcquire:
+ case Intrinsics::kVarHandleGetAndSetRelease:
+ case Intrinsics::kVarHandleGetOpaque:
+ case Intrinsics::kVarHandleGetVolatile:
+ case Intrinsics::kVarHandleSet:
+ case Intrinsics::kVarHandleSetOpaque:
+ case Intrinsics::kVarHandleSetRelease:
+ case Intrinsics::kVarHandleSetVolatile:
+ case Intrinsics::kVarHandleWeakCompareAndSet:
+ case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
+ case Intrinsics::kVarHandleWeakCompareAndSetPlain:
+ case Intrinsics::kVarHandleWeakCompareAndSetRelease:
+ return 0u;
+ default:
+ // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
+ return kAccPublicApi;
+ }
+ } else {
+ return method->GetAccessFlags() & kAccHiddenapiBits;
+ }
+}
+
// Returns true if access to `member` should be denied in the given context.
// The decision is based on whether the caller is in a trusted context or not.
// Because determining the access context can be expensive, a lambda function
@@ -183,16 +301,9 @@ inline bool ShouldDenyAccessToMember(T* member,
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(member != nullptr);
- // Decode hidden API access flags.
- // NB Multiple threads might try to access (and overwrite) these simultaneously,
- // causing a race. We only do that if access has not been denied, so the race
- // cannot change Java semantics. We should, however, decode the access flags
- // once and use it throughout this function, otherwise we may get inconsistent
- // results, e.g. print whitelist warnings (b/78327881).
- ApiList api_list = member->GetHiddenApiAccessFlags();
-
- // Exit early if member is on the whitelist.
- if (api_list == ApiList::kWhitelist) {
+ // Exit early if member is public API. This flag is also set for non-boot class
+ // path fields/methods.
+ if ((GetRuntimeFlags(member) & kAccPublicApi) != 0) {
return false;
}
@@ -202,6 +313,11 @@ inline bool ShouldDenyAccessToMember(T* member,
return false;
}
+ // Decode hidden API access flags from the dex file.
+ // This is an O(N) operation scaling with the number of fields/methods
+ // in the class. Only do this on slow path and only do it once.
+ ApiList api_list = static_cast<hiddenapi::ApiList>(detail::GetDexFlags(member));
+
// Member is hidden and caller is not exempted. Enter slow path.
return detail::ShouldDenyAccessToMemberImpl(member, api_list, access_method);
}
diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc
index 627d9a7e1c..314d878c66 100644
--- a/runtime/hidden_api_test.cc
+++ b/runtime/hidden_api_test.cc
@@ -16,6 +16,7 @@
#include "hidden_api.h"
+#include "base/sdk_version.h"
#include "common_runtime_test.h"
#include "jni/jni_internal.h"
#include "proxy_test.h"
@@ -112,14 +113,14 @@ TEST_F(HiddenApiTest, CheckGetActionFromRuntimeFlags) {
ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kBlacklist), false);
runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
- runtime_->SetTargetSdkVersion(static_cast<int32_t>(hiddenapi::detail::SdkCodes::kVersionO_MR1));
+ runtime_->SetTargetSdkVersion(static_cast<uint32_t>(SdkVersion::kO_MR1));
ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kWhitelist), false);
ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kLightGreylist), false);
ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kDarkGreylist), false);
ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kBlacklist), true);
runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
- runtime_->SetTargetSdkVersion(static_cast<int32_t>(hiddenapi::detail::SdkCodes::kVersionP));
+ runtime_->SetTargetSdkVersion(static_cast<uint32_t>(SdkVersion::kP));
ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kWhitelist), false);
ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kLightGreylist), false);
ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kDarkGreylist), true);
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 359f97e705..1701ca8a78 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -1274,10 +1274,10 @@ size_t JitCodeCache::ReserveData(Thread* self,
class MarkCodeVisitor final : public StackVisitor {
public:
- MarkCodeVisitor(Thread* thread_in, JitCodeCache* code_cache_in)
+ MarkCodeVisitor(Thread* thread_in, JitCodeCache* code_cache_in, CodeCacheBitmap* bitmap)
: StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kSkipInlinedFrames),
code_cache_(code_cache_in),
- bitmap_(code_cache_->GetLiveBitmap()) {}
+ bitmap_(bitmap) {}
bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
@@ -1299,13 +1299,13 @@ class MarkCodeVisitor final : public StackVisitor {
class MarkCodeClosure final : public Closure {
public:
- MarkCodeClosure(JitCodeCache* code_cache, Barrier* barrier)
- : code_cache_(code_cache), barrier_(barrier) {}
+ MarkCodeClosure(JitCodeCache* code_cache, CodeCacheBitmap* bitmap, Barrier* barrier)
+ : code_cache_(code_cache), bitmap_(bitmap), barrier_(barrier) {}
void Run(Thread* thread) override REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedTrace trace(__PRETTY_FUNCTION__);
DCHECK(thread == Thread::Current() || thread->IsSuspended());
- MarkCodeVisitor visitor(thread, code_cache_);
+ MarkCodeVisitor visitor(thread, code_cache_, bitmap_);
visitor.WalkStack();
if (kIsDebugBuild) {
// The stack walking code queries the side instrumentation stack if it
@@ -1320,7 +1320,7 @@ class MarkCodeClosure final : public Closure {
code_cache_->LookupMethodHeader(frame.return_pc_, /* method= */ nullptr);
if (method_header != nullptr) {
const void* code = method_header->GetCode();
- CHECK(code_cache_->GetLiveBitmap()->Test(FromCodeToAllocation(code)));
+ CHECK(bitmap_->Test(FromCodeToAllocation(code)));
}
}
}
@@ -1329,6 +1329,7 @@ class MarkCodeClosure final : public Closure {
private:
JitCodeCache* const code_cache_;
+ CodeCacheBitmap* const bitmap_;
Barrier* const barrier_;
};
@@ -1374,7 +1375,7 @@ bool JitCodeCache::IncreaseCodeCacheCapacity() {
void JitCodeCache::MarkCompiledCodeOnThreadStacks(Thread* self) {
Barrier barrier(0);
size_t threads_running_checkpoint = 0;
- MarkCodeClosure closure(this, &barrier);
+ MarkCodeClosure closure(this, GetLiveBitmap(), &barrier);
threads_running_checkpoint = Runtime::Current()->GetThreadList()->RunCheckpoint(&closure);
// Now that we have run our checkpoint, move to a suspended state and wait
// for other threads to run the checkpoint.
@@ -1987,11 +1988,6 @@ void JitCodeCache::DoneCompiling(ArtMethod* method, Thread* self, bool osr) {
}
}
-size_t JitCodeCache::GetMemorySizeOfCodePointer(const void* ptr) {
- MutexLock mu(Thread::Current(), lock_);
- return mspace_usable_size(reinterpret_cast<const void*>(FromCodeToAllocation(ptr)));
-}
-
void JitCodeCache::InvalidateCompiledCodeFor(ArtMethod* method,
const OatQuickMethodHeader* header) {
DCHECK(!method->IsNative());
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 126fd441db..a5075638f2 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -71,7 +71,6 @@ template<class T> class ObjectArray;
namespace jit {
-class JitInstrumentationCache;
class ScopedCodeCacheWrite;
// Alignment in bits that will suit all architectures.
@@ -97,12 +96,6 @@ class JitCodeCache {
std::string* error_msg);
~JitCodeCache();
- // Number of bytes allocated in the code cache.
- size_t CodeCacheSize() REQUIRES(!lock_);
-
- // Number of bytes allocated in the data cache.
- size_t DataCacheSize() REQUIRES(!lock_);
-
bool NotifyCompilationOf(ArtMethod* method, Thread* self, bool osr)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!lock_);
@@ -177,10 +170,6 @@ class JitCodeCache {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!lock_);
- CodeCacheBitmap* GetLiveBitmap() const {
- return live_bitmap_.get();
- }
-
// Perform a collection on the code cache.
void GarbageCollectCache(Thread* self)
REQUIRES(!lock_)
@@ -234,10 +223,6 @@ class JitCodeCache {
REQUIRES(!lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- uint64_t GetLastUpdateTimeNs() const;
-
- size_t GetMemorySizeOfCodePointer(const void* ptr) REQUIRES(!lock_);
-
void InvalidateCompiledCodeFor(ArtMethod* method, const OatQuickMethodHeader* code)
REQUIRES(!lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -339,6 +324,12 @@ class JitCodeCache {
void FreeCodeAndData(const void* code_ptr) REQUIRES(lock_);
// Number of bytes allocated in the code cache.
+ size_t CodeCacheSize() REQUIRES(!lock_);
+
+ // Number of bytes allocated in the data cache.
+ size_t DataCacheSize() REQUIRES(!lock_);
+
+ // Number of bytes allocated in the code cache.
size_t CodeCacheSizeLocked() REQUIRES(lock_);
// Number of bytes allocated in the data cache.
@@ -375,6 +366,10 @@ class JitCodeCache {
REQUIRES(lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
+ CodeCacheBitmap* GetLiveBitmap() const {
+ return live_bitmap_.get();
+ }
+
uint8_t* AllocateCode(size_t code_size) REQUIRES(lock_);
void FreeCode(uint8_t* code) REQUIRES(lock_);
uint8_t* AllocateData(size_t data_size) REQUIRES(lock_);
diff --git a/runtime/jni/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc
index 6769368ee4..a61a48a29b 100644
--- a/runtime/jni/java_vm_ext.cc
+++ b/runtime/jni/java_vm_ext.cc
@@ -23,6 +23,7 @@
#include "art_method-inl.h"
#include "base/dumpable.h"
#include "base/mutex-inl.h"
+#include "base/sdk_version.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "check_jni.h"
@@ -1030,7 +1031,7 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
int version = (*jni_on_load)(this, nullptr);
- if (runtime_->GetTargetSdkVersion() != 0 && runtime_->GetTargetSdkVersion() <= 21) {
+ if (IsSdkVersionSetAndAtMost(runtime_->GetTargetSdkVersion(), SdkVersion::kL)) {
// Make sure that sigchain owns SIGSEGV.
EnsureFrontOfChain(SIGSEGV);
}
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index c38cc86c59..4e551adfde 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -211,12 +211,12 @@ class MANAGED Class final : public Object {
}
ALWAYS_INLINE bool ShouldSkipHiddenApiChecks() REQUIRES_SHARED(Locks::mutator_lock_) {
- return (GetAccessFlags() & kAccSkipHiddenApiChecks) != 0;
+ return (GetAccessFlags() & kAccSkipHiddenapiChecks) != 0;
}
ALWAYS_INLINE void SetSkipHiddenApiChecks() REQUIRES_SHARED(Locks::mutator_lock_) {
uint32_t flags = GetAccessFlags();
- SetAccessFlags(flags | kAccSkipHiddenApiChecks);
+ SetAccessFlags(flags | kAccSkipHiddenapiChecks);
}
ALWAYS_INLINE void SetRecursivelyInitialized() REQUIRES_SHARED(Locks::mutator_lock_) {
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 49b71cd801..e213dc79b8 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -29,6 +29,7 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version);
#include "arch/instruction_set.h"
#include "art_method-inl.h"
#include "base/enums.h"
+#include "base/sdk_version.h"
#include "class_linker-inl.h"
#include "common_throws.h"
#include "debugger.h"
@@ -256,12 +257,15 @@ static void VMRuntime_setTargetSdkVersionNative(JNIEnv*, jobject, jint target_sd
// where workarounds can be enabled.
// Note that targetSdkVersion may be CUR_DEVELOPMENT (10000).
// Note that targetSdkVersion may be 0, meaning "current".
- Runtime::Current()->SetTargetSdkVersion(target_sdk_version);
+ uint32_t uint_target_sdk_version =
+ target_sdk_version <= 0 ? static_cast<uint32_t>(SdkVersion::kUnset)
+ : static_cast<uint32_t>(target_sdk_version);
+ Runtime::Current()->SetTargetSdkVersion(uint_target_sdk_version);
#ifdef ART_TARGET_ANDROID
// This part is letting libc/dynamic linker know about current app's
// target sdk version to enable compatibility workarounds.
- android_set_application_target_sdk_version(static_cast<uint32_t>(target_sdk_version));
+ android_set_application_target_sdk_version(uint_target_sdk_version);
#endif
}
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 715792876d..33c85973b3 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -323,7 +323,7 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize
.WithValueMap({{"false", false}, {"true", true}})
.IntoKey(M::SlowDebug)
.Define("-Xtarget-sdk-version:_")
- .WithType<int>()
+ .WithType<unsigned int>()
.IntoKey(M::TargetSdkVersion)
.Define("-Xhidden-api-checks")
.IntoKey(M::HiddenApiChecks)
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index ccbc2d92e1..f016e874ca 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -61,6 +61,7 @@
#include "base/mutex.h"
#include "base/os.h"
#include "base/quasi_atomic.h"
+#include "base/sdk_version.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
@@ -253,7 +254,7 @@ Runtime::Runtime()
preinitialization_transactions_(),
verify_(verifier::VerifyMode::kNone),
allow_dex_file_fallback_(true),
- target_sdk_version_(kUnsetSdkVersion),
+ target_sdk_version_(static_cast<uint32_t>(SdkVersion::kUnset)),
implicit_null_checks_(false),
implicit_so_checks_(false),
implicit_suspend_checks_(false),
@@ -277,6 +278,7 @@ 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");
@@ -320,11 +322,20 @@ Runtime::~Runtime() {
}
if (dump_gc_performance_on_shutdown_) {
+ 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 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";
}
if (jit_ != nullptr) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index f6a5634379..3c057f3c41 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -583,11 +583,11 @@ class Runtime {
return is_running_on_memory_tool_;
}
- void SetTargetSdkVersion(int32_t version) {
+ void SetTargetSdkVersion(uint32_t version) {
target_sdk_version_ = version;
}
- int32_t GetTargetSdkVersion() const {
+ uint32_t GetTargetSdkVersion() const {
return target_sdk_version_;
}
@@ -793,8 +793,6 @@ class Runtime {
return jdwp_provider_;
}
- static constexpr int32_t kUnsetSdkVersion = 0u;
-
uint32_t GetVerifierLoggingThresholdMs() const {
return verifier_logging_threshold_ms_;
}
@@ -975,7 +973,7 @@ class Runtime {
std::vector<std::string> cpu_abilist_;
// Specifies target SDK version to allow workarounds for certain API levels.
- int32_t target_sdk_version_;
+ uint32_t target_sdk_version_;
// Implicit checks flags.
bool implicit_null_checks_; // NullPointer checks are implicit.
@@ -1111,6 +1109,9 @@ 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/runtime_options.cc b/runtime/runtime_options.cc
index f8c680db44..12dab158e5 100644
--- a/runtime/runtime_options.cc
+++ b/runtime/runtime_options.cc
@@ -18,6 +18,7 @@
#include <memory>
+#include "base/sdk_version.h"
#include "base/utils.h"
#include "debugger.h"
#include "gc/heap.h"
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index ae1e08f10b..5cec309453 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -116,7 +116,8 @@ RUNTIME_OPTIONS_KEY (std::vector<std::string>, \
ImageCompilerOptions) // -Ximage-compiler-option ...
RUNTIME_OPTIONS_KEY (verifier::VerifyMode, \
Verify, verifier::VerifyMode::kEnable)
-RUNTIME_OPTIONS_KEY (int, TargetSdkVersion, Runtime::kUnsetSdkVersion)
+RUNTIME_OPTIONS_KEY (unsigned int, TargetSdkVersion, \
+ static_cast<unsigned int>(SdkVersion::kUnset))
RUNTIME_OPTIONS_KEY (Unit, HiddenApiChecks)
RUNTIME_OPTIONS_KEY (std::string, NativeBridge)
RUNTIME_OPTIONS_KEY (unsigned int, ZygoteMaxFailedBoots, 10)
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 7b07389057..0b33a0b3c0 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -28,6 +28,7 @@
#include "base/indenter.h"
#include "base/logging.h" // For VLOG.
#include "base/mutex-inl.h"
+#include "base/sdk_version.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
@@ -3677,9 +3678,10 @@ const RegType& MethodVerifier::ResolveClass(dex::TypeIndex class_idx) {
// Note: we do this for unresolved classes to trigger re-verification at runtime.
if (C == CheckAccess::kYes &&
result->IsNonZeroReferenceTypes() &&
- (api_level_ >= 28u || !result->IsUnresolvedTypes())) {
+ (IsSdkVersionSetAndAtLeast(api_level_, SdkVersion::kP) || !result->IsUnresolvedTypes())) {
const RegType& referrer = GetDeclaringClass();
- if ((api_level_ >= 28u || !referrer.IsUnresolvedTypes()) && !referrer.CanAccess(*result)) {
+ if ((IsSdkVersionSetAndAtLeast(api_level_, SdkVersion::kP) || !referrer.IsUnresolvedTypes()) &&
+ !referrer.CanAccess(*result)) {
Fail(VERIFY_ERROR_ACCESS_CLASS) << "(possibly) illegal class access: '"
<< referrer << "' -> '" << *result << "'";
}
@@ -4562,7 +4564,9 @@ ArtField* MethodVerifier::GetStaticField(int field_idx) {
}
if (klass_type.IsUnresolvedTypes()) {
// Accessibility checks depend on resolved fields.
- DCHECK(klass_type.Equals(GetDeclaringClass()) || !failures_.empty() || api_level_ < 28u);
+ DCHECK(klass_type.Equals(GetDeclaringClass()) ||
+ !failures_.empty() ||
+ IsSdkVersionSetAndLessThan(api_level_, SdkVersion::kP));
return nullptr; // Can't resolve Class so no more to do here, will do checking at runtime.
}
@@ -4603,7 +4607,9 @@ ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int field_id
}
if (klass_type.IsUnresolvedTypes()) {
// Accessibility checks depend on resolved fields.
- DCHECK(klass_type.Equals(GetDeclaringClass()) || !failures_.empty() || api_level_ < 28u);
+ DCHECK(klass_type.Equals(GetDeclaringClass()) ||
+ !failures_.empty() ||
+ IsSdkVersionSetAndLessThan(api_level_, SdkVersion::kP));
return nullptr; // Can't resolve Class so no more to do here
}
@@ -4739,7 +4745,7 @@ void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType&
DCHECK(!can_load_classes_ || self_->IsExceptionPending());
self_->ClearException();
}
- } else if (api_level_ >= 28u) {
+ } else if (IsSdkVersionSetAndAtLeast(api_level_, SdkVersion::kP)) {
// If we don't have the field (it seems we failed resolution) and this is a PUT, we need to
// redo verification at runtime as the field may be final, unless the field id shows it's in
// the same class.
diff --git a/test/674-hiddenapi/hiddenapi.cc b/test/674-hiddenapi/hiddenapi.cc
index 8e3e4eb5ce..d11aa579e5 100644
--- a/test/674-hiddenapi/hiddenapi.cc
+++ b/test/674-hiddenapi/hiddenapi.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "base/sdk_version.h"
#include "class_linker.h"
#include "dex/art_dex_file_loader.h"
#include "hidden_api.h"
@@ -29,7 +30,7 @@ namespace Test674HiddenApi {
extern "C" JNIEXPORT void JNICALL Java_Main_init(JNIEnv*, jclass) {
Runtime* runtime = Runtime::Current();
runtime->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
- runtime->SetTargetSdkVersion(static_cast<int32_t>(hiddenapi::detail::SdkCodes::kVersionO_MR1));
+ runtime->SetTargetSdkVersion(static_cast<uint32_t>(SdkVersion::kO_MR1));
runtime->SetDedupeHiddenApiWarnings(false);
}
@@ -284,7 +285,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeConstructorV(
}
extern "C" JNIEXPORT jint JNICALL Java_Reflection_getHiddenApiAccessFlags(JNIEnv*, jclass) {
- return static_cast<jint>(kAccHiddenApiBits);
+ return static_cast<jint>(kAccHiddenapiBits);
}
} // namespace Test674HiddenApi
diff --git a/test/688-shared-library/run b/test/688-shared-library/run
new file mode 100644
index 0000000000..fa6ab58da6
--- /dev/null
+++ b/test/688-shared-library/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# App images are incompatible with what the test is doing: loading one
+# dex file multiple times.
+exec ${RUN} "${@}" --no-app-image
diff --git a/test/999-redefine-hiddenapi/src-redefine/gen.sh b/test/999-redefine-hiddenapi/src-redefine/gen.sh
index 6948cbbfc3..f78a025265 100755
--- a/test/999-redefine-hiddenapi/src-redefine/gen.sh
+++ b/test/999-redefine-hiddenapi/src-redefine/gen.sh
@@ -18,13 +18,21 @@ set -e
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
TMP=`mktemp -d`
-CLASS "art/Test999"
+CLASS="art/Test999"
-(cd "$TMP" && javac -d "${TMP}" "$DIR/${CLASS}.java" && d8 --output . "$TMP/${CLASS}.class")
+(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" \
+ --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 c6365ac234..4627b4fd22 100644
--- a/test/999-redefine-hiddenapi/src/Main.java
+++ b/test/999-redefine-hiddenapi/src/Main.java
@@ -19,7 +19,7 @@ import java.lang.reflect.Method;
import java.util.Base64;
public class Main {
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) throws ClassNotFoundException {
System.loadLibrary(args[0]);
// Run the initialization routine. This will enable hidden API checks in
@@ -31,35 +31,53 @@ 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(klass, "before redefinition");
- assertFieldIsHidden(klass, "before redefinition");
+ assertMethodIsHidden(true, klass, "before redefinition");
+ assertFieldIsHidden(true, klass, "before redefinition");
- // Redefine the class using JVMTI.
+ // 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 still hidden.
- assertMethodIsHidden(klass, "after redefinition");
- assertFieldIsHidden(klass, "after redefinition");
+ // 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");
}
- private static void assertMethodIsHidden(Class<?> klass, String msg) throws Exception {
+ private static void assertMethodIsHidden(boolean expectedHidden, Class<?> klass, String msg) {
try {
klass.getDeclaredMethod("foo");
- // Unexpected. Should have thrown NoSuchMethodException.
- throw new Exception("Method should not be accessible " + msg);
+ if (expectedHidden) {
+ // Unexpected. Should have thrown NoSuchMethodException.
+ throw new RuntimeException("Method should not be accessible " + msg);
+ }
} catch (NoSuchMethodException ex) {
- // Expected.
+ if (!expectedHidden) {
+ // Unexpected. Should not have thrown NoSuchMethodException.
+ throw new RuntimeException("Method should be accessible " + msg);
+ }
}
}
- private static void assertFieldIsHidden(Class<?> klass, String msg) throws Exception {
+ private static void assertFieldIsHidden(boolean expectedHidden, Class<?> klass, String msg) {
try {
klass.getDeclaredField("bar");
- // Unexpected. Should have thrown NoSuchFieldException.
- throw new Exception("Field should not be accessible " + msg);
+ if (expectedHidden) {
+ // Unexpected. Should have thrown NoSuchFieldException.
+ throw new RuntimeException("Field should not be accessible " + msg);
+ }
} catch (NoSuchFieldException ex) {
- // Expected.
+ if (!expectedHidden) {
+ // Unexpected. Should not have thrown NoSuchFieldException.
+ throw new RuntimeException("Field should be accessible " + msg);
+ }
}
}
@@ -93,19 +111,37 @@ public class Main {
"ASoQQLUAArEAAAABAA0AAAAKAAIAAAATAAQAGAABAA4ACwABAAwAAAAlAAIAAQAAAAmyAAMSBLYA" +
"BbEAAAABAA0AAAAKAAIAAAAVAAgAFgABAA8AAAACABA=");
private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQD0dZ+IWxOi+cJDSWjfTnUerlZj1Lll3ONIAwAAcAAAAHhWNBIAAAAAAAAAAJwCAAAQ" +
- "AAAAcAAAAAcAAACwAAAAAgAAAMwAAAACAAAA5AAAAAQAAAD0AAAAAQAAABQBAAAUAgAANAEAAIYB" +
+ "ZGV4CjAzNQDlfmgFfKulToQpDF+P4dsgeOkgfzzH+5lgAwAAcAAAAHhWNBIAAAAAAAAAALQCAAAQ" +
+ "AAAAcAAAAAcAAACwAAAAAgAAAMwAAAACAAAA5AAAAAQAAAD0AAAAAQAAABQBAAAsAgAANAEAAIYB" +
+ "AACOAQAAlwEAAJoBAACpAQAAwAEAANQBAADoAQAA/AEAAAoCAAANAgAAEQIAABYCAAAbAgAAIAIA" +
+ "ACkCAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAJAAAACQAAAAYAAAAAAAAACgAAAAYAAACAAQAA" +
+ "AQAAAAsAAAAFAAIADQAAAAEAAAAAAAAAAQAAAAwAAAACAAEADgAAAAMAAAAAAAAAAQAAAAEAAAAD" +
+ "AAAAAAAAAAgAAAAAAAAAoAIAAAAAAAACAAEAAQAAAHQBAAAIAAAAcBADAAEAEwBAAFkQAAAOAAMA" +
+ "AQACAAAAeQEAAAgAAABiAAEAGgEBAG4gAgAQAA4AEwAOQAAVAA54AAAAAQAAAAQABjxpbml0PgAH" +
+ "R29vZGJ5ZQABSQANTGFydC9UZXN0OTk5OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9s" +
+ "YW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0" +
+ "OTk5LmphdmEAAVYAAlZMAANiYXIAA2ZvbwADb3V0AAdwcmludGxuAHV+fkQ4eyJjb21waWxhdGlv" +
+ "bi1tb2RlIjoiZGVidWciLCJtaW4tYXBpIjoxLCJzaGEtMSI6ImQyMmFiNGYxOWI3NTYxNDQ3NTI4" +
+ "NTdjYTg2YjJjZWU0ZGQ5Y2ExNjYiLCJ2ZXJzaW9uIjoiMS40LjktZGV2In0AAAEBAQABAIGABLQC" +
+ "AQHUAgAAAAAOAAAAAAAAAAEAAAAAAAAAAQAAABAAAABwAAAAAgAAAAcAAACwAAAAAwAAAAIAAADM" +
+ "AAAABAAAAAIAAADkAAAABQAAAAQAAAD0AAAABgAAAAEAAAAUAQAAASAAAAIAAAA0AQAAAyAAAAIA" +
+ "AAB0AQAAARAAAAEAAACAAQAAAiAAABAAAACGAQAAACAAAAEAAACgAgAAAxAAAAEAAACwAgAAABAA" +
+ "AAEAAAC0AgAA");
+ private static final byte[] DEX_BYTES_HIDDEN = Base64.getDecoder().decode(
+ "ZGV4CjAzNQDsgG5ufKulToQpDF+P4dsgeOkgfzzH+5l4AwAAcAAAAHhWNBIAAAAAAAAAAMACAAAQ" +
+ "AAAAcAAAAAcAAACwAAAAAgAAAMwAAAACAAAA5AAAAAQAAAD0AAAAAQAAABQBAABEAgAANAEAAIYB" +
"AACOAQAAlwEAAJoBAACpAQAAwAEAANQBAADoAQAA/AEAAAoCAAANAgAAEQIAABYCAAAbAgAAIAIA" +
"ACkCAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAJAAAACQAAAAYAAAAAAAAACgAAAAYAAACAAQAA" +
"AQAAAAsAAAAFAAIADQAAAAEAAAAAAAAAAQAAAAwAAAACAAEADgAAAAMAAAAAAAAAAQAAAAEAAAAD" +
- "AAAAAAAAAAgAAAAAAAAAhwIAAAAAAAACAAEAAQAAAHQBAAAIAAAAcBADAAEAEwBAAFkQAAAOAAMA" +
+ "AAAAAAAAAAgAAAAAAAAAoAIAAAAAAAACAAEAAQAAAHQBAAAIAAAAcBADAAEAEwBAAFkQAAAOAAMA" +
"AQACAAAAeQEAAAgAAABiAAEAGgEBAG4gAgAQAA4AEwAOQAAVAA54AAAAAQAAAAQABjxpbml0PgAH" +
"R29vZGJ5ZQABSQANTGFydC9UZXN0OTk5OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9s" +
"YW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0" +
- "OTk5LmphdmEAAVYAAlZMAANiYXIAA2ZvbwADb3V0AAdwcmludGxuAFx+fkQ4eyJtaW4tYXBpIjox" +
- "LCJzaGEtMSI6IjU2YzJlMzBmNTIzM2I4NDRmZjZkZGQ4N2ZiNTNkMzRmYjE3MjM3ZGYiLCJ2ZXJz" +
- "aW9uIjoidjEuMi4xNS1kZXYifQAAAQEBAAEAgYAEtAIBAdQCAAAAAAAOAAAAAAAAAAEAAAAAAAAA" +
- "AQAAABAAAABwAAAAAgAAAAcAAACwAAAAAwAAAAIAAADMAAAABAAAAAIAAADkAAAABQAAAAQAAAD0" +
- "AAAABgAAAAEAAAAUAQAAASAAAAIAAAA0AQAAAyAAAAIAAAB0AQAAARAAAAEAAACAAQAAAiAAABAA" +
- "AACGAQAAACAAAAEAAACHAgAAAxAAAAEAAACYAgAAABAAAAEAAACcAgAA");
+ "OTk5LmphdmEAAVYAAlZMAANiYXIAA2ZvbwADb3V0AAdwcmludGxuAHV+fkQ4eyJjb21waWxhdGlv" +
+ "bi1tb2RlIjoiZGVidWciLCJtaW4tYXBpIjoxLCJzaGEtMSI6ImQyMmFiNGYxOWI3NTYxNDQ3NTI4" +
+ "NTdjYTg2YjJjZWU0ZGQ5Y2ExNjYiLCJ2ZXJzaW9uIjoiMS40LjktZGV2In0AAAEBAQABAIGABLQC" +
+ "AQHUAgAAAAALAAAACAAAAAIAAgAPAAAAAAAAAAEAAAAAAAAAAQAAABAAAABwAAAAAgAAAAcAAACw" +
+ "AAAAAwAAAAIAAADMAAAABAAAAAIAAADkAAAABQAAAAQAAAD0AAAABgAAAAEAAAAUAQAAASAAAAIA" +
+ "AAA0AQAAAyAAAAIAAAB0AQAAARAAAAEAAACAAQAAAiAAABAAAACGAQAAACAAAAEAAACgAgAAAxAA" +
+ "AAEAAACwAgAAAPAAAAEAAAC0AgAAABAAAAEAAADAAgAA");
}
diff --git a/tools/build_linux_bionic_tests.sh b/tools/build_linux_bionic_tests.sh
index 3ee7d506aa..2b178f2cff 100755
--- a/tools/build_linux_bionic_tests.sh
+++ b/tools/build_linux_bionic_tests.sh
@@ -29,6 +29,7 @@ fi
source build/envsetup.sh >&/dev/null # for get_build_var
out_dir=$(get_build_var OUT_DIR)
+host_out=$(get_build_var HOST_OUT)
# TODO(b/31559095) Figure out a better way to do this.
#
@@ -80,8 +81,8 @@ bionic_targets=(
$soong_out/bin/hiddenapi
$soong_out/bin/hprof-conv
$soong_out/bin/timeout_dumper
- $(find $ANDROID_HOST_OUT/lib64 -type f | sed "s:$ANDROID_HOST_OUT:$soong_out:g")
- $(find $ANDROID_HOST_OUT/nativetest64 -type f | sed "s:$ANDROID_HOST_OUT:$soong_out:g"))
+ $(find $host_out/lib64 -type f | sed "s:$host_out:$soong_out:g")
+ $(find $host_out/nativetest64 -type f | sed "s:$host_out:$soong_out:g"))
echo building ${bionic_targets[*]}
diff --git a/tools/timeout_dumper/Android.bp b/tools/timeout_dumper/Android.bp
index dfd54421fd..bb813d4bbb 100644
--- a/tools/timeout_dumper/Android.bp
+++ b/tools/timeout_dumper/Android.bp
@@ -22,6 +22,11 @@ art_cc_binary {
darwin: {
enabled: false,
},
+ linux_bionic: {
+ sanitize: {
+ address: false,
+ },
+ },
},
device_supported: false,