summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk11
-rw-r--r--build/apex/Android.bp37
-rwxr-xr-xbuild/apex/runtests.sh9
-rw-r--r--dex2oat/dex2oat_test.cc11
-rw-r--r--runtime/class_linker.cc81
-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/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/runtime.cc10
-rw-r--r--runtime/runtime.h3
-rw-r--r--test/testrunner/target_config.py9
-rwxr-xr-xtools/build_linux_bionic_tests.sh5
17 files changed, 634 insertions, 112 deletions
diff --git a/Android.mk b/Android.mk
index b9f617035c..d6392201cb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -326,6 +326,17 @@ endif
#######################
+# Android Runtime APEX.
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.runtime
+# TODO: Select the debug module (`com.android.runtime.debug`) for
+# userdebug and eng products.
+LOCAL_REQUIRED_MODULES := com.android.runtime.release
+include $(BUILD_PHONY_PACKAGE)
+
+
+#######################
# Fake packages for ART
# The art-runtime package depends on the core ART libraries and binaries. It exists so we can
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index 8bddb5dfe7..bfaacb10fa 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -72,8 +72,41 @@ apex_key {
private_key: "runtime.pem",
}
+// TODO: Introduce `apex_defaults` to factor common parts of `apex`
+// module definitions below?
+
+// Release version of the Runtime APEX module (not containing debug
+// variants nor tools), included in user builds. Also used for
+// storage-constrained devices in userdebug and eng builds.
+apex {
+ name: "com.android.runtime.release",
+ compile_multilib: "both",
+ manifest: "manifest.json",
+ native_shared_libs: art_runtime_base_native_shared_libs
+ + art_runtime_fake_native_shared_libs,
+ multilib: {
+ both: {
+ // TODO: Add logic to create a `dalvikvm` symlink to `dalvikvm32` or `dalvikvm64`
+ // (see `symlink_preferred_arch` in art/dalvikvm/Android.bp).
+ binaries: art_runtime_base_binaries_both,
+ },
+ prefer32: {
+ binaries: art_runtime_base_binaries_prefer32,
+ },
+ first: {
+ binaries: [],
+ }
+ },
+ key: "com.android.runtime.key",
+ // TODO: Also package a `ld.config.txt` config file (to be placed in `etc/`).
+ // ...
+}
+
+// "Debug" version of the Runtime APEX module (containing both release and
+// debug variants, as well as additional tools), included in userdebug and
+// eng build.
apex {
- name: "com.android.runtime",
+ name: "com.android.runtime.debug",
compile_multilib: "both",
manifest: "manifest.json",
native_shared_libs: art_runtime_base_native_shared_libs
@@ -87,7 +120,7 @@ apex {
},
prefer32: {
binaries: art_runtime_base_binaries_prefer32
- + art_runtime_debug_binaries_prefer32
+ + art_runtime_debug_binaries_prefer32,
},
first: {
binaries: art_tools_binaries,
diff --git a/build/apex/runtests.sh b/build/apex/runtests.sh
index 6af2a8bc5c..86cd8cb758 100755
--- a/build/apex/runtests.sh
+++ b/build/apex/runtests.sh
@@ -79,7 +79,8 @@ function finish {
trap finish EXIT
-apex_module="com.android.runtime"
+# TODO: Also exercise the Release Runtime APEX (`com.android.runtime.release`).
+apex_module="com.android.runtime.debug"
# Build the Android Runtime APEX package (optional).
$build_apex_p && say "Building package" && make "$apex_module"
@@ -190,10 +191,8 @@ check_library libprofiled.so
# libsigchain.so
# libtombstoned_client.so
# libunwindstack.so
-# libvixl-arm64.so
-# libvixl-arm.so
-# libvixld-arm64.so
-# libvixld-arm.so
+# libvixl.so
+# libvixld.so
# ...
#
# ?
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/runtime/class_linker.cc b/runtime/class_linker.cc
index ce7dfaf8af..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();
@@ -8994,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);
@@ -9098,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 =
@@ -9115,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());
+ }
+
+ 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());
- 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);
+ 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/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/runtime.cc b/runtime/runtime.cc
index 19c1623d1f..f016e874ca 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -278,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");
@@ -321,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 a696c2845e..3c057f3c41 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -1109,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/test/testrunner/target_config.py b/test/testrunner/target_config.py
index b1878133f0..077129fa6c 100644
--- a/test/testrunner/target_config.py
+++ b/test/testrunner/target_config.py
@@ -331,10 +331,9 @@ target_config = {
},
'art-linux-bionic-x64': {
'build': '{ANDROID_BUILD_TOP}/art/tools/build_linux_bionic_tests.sh {MAKE_OPTIONS}',
- # Currently failing on the build-bots due to some library search path issue.
- # 'run-test': ['--run-test-option=--bionic',
- # '--host',
- # '--64',
- # '--no-build-dependencies'],
+ 'run-test': ['--run-test-option=--bionic',
+ '--host',
+ '--64',
+ '--no-build-dependencies'],
},
}
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[*]}