HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Oreo
|
8.0.0_r4
下载
查看原文件
收藏
根目录
art
runtime
class_linker.cc
/* * Copyright (C) 2011 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. */ #include "class_linker.h" #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "android-base/stringprintf.h" #include "art_field-inl.h" #include "art_method-inl.h" #include "base/arena_allocator.h" #include "base/casts.h" #include "base/logging.h" #include "base/scoped_arena_containers.h" #include "base/scoped_flock.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "base/value_object.h" #include "cha.h" #include "class_linker-inl.h" #include "class_table-inl.h" #include "compiler_callbacks.h" #include "debugger.h" #include "dex_file-inl.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "experimental_flags.h" #include "gc_root-inl.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap-inl.h" #include "gc/heap.h" #include "gc/scoped_gc_critical_section.h" #include "gc/space/image_space.h" #include "gc/space/space-inl.h" #include "handle_scope-inl.h" #include "image-inl.h" #include "imt_conflict_table.h" #include "imtable-inl.h" #include "intern_table.h" #include "interpreter/interpreter.h" #include "java_vm_ext.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "jit/profile_compilation_info.h" #include "jni_internal.h" #include "leb128.h" #include "linear_alloc.h" #include "mirror/call_site.h" #include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/class_ext.h" #include "mirror/class_loader.h" #include "mirror/dex_cache.h" #include "mirror/dex_cache-inl.h" #include "mirror/emulated_stack_frame.h" #include "mirror/field.h" #include "mirror/iftable-inl.h" #include "mirror/method.h" #include "mirror/method_type.h" #include "mirror/method_handle_impl.h" #include "mirror/method_handles_lookup.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/proxy.h" #include "mirror/reference-inl.h" #include "mirror/stack_trace_element.h" #include "mirror/string-inl.h" #include "native/dalvik_system_DexFile.h" #include "oat.h" #include "oat_file.h" #include "oat_file-inl.h" #include "oat_file_assistant.h" #include "oat_file_manager.h" #include "object_lock.h" #include "os.h" #include "runtime.h" #include "runtime_callbacks.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" #include "thread_list.h" #include "trace.h" #include "utils.h" #include "utils/dex_cache_arrays_layout-inl.h" #include "verifier/method_verifier.h" #include "well_known_classes.h" namespace art { using android::base::StringPrintf; static constexpr bool kSanityCheckObjects = kIsDebugBuild; static constexpr bool kVerifyArtMethodDeclaringClasses = kIsDebugBuild; static void ThrowNoClassDefFoundError(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))) REQUIRES_SHARED(Locks::mutator_lock_); static void ThrowNoClassDefFoundError(const char* fmt, ...) { va_list args; va_start(args, fmt); Thread* self = Thread::Current(); self->ThrowNewExceptionV("Ljava/lang/NoClassDefFoundError;", fmt, args); va_end(args); } static bool HasInitWithString(Thread* self, ClassLinker* class_linker, const char* descriptor) REQUIRES_SHARED(Locks::mutator_lock_) { ArtMethod* method = self->GetCurrentMethod(nullptr); StackHandleScope<1> hs(self); Handle
class_loader(hs.NewHandle(method != nullptr ? method->GetDeclaringClass()->GetClassLoader() : nullptr)); ObjPtr
exception_class = class_linker->FindClass(self, descriptor, class_loader); if (exception_class == nullptr) { // No exc class ~ no
-with-string. CHECK(self->IsExceptionPending()); self->ClearException(); return false; } ArtMethod* exception_init_method = exception_class->FindDeclaredDirectMethod( "
", "(Ljava/lang/String;)V", class_linker->GetImagePointerSize()); return exception_init_method != nullptr; } static mirror::Object* GetVerifyError(ObjPtr
c) REQUIRES_SHARED(Locks::mutator_lock_) { ObjPtr
ext(c->GetExtData()); if (ext == nullptr) { return nullptr; } else { return ext->GetVerifyError(); } } // Helper for ThrowEarlierClassFailure. Throws the stored error. static void HandleEarlierVerifyError(Thread* self, ClassLinker* class_linker, ObjPtr
c) REQUIRES_SHARED(Locks::mutator_lock_) { ObjPtr
obj = GetVerifyError(c); DCHECK(obj != nullptr); self->AssertNoPendingException(); if (obj->IsClass()) { // Previous error has been stored as class. Create a new exception of that type. // It's possible the exception doesn't have a
(String). std::string temp; const char* descriptor = obj->AsClass()->GetDescriptor(&temp); if (HasInitWithString(self, class_linker, descriptor)) { self->ThrowNewException(descriptor, c->PrettyDescriptor().c_str()); } else { self->ThrowNewException(descriptor, nullptr); } } else { // Previous error has been stored as an instance. Just rethrow. ObjPtr
throwable_class = self->DecodeJObject(WellKnownClasses::java_lang_Throwable)->AsClass(); ObjPtr
error_class = obj->GetClass(); CHECK(throwable_class->IsAssignableFrom(error_class)); self->SetException(obj->AsThrowable()); } self->AssertPendingException(); } void ClassLinker::ThrowEarlierClassFailure(ObjPtr
c, bool wrap_in_no_class_def) { // The class failed to initialize on a previous attempt, so we want to throw // a NoClassDefFoundError (v2 2.17.5). The exception to this rule is if we // failed in verification, in which case v2 5.4.1 says we need to re-throw // the previous error. Runtime* const runtime = Runtime::Current(); if (!runtime->IsAotCompiler()) { // Give info if this occurs at runtime. std::string extra; if (GetVerifyError(c) != nullptr) { ObjPtr
verify_error = GetVerifyError(c); if (verify_error->IsClass()) { extra = mirror::Class::PrettyDescriptor(verify_error->AsClass()); } else { extra = verify_error->AsThrowable()->Dump(); } } LOG(INFO) << "Rejecting re-init on previously-failed class " << c->PrettyClass() << ": " << extra; } CHECK(c->IsErroneous()) << c->PrettyClass() << " " << c->GetStatus(); Thread* self = Thread::Current(); if (runtime->IsAotCompiler()) { // At compile time, accurate errors and NCDFE are disabled to speed compilation. ObjPtr
pre_allocated = runtime->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); } else { if (GetVerifyError(c) != nullptr) { // Rethrow stored error. HandleEarlierVerifyError(self, this, c); } // TODO This might be wrong if we hit an OOME while allocating the ClassExt. In that case we // might have meant to go down the earlier if statement with the original error but it got // swallowed by the OOM so we end up here. if (GetVerifyError(c) == nullptr || wrap_in_no_class_def) { // If there isn't a recorded earlier error, or this is a repeat throw from initialization, // the top-level exception must be a NoClassDefFoundError. The potentially already pending // exception will be a cause. self->ThrowNewWrappedException("Ljava/lang/NoClassDefFoundError;", c->PrettyDescriptor().c_str()); } } } static void VlogClassInitializationFailure(Handle
klass) REQUIRES_SHARED(Locks::mutator_lock_) { if (VLOG_IS_ON(class_linker)) { std::string temp; LOG(INFO) << "Failed to initialize class " << klass->GetDescriptor(&temp) << " from " << klass->GetLocation() << "\n" << Thread::Current()->GetException()->Dump(); } } static void WrapExceptionInInitializer(Handle
klass) REQUIRES_SHARED(Locks::mutator_lock_) { Thread* self = Thread::Current(); JNIEnv* env = self->GetJniEnv(); ScopedLocalRef
cause(env, env->ExceptionOccurred()); CHECK(cause.get() != nullptr); // Boot classpath classes should not fail initialization. This is a sanity debug check. This // cannot in general be guaranteed, but in all likelihood leads to breakage down the line. if (klass->GetClassLoader() == nullptr && !Runtime::Current()->IsAotCompiler()) { std::string tmp; LOG(kIsDebugBuild ? FATAL : WARNING) << klass->GetDescriptor(&tmp) << " failed initialization"; } env->ExceptionClear(); bool is_error = env->IsInstanceOf(cause.get(), WellKnownClasses::java_lang_Error); env->Throw(cause.get()); // We only wrap non-Error exceptions; an Error can just be used as-is. if (!is_error) { self->ThrowNewWrappedException("Ljava/lang/ExceptionInInitializerError;", nullptr); } VlogClassInitializationFailure(klass); } // Gap between two fields in object layout. struct FieldGap { uint32_t start_offset; // The offset from the start of the object. uint32_t size; // The gap size of 1, 2, or 4 bytes. }; struct FieldGapsComparator { explicit FieldGapsComparator() { } bool operator() (const FieldGap& lhs, const FieldGap& rhs) NO_THREAD_SAFETY_ANALYSIS { // Sort by gap size, largest first. Secondary sort by starting offset. // Note that the priority queue returns the largest element, so operator() // should return true if lhs is less than rhs. return lhs.size < rhs.size || (lhs.size == rhs.size && lhs.start_offset > rhs.start_offset); } }; typedef std::priority_queue
, FieldGapsComparator> FieldGaps; // Adds largest aligned gaps to queue of gaps. static void AddFieldGap(uint32_t gap_start, uint32_t gap_end, FieldGaps* gaps) { DCHECK(gaps != nullptr); uint32_t current_offset = gap_start; while (current_offset != gap_end) { size_t remaining = gap_end - current_offset; if (remaining >= sizeof(uint32_t) && IsAligned<4>(current_offset)) { gaps->push(FieldGap {current_offset, sizeof(uint32_t)}); current_offset += sizeof(uint32_t); } else if (remaining >= sizeof(uint16_t) && IsAligned<2>(current_offset)) { gaps->push(FieldGap {current_offset, sizeof(uint16_t)}); current_offset += sizeof(uint16_t); } else { gaps->push(FieldGap {current_offset, sizeof(uint8_t)}); current_offset += sizeof(uint8_t); } DCHECK_LE(current_offset, gap_end) << "Overran gap"; } } // Shuffle fields forward, making use of gaps whenever possible. template
static void ShuffleForward(size_t* current_field_idx, MemberOffset* field_offset, std::deque
* grouped_and_sorted_fields, FieldGaps* gaps) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(current_field_idx != nullptr); DCHECK(grouped_and_sorted_fields != nullptr); DCHECK(gaps != nullptr); DCHECK(field_offset != nullptr); DCHECK(IsPowerOfTwo(n)); while (!grouped_and_sorted_fields->empty()) { ArtField* field = grouped_and_sorted_fields->front(); Primitive::Type type = field->GetTypeAsPrimitiveType(); if (Primitive::ComponentSize(type) < n) { break; } if (!IsAligned
(field_offset->Uint32Value())) { MemberOffset old_offset = *field_offset; *field_offset = MemberOffset(RoundUp(field_offset->Uint32Value(), n)); AddFieldGap(old_offset.Uint32Value(), field_offset->Uint32Value(), gaps); } CHECK(type != Primitive::kPrimNot) << field->PrettyField(); // should be primitive types grouped_and_sorted_fields->pop_front(); if (!gaps->empty() && gaps->top().size >= n) { FieldGap gap = gaps->top(); gaps->pop(); DCHECK_ALIGNED(gap.start_offset, n); field->SetOffset(MemberOffset(gap.start_offset)); if (gap.size > n) { AddFieldGap(gap.start_offset + n, gap.start_offset + gap.size, gaps); } } else { DCHECK_ALIGNED(field_offset->Uint32Value(), n); field->SetOffset(*field_offset); *field_offset = MemberOffset(field_offset->Uint32Value() + n); } ++(*current_field_idx); } } ClassLinker::ClassLinker(InternTable* intern_table) : failed_dex_cache_class_lookups_(0), class_roots_(nullptr), array_iftable_(nullptr), find_array_class_cache_next_victim_(0), init_done_(false), log_new_roots_(false), intern_table_(intern_table), quick_resolution_trampoline_(nullptr), quick_imt_conflict_trampoline_(nullptr), quick_generic_jni_trampoline_(nullptr), quick_to_interpreter_bridge_trampoline_(nullptr), image_pointer_size_(kRuntimePointerSize) { CHECK(intern_table_ != nullptr); static_assert(kFindArrayCacheSize == arraysize(find_array_class_cache_), "Array cache size wrong."); std::fill_n(find_array_class_cache_, kFindArrayCacheSize, GcRoot
(nullptr)); } void ClassLinker::CheckSystemClass(Thread* self, Handle
c1, const char* descriptor) { ObjPtr
c2 = FindSystemClass(self, descriptor); if (c2 == nullptr) { LOG(FATAL) << "Could not find class " << descriptor; UNREACHABLE(); } if (c1.Get() != c2) { std::ostringstream os1, os2; c1->DumpClass(os1, mirror::Class::kDumpClassFullDetail); c2->DumpClass(os2, mirror::Class::kDumpClassFullDetail); LOG(FATAL) << "InitWithoutImage: Class mismatch for " << descriptor << ". This is most likely the result of a broken build. Make sure that " << "libcore and art projects match.\n\n" << os1.str() << "\n\n" << os2.str(); UNREACHABLE(); } } bool ClassLinker::InitWithoutImage(std::vector
> boot_class_path, std::string* error_msg) { VLOG(startup) << "ClassLinker::Init"; Thread* const self = Thread::Current(); Runtime* const runtime = Runtime::Current(); gc::Heap* const heap = runtime->GetHeap(); CHECK(!heap->HasBootImageSpace()) << "Runtime has image. We should use it."; CHECK(!init_done_); // Use the pointer size from the runtime since we are probably creating the image. image_pointer_size_ = InstructionSetPointerSize(runtime->GetInstructionSet()); // java_lang_Class comes first, it's needed for AllocClass // The GC can't handle an object with a null class since we can't get the size of this object. heap->IncrementDisableMovingGC(self); StackHandleScope<64> hs(self); // 64 is picked arbitrarily. auto class_class_size = mirror::Class::ClassClassSize(image_pointer_size_); Handle
java_lang_Class(hs.NewHandle(down_cast
( heap->AllocNonMovableObject
(self, nullptr, class_class_size, VoidFunctor())))); CHECK(java_lang_Class != nullptr); mirror::Class::SetClassClass(java_lang_Class.Get()); java_lang_Class->SetClass(java_lang_Class.Get()); if (kUseBakerReadBarrier) { java_lang_Class->AssertReadBarrierState(); } java_lang_Class->SetClassSize(class_class_size); java_lang_Class->SetPrimitiveType(Primitive::kPrimNot); heap->DecrementDisableMovingGC(self); // AllocClass(ObjPtr
) can now be used // Class[] is used for reflection support. auto class_array_class_size = mirror::ObjectArray
::ClassSize(image_pointer_size_); Handle
class_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), class_array_class_size))); class_array_class->SetComponentType(java_lang_Class.Get()); // java_lang_Object comes next so that object_array_class can be created. Handle
java_lang_Object(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Object::ClassSize(image_pointer_size_)))); CHECK(java_lang_Object != nullptr); // backfill Object as the super class of Class. java_lang_Class->SetSuperClass(java_lang_Object.Get()); mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusLoaded, self); java_lang_Object->SetObjectSize(sizeof(mirror::Object)); // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been // cleared without triggering the read barrier and unintentionally mark the sentinel alive. runtime->SetSentinel(heap->AllocNonMovableObject
(self, java_lang_Object.Get(), java_lang_Object->GetObjectSize(), VoidFunctor())); // Object[] next to hold class roots. Handle
object_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray
::ClassSize(image_pointer_size_)))); object_array_class->SetComponentType(java_lang_Object.Get()); // Setup the char (primitive) class to be used for char[]. Handle
char_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Class::PrimitiveClassSize(image_pointer_size_)))); // The primitive char class won't be initialized by // InitializePrimitiveClass until line 459, but strings (and // internal char arrays) will be allocated before that and the // component size, which is computed from the primitive type, needs // to be set here. char_class->SetPrimitiveType(Primitive::kPrimChar); // Setup the char[] class to be used for String. Handle
char_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); char_array_class->SetComponentType(char_class.Get()); mirror::CharArray::SetArrayClass(char_array_class.Get()); // Setup String. Handle
java_lang_String(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_)))); java_lang_String->SetStringClass(); mirror::String::SetClass(java_lang_String.Get()); mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusResolved, self); // Setup java.lang.ref.Reference. Handle
java_lang_ref_Reference(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize(image_pointer_size_)))); mirror::Reference::SetClass(java_lang_ref_Reference.Get()); java_lang_ref_Reference->SetObjectSize(mirror::Reference::InstanceSize()); mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusResolved, self); // Create storage for root classes, save away our work so far (requires descriptors). class_roots_ = GcRoot
>( mirror::ObjectArray
::Alloc(self, object_array_class.Get(), kClassRootsMax)); CHECK(!class_roots_.IsNull()); SetClassRoot(kJavaLangClass, java_lang_Class.Get()); SetClassRoot(kJavaLangObject, java_lang_Object.Get()); SetClassRoot(kClassArrayClass, class_array_class.Get()); SetClassRoot(kObjectArrayClass, object_array_class.Get()); SetClassRoot(kCharArrayClass, char_array_class.Get()); SetClassRoot(kJavaLangString, java_lang_String.Get()); SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference.Get()); // Fill in the empty iftable. Needs to be done after the kObjectArrayClass root is set. java_lang_Object->SetIfTable(AllocIfTable(self, 0)); // Setup the primitive type classes. SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean)); SetClassRoot(kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte)); SetClassRoot(kPrimitiveShort, CreatePrimitiveClass(self, Primitive::kPrimShort)); SetClassRoot(kPrimitiveInt, CreatePrimitiveClass(self, Primitive::kPrimInt)); SetClassRoot(kPrimitiveLong, CreatePrimitiveClass(self, Primitive::kPrimLong)); SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass(self, Primitive::kPrimFloat)); SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass(self, Primitive::kPrimDouble)); SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid)); // Create array interface entries to populate once we can load system classes. array_iftable_ = GcRoot
(AllocIfTable(self, 2)); // Create int array type for AllocDexCache (done in AppendToBootClassPath). Handle
int_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt)); mirror::IntArray::SetArrayClass(int_array_class.Get()); SetClassRoot(kIntArrayClass, int_array_class.Get()); // Create long array type for AllocDexCache (done in AppendToBootClassPath). Handle
long_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); long_array_class->SetComponentType(GetClassRoot(kPrimitiveLong)); mirror::LongArray::SetArrayClass(long_array_class.Get()); SetClassRoot(kLongArrayClass, long_array_class.Get()); // now that these are registered, we can use AllocClass() and AllocObjectArray // Set up DexCache. This cannot be done later since AppendToBootClassPath calls AllocDexCache. Handle
java_lang_DexCache(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::DexCache::ClassSize(image_pointer_size_)))); SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get()); java_lang_DexCache->SetDexCacheClass(); java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize()); mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusResolved, self); // Setup dalvik.system.ClassExt Handle
dalvik_system_ClassExt(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::ClassExt::ClassSize(image_pointer_size_)))); SetClassRoot(kDalvikSystemClassExt, dalvik_system_ClassExt.Get()); mirror::ClassExt::SetClass(dalvik_system_ClassExt.Get()); mirror::Class::SetStatus(dalvik_system_ClassExt, mirror::Class::kStatusResolved, self); // Set up array classes for string, field, method Handle
object_array_string(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray
::ClassSize(image_pointer_size_)))); object_array_string->SetComponentType(java_lang_String.Get()); SetClassRoot(kJavaLangStringArrayClass, object_array_string.Get()); LinearAlloc* linear_alloc = runtime->GetLinearAlloc(); // Create runtime resolution and imt conflict methods. runtime->SetResolutionMethod(runtime->CreateResolutionMethod()); runtime->SetImtConflictMethod(runtime->CreateImtConflictMethod(linear_alloc)); runtime->SetImtUnimplementedMethod(runtime->CreateImtConflictMethod(linear_alloc)); // Setup boot_class_path_ and register class_path now that we can use AllocObjectArray to create // DexCache instances. Needs to be after String, Field, Method arrays since AllocDexCache uses // these roots. if (boot_class_path.empty()) { *error_msg = "Boot classpath is empty."; return false; } for (auto& dex_file : boot_class_path) { if (dex_file.get() == nullptr) { *error_msg = "Null dex file."; return false; } AppendToBootClassPath(self, *dex_file); boot_dex_files_.push_back(std::move(dex_file)); } // now we can use FindSystemClass // run char class through InitializePrimitiveClass to finish init InitializePrimitiveClass(char_class.Get(), Primitive::kPrimChar); SetClassRoot(kPrimitiveChar, char_class.Get()); // needs descriptor // Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that // we do not need friend classes or a publicly exposed setter. quick_generic_jni_trampoline_ = GetQuickGenericJniStub(); if (!runtime->IsAotCompiler()) { // We need to set up the generic trampolines since we don't have an image. quick_resolution_trampoline_ = GetQuickResolutionStub(); quick_imt_conflict_trampoline_ = GetQuickImtConflictStub(); quick_to_interpreter_bridge_trampoline_ = GetQuickToInterpreterBridge(); } // Object, String, ClassExt and DexCache need to be rerun through FindSystemClass to finish init mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusNotReady, self); CheckSystemClass(self, java_lang_Object, "Ljava/lang/Object;"); CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize()); mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusNotReady, self); CheckSystemClass(self, java_lang_String, "Ljava/lang/String;"); mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusNotReady, self); CheckSystemClass(self, java_lang_DexCache, "Ljava/lang/DexCache;"); CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize()); mirror::Class::SetStatus(dalvik_system_ClassExt, mirror::Class::kStatusNotReady, self); CheckSystemClass(self, dalvik_system_ClassExt, "Ldalvik/system/ClassExt;"); CHECK_EQ(dalvik_system_ClassExt->GetObjectSize(), mirror::ClassExt::InstanceSize()); // Setup the primitive array type classes - can't be done until Object has a vtable. SetClassRoot(kBooleanArrayClass, FindSystemClass(self, "[Z")); mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); SetClassRoot(kByteArrayClass, FindSystemClass(self, "[B")); mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); CheckSystemClass(self, char_array_class, "[C"); SetClassRoot(kShortArrayClass, FindSystemClass(self, "[S")); mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass)); CheckSystemClass(self, int_array_class, "[I"); CheckSystemClass(self, long_array_class, "[J"); SetClassRoot(kFloatArrayClass, FindSystemClass(self, "[F")); mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass)); SetClassRoot(kDoubleArrayClass, FindSystemClass(self, "[D")); mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); // Run Class through FindSystemClass. This initializes the dex_cache_ fields and register it // in class_table_. CheckSystemClass(self, java_lang_Class, "Ljava/lang/Class;"); CheckSystemClass(self, class_array_class, "[Ljava/lang/Class;"); CheckSystemClass(self, object_array_class, "[Ljava/lang/Object;"); // Setup the single, global copy of "iftable". auto java_lang_Cloneable = hs.NewHandle(FindSystemClass(self, "Ljava/lang/Cloneable;")); CHECK(java_lang_Cloneable != nullptr); auto java_io_Serializable = hs.NewHandle(FindSystemClass(self, "Ljava/io/Serializable;")); CHECK(java_io_Serializable != nullptr); // We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to // crawl up and explicitly list all of the supers as well. array_iftable_.Read()->SetInterface(0, java_lang_Cloneable.Get()); array_iftable_.Read()->SetInterface(1, java_io_Serializable.Get()); // Sanity check Class[] and Object[]'s interfaces. GetDirectInterface may cause thread // suspension. CHECK_EQ(java_lang_Cloneable.Get(), mirror::Class::GetDirectInterface(self, class_array_class.Get(), 0)); CHECK_EQ(java_io_Serializable.Get(), mirror::Class::GetDirectInterface(self, class_array_class.Get(), 1)); CHECK_EQ(java_lang_Cloneable.Get(), mirror::Class::GetDirectInterface(self, object_array_class.Get(), 0)); CHECK_EQ(java_io_Serializable.Get(), mirror::Class::GetDirectInterface(self, object_array_class.Get(), 1)); CHECK_EQ(object_array_string.Get(), FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass))); // End of special init trickery, all subsequent classes may be loaded via FindSystemClass. // Create java.lang.reflect.Proxy root. SetClassRoot(kJavaLangReflectProxy, FindSystemClass(self, "Ljava/lang/reflect/Proxy;")); // Create java.lang.reflect.Field.class root. auto* class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangReflectField, class_root); mirror::Field::SetClass(class_root); // Create java.lang.reflect.Field array root. class_root = FindSystemClass(self, "[Ljava/lang/reflect/Field;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangReflectFieldArrayClass, class_root); mirror::Field::SetArrayClass(class_root); // Create java.lang.reflect.Constructor.class root and array root. class_root = FindSystemClass(self, "Ljava/lang/reflect/Constructor;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangReflectConstructor, class_root); mirror::Constructor::SetClass(class_root); class_root = FindSystemClass(self, "[Ljava/lang/reflect/Constructor;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangReflectConstructorArrayClass, class_root); mirror::Constructor::SetArrayClass(class_root); // Create java.lang.reflect.Method.class root and array root. class_root = FindSystemClass(self, "Ljava/lang/reflect/Method;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangReflectMethod, class_root); mirror::Method::SetClass(class_root); class_root = FindSystemClass(self, "[Ljava/lang/reflect/Method;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangReflectMethodArrayClass, class_root); mirror::Method::SetArrayClass(class_root); // Create java.lang.invoke.MethodType.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodType;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeMethodType, class_root); mirror::MethodType::SetClass(class_root); // Create java.lang.invoke.MethodHandleImpl.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandleImpl;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeMethodHandleImpl, class_root); mirror::MethodHandleImpl::SetClass(class_root); // Create java.lang.invoke.MethodHandles.Lookup.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandles$Lookup;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeMethodHandlesLookup, class_root); mirror::MethodHandlesLookup::SetClass(class_root); // Create java.lang.invoke.CallSite.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/CallSite;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeCallSite, class_root); mirror::CallSite::SetClass(class_root); class_root = FindSystemClass(self, "Ldalvik/system/EmulatedStackFrame;"); CHECK(class_root != nullptr); SetClassRoot(kDalvikSystemEmulatedStackFrame, class_root); mirror::EmulatedStackFrame::SetClass(class_root); // java.lang.ref classes need to be specially flagged, but otherwise are normal classes // finish initializing Reference class mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self); CheckSystemClass(self, java_lang_ref_Reference, "Ljava/lang/ref/Reference;"); CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize()); CHECK_EQ(java_lang_ref_Reference->GetClassSize(), mirror::Reference::ClassSize(image_pointer_size_)); class_root = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;"); CHECK_EQ(class_root->GetClassFlags(), mirror::kClassFlagNormal); class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagFinalizerReference); class_root = FindSystemClass(self, "Ljava/lang/ref/PhantomReference;"); CHECK_EQ(class_root->GetClassFlags(), mirror::kClassFlagNormal); class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagPhantomReference); class_root = FindSystemClass(self, "Ljava/lang/ref/SoftReference;"); CHECK_EQ(class_root->GetClassFlags(), mirror::kClassFlagNormal); class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagSoftReference); class_root = FindSystemClass(self, "Ljava/lang/ref/WeakReference;"); CHECK_EQ(class_root->GetClassFlags(), mirror::kClassFlagNormal); class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagWeakReference); // Setup the ClassLoader, verifying the object_size_. class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;"); class_root->SetClassLoaderClass(); CHECK_EQ(class_root->GetObjectSize(), mirror::ClassLoader::InstanceSize()); SetClassRoot(kJavaLangClassLoader, class_root); // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and // java.lang.StackTraceElement as a convenience. SetClassRoot(kJavaLangThrowable, FindSystemClass(self, "Ljava/lang/Throwable;")); mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable)); SetClassRoot(kJavaLangClassNotFoundException, FindSystemClass(self, "Ljava/lang/ClassNotFoundException;")); SetClassRoot(kJavaLangStackTraceElement, FindSystemClass(self, "Ljava/lang/StackTraceElement;")); SetClassRoot(kJavaLangStackTraceElementArrayClass, FindSystemClass(self, "[Ljava/lang/StackTraceElement;")); mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement)); // Create conflict tables that depend on the class linker. runtime->FixupConflictTables(); FinishInit(self); VLOG(startup) << "ClassLinker::InitFromCompiler exiting"; return true; } void ClassLinker::FinishInit(Thread* self) { VLOG(startup) << "ClassLinker::FinishInit entering"; // Let the heap know some key offsets into java.lang.ref instances // Note: we hard code the field indexes here rather than using FindInstanceField // as the types of the field can't be resolved prior to the runtime being // fully initialized StackHandleScope<2> hs(self); Handle
java_lang_ref_Reference = hs.NewHandle(GetClassRoot(kJavaLangRefReference)); Handle
java_lang_ref_FinalizerReference = hs.NewHandle(FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;")); ArtField* pendingNext = java_lang_ref_Reference->GetInstanceField(0); CHECK_STREQ(pendingNext->GetName(), "pendingNext"); CHECK_STREQ(pendingNext->GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); ArtField* queue = java_lang_ref_Reference->GetInstanceField(1); CHECK_STREQ(queue->GetName(), "queue"); CHECK_STREQ(queue->GetTypeDescriptor(), "Ljava/lang/ref/ReferenceQueue;"); ArtField* queueNext = java_lang_ref_Reference->GetInstanceField(2); CHECK_STREQ(queueNext->GetName(), "queueNext"); CHECK_STREQ(queueNext->GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); ArtField* referent = java_lang_ref_Reference->GetInstanceField(3); CHECK_STREQ(referent->GetName(), "referent"); CHECK_STREQ(referent->GetTypeDescriptor(), "Ljava/lang/Object;"); ArtField* zombie = java_lang_ref_FinalizerReference->GetInstanceField(2); CHECK_STREQ(zombie->GetName(), "zombie"); CHECK_STREQ(zombie->GetTypeDescriptor(), "Ljava/lang/Object;"); // ensure all class_roots_ are initialized for (size_t i = 0; i < kClassRootsMax; i++) { ClassRoot class_root = static_cast
(i); ObjPtr
klass = GetClassRoot(class_root); CHECK(klass != nullptr); DCHECK(klass->IsArrayClass() || klass->IsPrimitive() || klass->GetDexCache() != nullptr); // note SetClassRoot does additional validation. // if possible add new checks there to catch errors early } CHECK(!array_iftable_.IsNull()); // disable the slow paths in FindClass and CreatePrimitiveClass now // that Object, Class, and Object[] are setup init_done_ = true; VLOG(startup) << "ClassLinker::FinishInit exiting"; } void ClassLinker::RunRootClinits() { Thread* self = Thread::Current(); for (size_t i = 0; i < ClassLinker::kClassRootsMax; ++i) { ObjPtr
c = GetClassRoot(ClassRoot(i)); if (!c->IsArrayClass() && !c->IsPrimitive()) { StackHandleScope<1> hs(self); Handle
h_class(hs.NewHandle(GetClassRoot(ClassRoot(i)))); EnsureInitialized(self, h_class, true, true); self->AssertNoPendingException(); } } } // Set image methods' entry point to interpreter. class SetInterpreterEntrypointArtMethodVisitor : public ArtMethodVisitor { public: explicit SetInterpreterEntrypointArtMethodVisitor(PointerSize image_pointer_size) : image_pointer_size_(image_pointer_size) {} void Visit(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { if (kIsDebugBuild && !method->IsRuntimeMethod()) { CHECK(method->GetDeclaringClass() != nullptr); } if (!method->IsNative() && !method->IsRuntimeMethod() && !method->IsResolutionMethod()) { method->SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(), image_pointer_size_); } } private: const PointerSize image_pointer_size_; DISALLOW_COPY_AND_ASSIGN(SetInterpreterEntrypointArtMethodVisitor); }; struct TrampolineCheckData { const void* quick_resolution_trampoline; const void* quick_imt_conflict_trampoline; const void* quick_generic_jni_trampoline; const void* quick_to_interpreter_bridge_trampoline; PointerSize pointer_size; ArtMethod* m; bool error; }; static void CheckTrampolines(mirror::Object* obj, void* arg) NO_THREAD_SAFETY_ANALYSIS { if (obj->IsClass()) { ObjPtr
klass = obj->AsClass(); TrampolineCheckData* d = reinterpret_cast
(arg); for (ArtMethod& m : klass->GetMethods(d->pointer_size)) { const void* entrypoint = m.GetEntryPointFromQuickCompiledCodePtrSize(d->pointer_size); if (entrypoint == d->quick_resolution_trampoline || entrypoint == d->quick_imt_conflict_trampoline || entrypoint == d->quick_generic_jni_trampoline || entrypoint == d->quick_to_interpreter_bridge_trampoline) { d->m = &m; d->error = true; return; } } } } bool ClassLinker::InitFromBootImage(std::string* error_msg) { VLOG(startup) << __FUNCTION__ << " entering"; CHECK(!init_done_); Runtime* const runtime = Runtime::Current(); Thread* const self = Thread::Current(); gc::Heap* const heap = runtime->GetHeap(); std::vector
spaces = heap->GetBootImageSpaces(); CHECK(!spaces.empty()); uint32_t pointer_size_unchecked = spaces[0]->GetImageHeader().GetPointerSizeUnchecked(); if (!ValidPointerSize(pointer_size_unchecked)) { *error_msg = StringPrintf("Invalid image pointer size: %u", pointer_size_unchecked); return false; } image_pointer_size_ = spaces[0]->GetImageHeader().GetPointerSize(); if (!runtime->IsAotCompiler()) { // Only the Aot compiler supports having an image with a different pointer size than the // runtime. This happens on the host for compiling 32 bit tests since we use a 64 bit libart // compiler. We may also use 32 bit dex2oat on a system with 64 bit apps. if (image_pointer_size_ != kRuntimePointerSize) { *error_msg = StringPrintf("Runtime must use current image pointer size: %zu vs %zu", static_cast
(image_pointer_size_), sizeof(void*)); return false; } } std::vector
oat_files = runtime->GetOatFileManager().RegisterImageOatFiles(spaces); DCHECK(!oat_files.empty()); const OatHeader& default_oat_header = oat_files[0]->GetOatHeader(); CHECK_EQ(default_oat_header.GetImageFileLocationOatDataBegin(), 0U); const char* image_file_location = oat_files[0]->GetOatHeader(). GetStoreValueByKey(OatHeader::kImageLocationKey); CHECK(image_file_location == nullptr || *image_file_location == 0); quick_resolution_trampoline_ = default_oat_header.GetQuickResolutionTrampoline(); quick_imt_conflict_trampoline_ = default_oat_header.GetQuickImtConflictTrampoline(); quick_generic_jni_trampoline_ = default_oat_header.GetQuickGenericJniTrampoline(); quick_to_interpreter_bridge_trampoline_ = default_oat_header.GetQuickToInterpreterBridge(); if (kIsDebugBuild) { // Check that the other images use the same trampoline. for (size_t i = 1; i < oat_files.size(); ++i) { const OatHeader& ith_oat_header = oat_files[i]->GetOatHeader(); const void* ith_quick_resolution_trampoline = ith_oat_header.GetQuickResolutionTrampoline(); const void* ith_quick_imt_conflict_trampoline = ith_oat_header.GetQuickImtConflictTrampoline(); const void* ith_quick_generic_jni_trampoline = ith_oat_header.GetQuickGenericJniTrampoline(); const void* ith_quick_to_interpreter_bridge_trampoline = ith_oat_header.GetQuickToInterpreterBridge(); if (ith_quick_resolution_trampoline != quick_resolution_trampoline_ || ith_quick_imt_conflict_trampoline != quick_imt_conflict_trampoline_ || ith_quick_generic_jni_trampoline != quick_generic_jni_trampoline_ || ith_quick_to_interpreter_bridge_trampoline != quick_to_interpreter_bridge_trampoline_) { // Make sure that all methods in this image do not contain those trampolines as // entrypoints. Otherwise the class-linker won't be able to work with a single set. TrampolineCheckData data; data.error = false; data.pointer_size = GetImagePointerSize(); data.quick_resolution_trampoline = ith_quick_resolution_trampoline; data.quick_imt_conflict_trampoline = ith_quick_imt_conflict_trampoline; data.quick_generic_jni_trampoline = ith_quick_generic_jni_trampoline; data.quick_to_interpreter_bridge_trampoline = ith_quick_to_interpreter_bridge_trampoline; ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_); spaces[i]->GetLiveBitmap()->Walk(CheckTrampolines, &data); if (data.error) { ArtMethod* m = data.m; LOG(ERROR) << "Found a broken ArtMethod: " << ArtMethod::PrettyMethod(m); *error_msg = "Found an ArtMethod with a bad entrypoint"; return false; } } } } class_roots_ = GcRoot
>( down_cast
*>( spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots))); mirror::Class::SetClassClass(class_roots_.Read()->Get(kJavaLangClass)); // Special case of setting up the String class early so that we can test arbitrary objects // as being Strings or not mirror::String::SetClass(GetClassRoot(kJavaLangString)); ObjPtr
java_lang_Object = GetClassRoot(kJavaLangObject); java_lang_Object->SetObjectSize(sizeof(mirror::Object)); // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been // cleared without triggering the read barrier and unintentionally mark the sentinel alive. runtime->SetSentinel(heap->AllocNonMovableObject
( self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor())); // reinit array_iftable_ from any array class instance, they should be == array_iftable_ = GcRoot
(GetClassRoot(kObjectArrayClass)->GetIfTable()); DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable()); // String class root was set above mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField)); mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass)); mirror::Constructor::SetClass(GetClassRoot(kJavaLangReflectConstructor)); mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass)); mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod)); mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass)); mirror::MethodType::SetClass(GetClassRoot(kJavaLangInvokeMethodType)); mirror::MethodHandleImpl::SetClass(GetClassRoot(kJavaLangInvokeMethodHandleImpl)); mirror::MethodHandlesLookup::SetClass(GetClassRoot(kJavaLangInvokeMethodHandlesLookup)); mirror::CallSite::SetClass(GetClassRoot(kJavaLangInvokeCallSite)); mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference)); mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); mirror::CharArray::SetArrayClass(GetClassRoot(kCharArrayClass)); mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass)); mirror::IntArray::SetArrayClass(GetClassRoot(kIntArrayClass)); mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass)); mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass)); mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable)); mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement)); mirror::EmulatedStackFrame::SetClass(GetClassRoot(kDalvikSystemEmulatedStackFrame)); mirror::ClassExt::SetClass(GetClassRoot(kDalvikSystemClassExt)); for (gc::space::ImageSpace* image_space : spaces) { // Boot class loader, use a null handle. std::vector
> dex_files; if (!AddImageSpace(image_space, ScopedNullHandle
(), /*dex_elements*/nullptr, /*dex_location*/nullptr, /*out*/&dex_files, error_msg)) { return false; } // Append opened dex files at the end. boot_dex_files_.insert(boot_dex_files_.end(), std::make_move_iterator(dex_files.begin()), std::make_move_iterator(dex_files.end())); } FinishInit(self); VLOG(startup) << __FUNCTION__ << " exiting"; return true; } bool ClassLinker::IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa, ObjPtr
class_loader) { return class_loader == nullptr || soa.Decode
(WellKnownClasses::java_lang_BootClassLoader) == class_loader->GetClass(); } static bool GetDexPathListElementName(ObjPtr
element, ObjPtr
* out_name) REQUIRES_SHARED(Locks::mutator_lock_) { ArtField* const dex_file_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile); ArtField* const dex_file_name_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_fileName); DCHECK(dex_file_field != nullptr); DCHECK(dex_file_name_field != nullptr); DCHECK(element != nullptr); CHECK_EQ(dex_file_field->GetDeclaringClass(), element->GetClass()) << element->PrettyTypeOf(); ObjPtr
dex_file = dex_file_field->GetObject(element); if (dex_file == nullptr) { // Null dex file means it was probably a jar with no dex files, return a null string. *out_name = nullptr; return true; } ObjPtr
name_object = dex_file_name_field->GetObject(dex_file); if (name_object != nullptr) { *out_name = name_object->AsString(); return true; } return false; } static bool FlattenPathClassLoader(ObjPtr
class_loader, std::list
>* out_dex_file_names, std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(out_dex_file_names != nullptr); DCHECK(error_msg != nullptr); ScopedObjectAccessUnchecked soa(Thread::Current()); ArtField* const dex_path_list_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList); ArtField* const dex_elements_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements); CHECK(dex_path_list_field != nullptr); CHECK(dex_elements_field != nullptr); while (!ClassLinker::IsBootClassLoader(soa, class_loader)) { if (soa.Decode
(WellKnownClasses::dalvik_system_PathClassLoader) != class_loader->GetClass()) { *error_msg = StringPrintf("Unknown class loader type %s", class_loader->PrettyTypeOf().c_str()); // Unsupported class loader. return false; } ObjPtr
dex_path_list = dex_path_list_field->GetObject(class_loader); if (dex_path_list != nullptr) { // DexPathList has an array dexElements of Elements[] which each contain a dex file. ObjPtr
dex_elements_obj = dex_elements_field->GetObject(dex_path_list); // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look // at the mCookie which is a DexFile vector. if (dex_elements_obj != nullptr) { ObjPtr
> dex_elements = dex_elements_obj->AsObjectArray
(); // Reverse order since we insert the parent at the front. for (int32_t i = dex_elements->GetLength() - 1; i >= 0; --i) { ObjPtr
element = dex_elements->GetWithoutChecks(i); if (element == nullptr) { *error_msg = StringPrintf("Null dex element at index %d", i); return false; } ObjPtr
name; if (!GetDexPathListElementName(element, &name)) { *error_msg = StringPrintf("Invalid dex path list element at index %d", i); return false; } if (name != nullptr) { out_dex_file_names->push_front(name.Ptr()); } } } } class_loader = class_loader->GetParent(); } return true; } class FixupArtMethodArrayVisitor : public ArtMethodVisitor { public: explicit FixupArtMethodArrayVisitor(const ImageHeader& header) : header_(header) {} virtual void Visit(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { const bool is_copied = method->IsCopied(); ArtMethod** resolved_methods = method->GetDexCacheResolvedMethods(kRuntimePointerSize); if (resolved_methods != nullptr) { bool in_image_space = false; if (kIsDebugBuild || is_copied) { in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains( reinterpret_cast
(resolved_methods) - header_.GetImageBegin()); } // Must be in image space for non-miranda method. DCHECK(is_copied || in_image_space) << resolved_methods << " is not in image starting at " << reinterpret_cast
(header_.GetImageBegin()); if (!is_copied || in_image_space) { method->SetDexCacheResolvedMethods(method->GetDexCache()->GetResolvedMethods(), kRuntimePointerSize); } } } private: const ImageHeader& header_; }; class VerifyClassInTableArtMethodVisitor : public ArtMethodVisitor { public: explicit VerifyClassInTableArtMethodVisitor(ClassTable* table) : table_(table) {} virtual void Visit(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_, Locks::classlinker_classes_lock_) { ObjPtr
klass = method->GetDeclaringClass(); if (klass != nullptr && !Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) { CHECK_EQ(table_->LookupByDescriptor(klass), klass) << mirror::Class::PrettyClass(klass); } } private: ClassTable* const table_; }; class VerifyDirectInterfacesInTableClassVisitor { public: explicit VerifyDirectInterfacesInTableClassVisitor(ObjPtr
class_loader) : class_loader_(class_loader), self_(Thread::Current()) { } bool operator()(ObjPtr
klass) REQUIRES_SHARED(Locks::mutator_lock_) { if (!klass->IsPrimitive() && klass->GetClassLoader() == class_loader_) { classes_.push_back(klass); } return true; } void Check() const REQUIRES_SHARED(Locks::mutator_lock_) { for (ObjPtr
klass : classes_) { for (uint32_t i = 0, num = klass->NumDirectInterfaces(); i != num; ++i) { CHECK(klass->GetDirectInterface(self_, klass, i) != nullptr) << klass->PrettyDescriptor() << " iface #" << i; } } } private: ObjPtr
class_loader_; Thread* self_; std::vector
> classes_; }; class VerifyDeclaringClassVisitor : public ArtMethodVisitor { public: VerifyDeclaringClassVisitor() REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) : live_bitmap_(Runtime::Current()->GetHeap()->GetLiveBitmap()) {} virtual void Visit(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) { ObjPtr
klass = method->GetDeclaringClassUnchecked(); if (klass != nullptr) { CHECK(live_bitmap_->Test(klass.Ptr())) << "Image method has unmarked declaring class"; } } private: gc::accounting::HeapBitmap* const live_bitmap_; }; // Copies data from one array to another array at the same position // if pred returns false. If there is a page of continuous data in // the src array for which pred consistently returns true then // corresponding page in the dst array will not be touched. // This should reduce number of allocated physical pages. template
static void CopyNonNull(const T* src, size_t count, T* dst, const NullPred& pred) { for (size_t i = 0; i < count; ++i) { if (!pred(src[i])) { dst[i] = src[i]; } } } template
static void CopyDexCachePairs(const std::atomic
>* src, size_t count, std::atomic
>* dst) { DCHECK_NE(count, 0u); DCHECK(!src[0].load(std::memory_order_relaxed).object.IsNull() || src[0].load(std::memory_order_relaxed).index != 0u); for (size_t i = 0; i < count; ++i) { DCHECK_EQ(dst[i].load(std::memory_order_relaxed).index, 0u); DCHECK(dst[i].load(std::memory_order_relaxed).object.IsNull()); mirror::DexCachePair
source = src[i].load(std::memory_order_relaxed); if (source.index != 0u || !source.object.IsNull()) { dst[i].store(source, std::memory_order_relaxed); } } } bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( gc::space::ImageSpace* space, Handle
class_loader, Handle
> dex_caches, ClassTable::ClassSet* new_class_set, bool* out_forward_dex_cache_array, std::string* out_error_msg) { DCHECK(out_forward_dex_cache_array != nullptr); DCHECK(out_error_msg != nullptr); Thread* const self = Thread::Current(); gc::Heap* const heap = Runtime::Current()->GetHeap(); const ImageHeader& header = space->GetImageHeader(); { // Add image classes into the class table for the class loader, and fixup the dex caches and // class loader fields. WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); // Dex cache array fixup is all or nothing, we must reject app images that have mixed since we // rely on clobering the dex cache arrays in the image to forward to bss. size_t num_dex_caches_with_bss_arrays = 0; const size_t num_dex_caches = dex_caches->GetLength(); for (size_t i = 0; i < num_dex_caches; i++) { ObjPtr
const dex_cache = dex_caches->Get(i); const DexFile* const dex_file = dex_cache->GetDexFile(); const OatFile::OatDexFile* oat_dex_file = dex_file->GetOatDexFile(); if (oat_dex_file != nullptr && oat_dex_file->GetDexCacheArrays() != nullptr) { ++num_dex_caches_with_bss_arrays; } } *out_forward_dex_cache_array = num_dex_caches_with_bss_arrays != 0; if (*out_forward_dex_cache_array) { if (num_dex_caches_with_bss_arrays != num_dex_caches) { // Reject application image since we cannot forward only some of the dex cache arrays. // TODO: We could get around this by having a dedicated forwarding slot. It should be an // uncommon case. *out_error_msg = StringPrintf("Dex caches in bss does not match total: %zu vs %zu", num_dex_caches_with_bss_arrays, num_dex_caches); return false; } } // Only add the classes to the class loader after the points where we can return false. for (size_t i = 0; i < num_dex_caches; i++) { ObjPtr
dex_cache = dex_caches->Get(i); const DexFile* const dex_file = dex_cache->GetDexFile(); const OatFile::OatDexFile* oat_dex_file = dex_file->GetOatDexFile(); if (oat_dex_file != nullptr && oat_dex_file->GetDexCacheArrays() != nullptr) { // If the oat file expects the dex cache arrays to be in the BSS, then allocate there and // copy over the arrays. DCHECK(dex_file != nullptr); size_t num_strings = mirror::DexCache::kDexCacheStringCacheSize; if (dex_file->NumStringIds() < num_strings) { num_strings = dex_file->NumStringIds(); } size_t num_types = mirror::DexCache::kDexCacheTypeCacheSize; if (dex_file->NumTypeIds() < num_types) { num_types = dex_file->NumTypeIds(); } const size_t num_methods = dex_file->NumMethodIds(); size_t num_fields = mirror::DexCache::kDexCacheFieldCacheSize; if (dex_file->NumFieldIds() < num_fields) { num_fields = dex_file->NumFieldIds(); } size_t num_method_types = mirror::DexCache::kDexCacheMethodTypeCacheSize; if (dex_file->NumProtoIds() < num_method_types) { num_method_types = dex_file->NumProtoIds(); } const size_t num_call_sites = dex_file->NumCallSiteIds(); CHECK_EQ(num_strings, dex_cache->NumStrings()); CHECK_EQ(num_types, dex_cache->NumResolvedTypes()); CHECK_EQ(num_methods, dex_cache->NumResolvedMethods()); CHECK_EQ(num_fields, dex_cache->NumResolvedFields()); CHECK_EQ(num_method_types, dex_cache->NumResolvedMethodTypes()); CHECK_EQ(num_call_sites, dex_cache->NumResolvedCallSites()); DexCacheArraysLayout layout(image_pointer_size_, dex_file); uint8_t* const raw_arrays = oat_dex_file->GetDexCacheArrays(); if (num_strings != 0u) { mirror::StringDexCacheType* const image_resolved_strings = dex_cache->GetStrings(); mirror::StringDexCacheType* const strings = reinterpret_cast
(raw_arrays + layout.StringsOffset()); CopyDexCachePairs(image_resolved_strings, num_strings, strings); dex_cache->SetStrings(strings); } if (num_types != 0u) { mirror::TypeDexCacheType* const image_resolved_types = dex_cache->GetResolvedTypes(); mirror::TypeDexCacheType* const types = reinterpret_cast
(raw_arrays + layout.TypesOffset()); CopyDexCachePairs(image_resolved_types, num_types, types); dex_cache->SetResolvedTypes(types); } if (num_methods != 0u) { ArtMethod** const methods = reinterpret_cast
( raw_arrays + layout.MethodsOffset()); ArtMethod** const image_resolved_methods = dex_cache->GetResolvedMethods(); for (size_t j = 0; kIsDebugBuild && j < num_methods; ++j) { DCHECK(methods[j] == nullptr); } CopyNonNull(image_resolved_methods, num_methods, methods, [] (const ArtMethod* method) { return method == nullptr; }); dex_cache->SetResolvedMethods(methods); } if (num_fields != 0u) { mirror::FieldDexCacheType* const image_resolved_fields = dex_cache->GetResolvedFields(); mirror::FieldDexCacheType* const fields = reinterpret_cast
(raw_arrays + layout.FieldsOffset()); for (size_t j = 0; j < num_fields; ++j) { DCHECK_EQ(mirror::DexCache::GetNativePairPtrSize(fields, j, image_pointer_size_).index, 0u); DCHECK(mirror::DexCache::GetNativePairPtrSize(fields, j, image_pointer_size_).object == nullptr); mirror::DexCache::SetNativePairPtrSize( fields, j, mirror::DexCache::GetNativePairPtrSize(image_resolved_fields, j, image_pointer_size_), image_pointer_size_); } dex_cache->SetResolvedFields(fields); } if (num_method_types != 0u) { // NOTE: We currently (Sep 2016) do not resolve any method types at // compile time, but plan to in the future. This code exists for the // sake of completeness. mirror::MethodTypeDexCacheType* const image_resolved_method_types = dex_cache->GetResolvedMethodTypes(); mirror::MethodTypeDexCacheType* const method_types = reinterpret_cast
( raw_arrays + layout.MethodTypesOffset()); CopyDexCachePairs(image_resolved_method_types, num_method_types, method_types); dex_cache->SetResolvedMethodTypes(method_types); } if (num_call_sites != 0u) { GcRoot
* const image_resolved_call_sites = dex_cache->GetResolvedCallSites(); GcRoot
* const call_sites = reinterpret_cast
*>(raw_arrays + layout.CallSitesOffset()); for (size_t j = 0; kIsDebugBuild && j < num_call_sites; ++j) { DCHECK(call_sites[j].IsNull()); } CopyNonNull(image_resolved_call_sites, num_call_sites, call_sites, [](const GcRoot
& elem) { return elem.IsNull(); }); dex_cache->SetResolvedCallSites(call_sites); } } { WriterMutexLock mu2(self, *Locks::dex_lock_); // Make sure to do this after we update the arrays since we store the resolved types array // in DexCacheData in RegisterDexFileLocked. We need the array pointer to be the one in the // BSS. CHECK(!FindDexCacheDataLocked(*dex_file).IsValid()); RegisterDexFileLocked(*dex_file, dex_cache, class_loader.Get()); } if (kIsDebugBuild) { CHECK(new_class_set != nullptr); mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); const size_t num_types = dex_cache->NumResolvedTypes(); for (size_t j = 0; j != num_types; ++j) { // The image space is not yet added to the heap, avoid read barriers. ObjPtr
klass = types[j].load(std::memory_order_relaxed).object.Read(); if (space->HasAddress(klass.Ptr())) { DCHECK(!klass->IsErroneous()) << klass->GetStatus(); auto it = new_class_set->Find(ClassTable::TableSlot(klass)); DCHECK(it != new_class_set->end()); DCHECK_EQ(it->Read(), klass); ObjPtr
super_class = klass->GetSuperClass(); if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) { auto it2 = new_class_set->Find(ClassTable::TableSlot(super_class)); DCHECK(it2 != new_class_set->end()); DCHECK_EQ(it2->Read(), super_class); } for (ArtMethod& m : klass->GetDirectMethods(kRuntimePointerSize)) { const void* code = m.GetEntryPointFromQuickCompiledCode(); const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code; if (!IsQuickResolutionStub(code) && !IsQuickGenericJniStub(code) && !IsQuickToInterpreterBridge(code) && !m.IsNative()) { DCHECK_EQ(code, oat_code) << m.PrettyMethod(); } } for (ArtMethod& m : klass->GetVirtualMethods(kRuntimePointerSize)) { const void* code = m.GetEntryPointFromQuickCompiledCode(); const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code; if (!IsQuickResolutionStub(code) && !IsQuickGenericJniStub(code) && !IsQuickToInterpreterBridge(code) && !m.IsNative()) { DCHECK_EQ(code, oat_code) << m.PrettyMethod(); } } } } } } } if (*out_forward_dex_cache_array) { ScopedTrace timing("Fixup ArtMethod dex cache arrays"); FixupArtMethodArrayVisitor visitor(header); header.VisitPackedArtMethods(&visitor, space->Begin(), kRuntimePointerSize); Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get()); } if (kVerifyArtMethodDeclaringClasses) { ScopedTrace timing("Verify declaring classes"); ReaderMutexLock rmu(self, *Locks::heap_bitmap_lock_); VerifyDeclaringClassVisitor visitor; header.VisitPackedArtMethods(&visitor, space->Begin(), kRuntimePointerSize); } return true; } // Update the class loader. Should only be used on classes in the image space. class UpdateClassLoaderVisitor { public: UpdateClassLoaderVisitor(gc::space::ImageSpace* space, ObjPtr
class_loader) : space_(space), class_loader_(class_loader) {} bool operator()(ObjPtr
klass) const REQUIRES_SHARED(Locks::mutator_lock_) { // Do not update class loader for boot image classes where the app image // class loader is only the initiating loader but not the defining loader. if (klass->GetClassLoader() != nullptr) { klass->SetClassLoader(class_loader_); } return true; } gc::space::ImageSpace* const space_; ObjPtr
const class_loader_; }; static std::unique_ptr
OpenOatDexFile(const OatFile* oat_file, const char* location, std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(error_msg != nullptr); std::unique_ptr
dex_file; const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(location, nullptr, error_msg); if (oat_dex_file == nullptr) { return std::unique_ptr
(); } std::string inner_error_msg; dex_file = oat_dex_file->OpenDexFile(&inner_error_msg); if (dex_file == nullptr) { *error_msg = StringPrintf("Failed to open dex file %s from within oat file %s error '%s'", location, oat_file->GetLocation().c_str(), inner_error_msg.c_str()); return std::unique_ptr
(); } if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) { *error_msg = StringPrintf("Checksums do not match for %s: %x vs %x", location, dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum()); return std::unique_ptr
(); } return dex_file; } bool ClassLinker::OpenImageDexFiles(gc::space::ImageSpace* space, std::vector
>* out_dex_files, std::string* error_msg) { ScopedAssertNoThreadSuspension nts(__FUNCTION__); const ImageHeader& header = space->GetImageHeader(); ObjPtr
dex_caches_object = header.GetImageRoot(ImageHeader::kDexCaches); DCHECK(dex_caches_object != nullptr); mirror::ObjectArray
* dex_caches = dex_caches_object->AsObjectArray
(); const OatFile* oat_file = space->GetOatFile(); for (int32_t i = 0; i < dex_caches->GetLength(); i++) { ObjPtr
dex_cache = dex_caches->Get(i); std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8()); std::unique_ptr
dex_file = OpenOatDexFile(oat_file, dex_file_location.c_str(), error_msg); if (dex_file == nullptr) { return false; } dex_cache->SetDexFile(dex_file.get()); out_dex_files->push_back(std::move(dex_file)); } return true; } // Helper class for ArtMethod checks when adding an image. Keeps all required functionality // together and caches some intermediate results. class ImageSanityChecks FINAL { public: static void CheckObjects(gc::Heap* heap, ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_) { ImageSanityChecks isc(heap, class_linker); heap->VisitObjects(ImageSanityChecks::SanityCheckObjectsCallback, &isc); } static void CheckPointerArray(gc::Heap* heap, ClassLinker* class_linker, ArtMethod** arr, size_t size) REQUIRES_SHARED(Locks::mutator_lock_) { ImageSanityChecks isc(heap, class_linker); isc.SanityCheckArtMethodPointerArray(arr, size); } static void SanityCheckObjectsCallback(mirror::Object* obj, void* arg) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(obj != nullptr); CHECK(obj->GetClass() != nullptr) << "Null class in object " << obj; CHECK(obj->GetClass()->GetClass() != nullptr) << "Null class class " << obj; if (obj->IsClass()) { ImageSanityChecks* isc = reinterpret_cast
(arg); auto klass = obj->AsClass(); for (ArtField& field : klass->GetIFields()) { CHECK_EQ(field.GetDeclaringClass(), klass); } for (ArtField& field : klass->GetSFields()) { CHECK_EQ(field.GetDeclaringClass(), klass); } const auto pointer_size = isc->pointer_size_; for (auto& m : klass->GetMethods(pointer_size)) { isc->SanityCheckArtMethod(&m, klass); } auto* vtable = klass->GetVTable(); if (vtable != nullptr) { isc->SanityCheckArtMethodPointerArray(vtable, nullptr); } if (klass->ShouldHaveImt()) { ImTable* imt = klass->GetImt(pointer_size); for (size_t i = 0; i < ImTable::kSize; ++i) { isc->SanityCheckArtMethod(imt->Get(i, pointer_size), nullptr); } } if (klass->ShouldHaveEmbeddedVTable()) { for (int32_t i = 0; i < klass->GetEmbeddedVTableLength(); ++i) { isc->SanityCheckArtMethod(klass->GetEmbeddedVTableEntry(i, pointer_size), nullptr); } } mirror::IfTable* iftable = klass->GetIfTable(); for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { if (iftable->GetMethodArrayCount(i) > 0) { isc->SanityCheckArtMethodPointerArray(iftable->GetMethodArray(i), nullptr); } } } } private: ImageSanityChecks(gc::Heap* heap, ClassLinker* class_linker) : spaces_(heap->GetBootImageSpaces()), pointer_size_(class_linker->GetImagePointerSize()) { space_begin_.reserve(spaces_.size()); method_sections_.reserve(spaces_.size()); runtime_method_sections_.reserve(spaces_.size()); for (gc::space::ImageSpace* space : spaces_) { space_begin_.push_back(space->Begin()); auto& header = space->GetImageHeader(); method_sections_.push_back(&header.GetMethodsSection()); runtime_method_sections_.push_back(&header.GetRuntimeMethodsSection()); } } void SanityCheckArtMethod(ArtMethod* m, ObjPtr
expected_class) REQUIRES_SHARED(Locks::mutator_lock_) { if (m->IsRuntimeMethod()) { ObjPtr
declaring_class = m->GetDeclaringClassUnchecked(); CHECK(declaring_class == nullptr) << declaring_class << " " << m->PrettyMethod(); } else if (m->IsCopied()) { CHECK(m->GetDeclaringClass() != nullptr) << m->PrettyMethod(); } else if (expected_class != nullptr) { CHECK_EQ(m->GetDeclaringClassUnchecked(), expected_class) << m->PrettyMethod(); } if (!spaces_.empty()) { bool contains = false; for (size_t i = 0; !contains && i != space_begin_.size(); ++i) { const size_t offset = reinterpret_cast
(m) - space_begin_[i]; contains = method_sections_[i]->Contains(offset) || runtime_method_sections_[i]->Contains(offset); } CHECK(contains) << m << " not found"; } } void SanityCheckArtMethodPointerArray(ObjPtr
arr, ObjPtr
expected_class) REQUIRES_SHARED(Locks::mutator_lock_) { CHECK(arr != nullptr); for (int32_t j = 0; j < arr->GetLength(); ++j) { auto* method = arr->GetElementPtrSize
(j, pointer_size_); // expected_class == null means we are a dex cache. if (expected_class != nullptr) { CHECK(method != nullptr); } if (method != nullptr) { SanityCheckArtMethod(method, expected_class); } } } void SanityCheckArtMethodPointerArray(ArtMethod** arr, size_t size) REQUIRES_SHARED(Locks::mutator_lock_) { CHECK_EQ(arr != nullptr, size != 0u); if (arr != nullptr) { bool contains = false; for (auto space : spaces_) { auto offset = reinterpret_cast
(arr) - space->Begin(); if (space->GetImageHeader().GetImageSection( ImageHeader::kSectionDexCacheArrays).Contains(offset)) { contains = true; break; } } CHECK(contains); } for (size_t j = 0; j < size; ++j) { ArtMethod* method = mirror::DexCache::GetElementPtrSize(arr, j, pointer_size_); // expected_class == null means we are a dex cache. if (method != nullptr) { SanityCheckArtMethod(method, nullptr); } } } const std::vector
& spaces_; const PointerSize pointer_size_; // Cached sections from the spaces. std::vector
space_begin_; std::vector
method_sections_; std::vector
runtime_method_sections_; }; bool ClassLinker::AddImageSpace( gc::space::ImageSpace* space, Handle
class_loader, jobjectArray dex_elements, const char* dex_location, std::vector
>* out_dex_files, std::string* error_msg) { DCHECK(out_dex_files != nullptr); DCHECK(error_msg != nullptr); const uint64_t start_time = NanoTime(); const bool app_image = class_loader != nullptr; const ImageHeader& header = space->GetImageHeader(); ObjPtr
dex_caches_object = header.GetImageRoot(ImageHeader::kDexCaches); DCHECK(dex_caches_object != nullptr); Runtime* const runtime = Runtime::Current(); gc::Heap* const heap = runtime->GetHeap(); Thread* const self = Thread::Current(); // Check that the image is what we are expecting. if (image_pointer_size_ != space->GetImageHeader().GetPointerSize()) { *error_msg = StringPrintf("Application image pointer size does not match runtime: %zu vs %zu", static_cast
(space->GetImageHeader().GetPointerSize()), image_pointer_size_); return false; } size_t expected_image_roots = ImageHeader::NumberOfImageRoots(app_image); if (static_cast
(header.GetImageRoots()->GetLength()) != expected_image_roots) { *error_msg = StringPrintf("Expected %zu image roots but got %d", expected_image_roots, header.GetImageRoots()->GetLength()); return false; } StackHandleScope<3> hs(self); Handle
> dex_caches( hs.NewHandle(dex_caches_object->AsObjectArray
())); Handle
> class_roots(hs.NewHandle( header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray
())); static_assert(ImageHeader::kClassLoader + 1u == ImageHeader::kImageRootsMax, "Class loader should be the last image root."); MutableHandle
image_class_loader(hs.NewHandle( app_image ? header.GetImageRoot(ImageHeader::kClassLoader)->AsClassLoader() : nullptr)); DCHECK(class_roots != nullptr); if (class_roots->GetLength() != static_cast
(kClassRootsMax)) { *error_msg = StringPrintf("Expected %d class roots but got %d", class_roots->GetLength(), static_cast
(kClassRootsMax)); return false; } // Check against existing class roots to make sure they match the ones in the boot image. for (size_t i = 0; i < kClassRootsMax; i++) { if (class_roots->Get(i) != GetClassRoot(static_cast
(i))) { *error_msg = "App image class roots must have pointer equality with runtime ones."; return false; } } const OatFile* oat_file = space->GetOatFile(); if (oat_file->GetOatHeader().GetDexFileCount() != static_cast
(dex_caches->GetLength())) { *error_msg = "Dex cache count and dex file count mismatch while trying to initialize from " "image"; return false; } for (int32_t i = 0; i < dex_caches->GetLength(); i++) { ObjPtr
dex_cache = dex_caches->Get(i); std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8()); // TODO: Only store qualified paths. // If non qualified, qualify it. if (dex_file_location.find('/') == std::string::npos) { std::string dex_location_path = dex_location; const size_t pos = dex_location_path.find_last_of('/'); CHECK_NE(pos, std::string::npos); dex_location_path = dex_location_path.substr(0, pos + 1); // Keep trailing '/' dex_file_location = dex_location_path + dex_file_location; } std::unique_ptr
dex_file = OpenOatDexFile(oat_file, dex_file_location.c_str(), error_msg); if (dex_file == nullptr) { return false; } if (app_image) { // The current dex file field is bogus, overwrite it so that we can get the dex file in the // loop below. dex_cache->SetDexFile(dex_file.get()); mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) { ObjPtr
klass = types[j].load(std::memory_order_relaxed).object.Read(); if (klass != nullptr) { DCHECK(!klass->IsErroneous()) << klass->GetStatus(); } } } else { if (kSanityCheckObjects) { ImageSanityChecks::CheckPointerArray(heap, this, dex_cache->GetResolvedMethods(), dex_cache->NumResolvedMethods()); } // Register dex files, keep track of existing ones that are conflicts. AppendToBootClassPath(*dex_file.get(), dex_cache); } out_dex_files->push_back(std::move(dex_file)); } if (app_image) { ScopedObjectAccessUnchecked soa(Thread::Current()); // Check that the class loader resolves the same way as the ones in the image. // Image class loader [A][B][C][image dex files] // Class loader = [???][dex_elements][image dex files] // Need to ensure that [???][dex_elements] == [A][B][C]. // For each class loader, PathClassLoader, the laoder checks the parent first. Also the logic // for PathClassLoader does this by looping through the array of dex files. To ensure they // resolve the same way, simply flatten the hierarchy in the way the resolution order would be, // and check that the dex file names are the same. if (IsBootClassLoader(soa, image_class_loader.Get())) { *error_msg = "Unexpected BootClassLoader in app image"; return false; } std::list
> image_dex_file_names; std::string temp_error_msg; if (!FlattenPathClassLoader(image_class_loader.Get(), &image_dex_file_names, &temp_error_msg)) { *error_msg = StringPrintf("Failed to flatten image class loader hierarchy '%s'", temp_error_msg.c_str()); return false; } std::list
> loader_dex_file_names; if (!FlattenPathClassLoader(class_loader.Get(), &loader_dex_file_names, &temp_error_msg)) { *error_msg = StringPrintf("Failed to flatten class loader hierarchy '%s'", temp_error_msg.c_str()); return false; } // Add the temporary dex path list elements at the end. auto elements = soa.Decode
>(dex_elements); for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) { ObjPtr
element = elements->GetWithoutChecks(i); if (element != nullptr) { // If we are somewhere in the middle of the array, there may be nulls at the end. ObjPtr
name; if (GetDexPathListElementName(element, &name) && name != nullptr) { loader_dex_file_names.push_back(name); } } } // Ignore the number of image dex files since we are adding those to the class loader anyways. CHECK_GE(static_cast
(image_dex_file_names.size()), static_cast
(dex_caches->GetLength())); size_t image_count = image_dex_file_names.size() - dex_caches->GetLength(); // Check that the dex file names match. bool equal = image_count == loader_dex_file_names.size(); if (equal) { auto it1 = image_dex_file_names.begin(); auto it2 = loader_dex_file_names.begin(); for (size_t i = 0; equal && i < image_count; ++i, ++it1, ++it2) { equal = equal && (*it1)->Equals(*it2); } } if (!equal) { VLOG(image) << "Image dex files " << image_dex_file_names.size(); for (ObjPtr
name : image_dex_file_names) { VLOG(image) << name->ToModifiedUtf8(); } VLOG(image) << "Loader dex files " << loader_dex_file_names.size(); for (ObjPtr
name : loader_dex_file_names) { VLOG(image) << name->ToModifiedUtf8(); } *error_msg = "Rejecting application image due to class loader mismatch"; // Ignore class loader mismatch for now since these would just use possibly incorrect // oat code anyways. The structural class check should be done in the parent. } } if (kSanityCheckObjects) { for (int32_t i = 0; i < dex_caches->GetLength(); i++) { auto* dex_cache = dex_caches->Get(i); for (size_t j = 0; j < dex_cache->NumResolvedFields(); ++j) { auto* field = dex_cache->GetResolvedField(j, image_pointer_size_); if (field != nullptr) { CHECK(field->GetDeclaringClass()->GetClass() != nullptr); } } } if (!app_image) { ImageSanityChecks::CheckObjects(heap, this); } } // Set entry point to interpreter if in InterpretOnly mode. if (!runtime->IsAotCompiler() && runtime->GetInstrumentation()->InterpretOnly()) { SetInterpreterEntrypointArtMethodVisitor visitor(image_pointer_size_); header.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_); } ClassTable* class_table = nullptr; { WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); class_table = InsertClassTableForClassLoader(class_loader.Get()); } // If we have a class table section, read it and use it for verification in // UpdateAppImageClassLoadersAndDexCaches. ClassTable::ClassSet temp_set; const ImageSection& class_table_section = header.GetImageSection(ImageHeader::kSectionClassTable); const bool added_class_table = class_table_section.Size() > 0u; if (added_class_table) { const uint64_t start_time2 = NanoTime(); size_t read_count = 0; temp_set = ClassTable::ClassSet(space->Begin() + class_table_section.Offset(), /*make copy*/false, &read_count); VLOG(image) << "Adding class table classes took " << PrettyDuration(NanoTime() - start_time2); } if (app_image) { bool forward_dex_cache_arrays = false; if (!UpdateAppImageClassLoadersAndDexCaches(space, class_loader, dex_caches, &temp_set, /*out*/&forward_dex_cache_arrays, /*out*/error_msg)) { return false; } // Update class loader and resolved strings. If added_class_table is false, the resolved // strings were forwarded UpdateAppImageClassLoadersAndDexCaches. UpdateClassLoaderVisitor visitor(space, class_loader.Get()); for (const ClassTable::TableSlot& root : temp_set) { visitor(root.Read()); } // forward_dex_cache_arrays is true iff we copied all of the dex cache arrays into the .bss. // In this case, madvise away the dex cache arrays section of the image to reduce RAM usage and // mark as PROT_NONE to catch any invalid accesses. if (forward_dex_cache_arrays) { const ImageSection& dex_cache_section = header.GetImageSection( ImageHeader::kSectionDexCacheArrays); uint8_t* section_begin = AlignUp(space->Begin() + dex_cache_section.Offset(), kPageSize); uint8_t* section_end = AlignDown(space->Begin() + dex_cache_section.End(), kPageSize); if (section_begin < section_end) { madvise(section_begin, section_end - section_begin, MADV_DONTNEED); mprotect(section_begin, section_end - section_begin, PROT_NONE); VLOG(image) << "Released and protected dex cache array image section from " << reinterpret_cast
(section_begin) << "-" << reinterpret_cast
(section_end); } } } if (!oat_file->GetBssGcRoots().empty()) { // Insert oat file to class table for visiting .bss GC roots. class_table->InsertOatFile(oat_file); } if (added_class_table) { WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); class_table->AddClassSet(std::move(temp_set)); } if (kIsDebugBuild && app_image) { // This verification needs to happen after the classes have been added to the class loader. // Since it ensures classes are in the class table. VerifyClassInTableArtMethodVisitor visitor2(class_table); header.VisitPackedArtMethods(&visitor2, space->Begin(), kRuntimePointerSize); // Verify that all direct interfaces of classes in the class table are also resolved. VerifyDirectInterfacesInTableClassVisitor visitor(class_loader.Get()); class_table->Visit(visitor); visitor.Check(); // Check that all non-primitive classes in dex caches are also in the class table. for (int32_t i = 0; i < dex_caches->GetLength(); i++) { ObjPtr
dex_cache = dex_caches->Get(i); mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) { ObjPtr
klass = types[j].load(std::memory_order_relaxed).object.Read(); if (klass != nullptr && !klass->IsPrimitive()) { CHECK(class_table->Contains(klass)) << klass->PrettyDescriptor() << " " << dex_cache->GetDexFile()->GetLocation(); } } } } VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time); return true; } bool ClassLinker::ClassInClassTable(ObjPtr
klass) { ClassTable* const class_table = ClassTableForClassLoader(klass->GetClassLoader()); return class_table != nullptr && class_table->Contains(klass); } void ClassLinker::VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags) { // Acquire tracing_enabled before locking class linker lock to prevent lock order violation. Since // enabling tracing requires the mutator lock, there are no race conditions here. const bool tracing_enabled = Trace::IsTracingEnabled(); Thread* const self = Thread::Current(); WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); if (kUseReadBarrier) { // We do not track new roots for CC. DCHECK_EQ(0, flags & (kVisitRootFlagNewRoots | kVisitRootFlagClearRootLog | kVisitRootFlagStartLoggingNewRoots | kVisitRootFlagStopLoggingNewRoots)); } if ((flags & kVisitRootFlagAllRoots) != 0) { // Argument for how root visiting deals with ArtField and ArtMethod roots. // There is 3 GC cases to handle: // Non moving concurrent: // This case is easy to handle since the reference members of ArtMethod and ArtFields are held // live by the class and class roots. // // Moving non-concurrent: // This case needs to call visit VisitNativeRoots in case the classes or dex cache arrays move. // To prevent missing roots, this case needs to ensure that there is no // suspend points between the point which we allocate ArtMethod arrays and place them in a // class which is in the class table. // // Moving concurrent: // Need to make sure to not copy ArtMethods without doing read barriers since the roots are // marked concurrently and we don't hold the classlinker_classes_lock_ when we do the copy. // // Use an unbuffered visitor since the class table uses a temporary GcRoot for holding decoded // ClassTable::TableSlot. The buffered root visiting would access a stale stack location for // these objects. UnbufferedRootVisitor root_visitor(visitor, RootInfo(kRootStickyClass)); boot_class_table_.VisitRoots(root_visitor); // If tracing is enabled, then mark all the class loaders to prevent unloading. if ((flags & kVisitRootFlagClassLoader) != 0 || tracing_enabled) { for (const ClassLoaderData& data : class_loaders_) { GcRoot
root(GcRoot
(self->DecodeJObject(data.weak_root))); root.VisitRoot(visitor, RootInfo(kRootVMInternal)); } } } else if (!kUseReadBarrier && (flags & kVisitRootFlagNewRoots) != 0) { for (auto& root : new_class_roots_) { ObjPtr
old_ref = root.Read
(); root.VisitRoot(visitor, RootInfo(kRootStickyClass)); ObjPtr
new_ref = root.Read
(); // Concurrent moving GC marked new roots through the to-space invariant. CHECK_EQ(new_ref, old_ref); } for (const OatFile* oat_file : new_bss_roots_boot_oat_files_) { for (GcRoot
& root : oat_file->GetBssGcRoots()) { ObjPtr
old_ref = root.Read
(); if (old_ref != nullptr) { DCHECK(old_ref->IsClass()); root.VisitRoot(visitor, RootInfo(kRootStickyClass)); ObjPtr
new_ref = root.Read
(); // Concurrent moving GC marked new roots through the to-space invariant. CHECK_EQ(new_ref, old_ref); } } } } if (!kUseReadBarrier && (flags & kVisitRootFlagClearRootLog) != 0) { new_class_roots_.clear(); new_bss_roots_boot_oat_files_.clear(); } if (!kUseReadBarrier && (flags & kVisitRootFlagStartLoggingNewRoots) != 0) { log_new_roots_ = true; } else if (!kUseReadBarrier && (flags & kVisitRootFlagStopLoggingNewRoots) != 0) { log_new_roots_ = false; } // We deliberately ignore the class roots in the image since we // handle image roots by using the MS/CMS rescanning of dirty cards. } // Keep in sync with InitCallback. Anything we visit, we need to // reinit references to when reinitializing a ClassLinker from a // mapped image. void ClassLinker::VisitRoots(RootVisitor* visitor, VisitRootFlags flags) { class_roots_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal)); VisitClassRoots(visitor, flags); array_iftable_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal)); // Instead of visiting the find_array_class_cache_ drop it so that it doesn't prevent class // unloading if we are marking roots. DropFindArrayClassCache(); } class VisitClassLoaderClassesVisitor : public ClassLoaderVisitor { public: explicit VisitClassLoaderClassesVisitor(ClassVisitor* visitor) : visitor_(visitor), done_(false) {} void Visit(ObjPtr
class_loader) REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) OVERRIDE { ClassTable* const class_table = class_loader->GetClassTable(); if (!done_ && class_table != nullptr) { DefiningClassLoaderFilterVisitor visitor(class_loader, visitor_); if (!class_table->Visit(visitor)) { // If the visitor ClassTable returns false it means that we don't need to continue. done_ = true; } } } private: // Class visitor that limits the class visits from a ClassTable to the classes with // the provided defining class loader. This filter is used to avoid multiple visits // of the same class which can be recorded for multiple initiating class loaders. class DefiningClassLoaderFilterVisitor : public ClassVisitor { public: DefiningClassLoaderFilterVisitor(ObjPtr
defining_class_loader, ClassVisitor* visitor) : defining_class_loader_(defining_class_loader), visitor_(visitor) { } bool operator()(ObjPtr
klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { if (klass->GetClassLoader() != defining_class_loader_) { return true; } return (*visitor_)(klass); } ObjPtr
const defining_class_loader_; ClassVisitor* const visitor_; }; ClassVisitor* const visitor_; // If done is true then we don't need to do any more visiting. bool done_; }; void ClassLinker::VisitClassesInternal(ClassVisitor* visitor) { if (boot_class_table_.Visit(*visitor)) { VisitClassLoaderClassesVisitor loader_visitor(visitor); VisitClassLoaders(&loader_visitor); } } void ClassLinker::VisitClasses(ClassVisitor* visitor) { Thread* const self = Thread::Current(); ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); // Not safe to have thread suspension when we are holding a lock. if (self != nullptr) { ScopedAssertNoThreadSuspension nts(__FUNCTION__); VisitClassesInternal(visitor); } else { VisitClassesInternal(visitor); } } class GetClassesInToVector : public ClassVisitor { public: bool operator()(ObjPtr
klass) OVERRIDE { classes_.push_back(klass); return true; } std::vector
> classes_; }; class GetClassInToObjectArray : public ClassVisitor { public: explicit GetClassInToObjectArray(mirror::ObjectArray
* arr) : arr_(arr), index_(0) {} bool operator()(ObjPtr
klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { ++index_; if (index_ <= arr_->GetLength()) { arr_->Set(index_ - 1, klass); return true; } return false; } bool Succeeded() const REQUIRES_SHARED(Locks::mutator_lock_) { return index_ <= arr_->GetLength(); } private: mirror::ObjectArray
* const arr_; int32_t index_; }; void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor) { // TODO: it may be possible to avoid secondary storage if we iterate over dex caches. The problem // is avoiding duplicates. if (!kMovingClasses) { ScopedAssertNoThreadSuspension nts(__FUNCTION__); GetClassesInToVector accumulator; VisitClasses(&accumulator); for (ObjPtr
klass : accumulator.classes_) { if (!visitor->operator()(klass)) { return; } } } else { Thread* const self = Thread::Current(); StackHandleScope<1> hs(self); auto classes = hs.NewHandle
>(nullptr); // We size the array assuming classes won't be added to the class table during the visit. // If this assumption fails we iterate again. while (true) { size_t class_table_size; { ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); // Add 100 in case new classes get loaded when we are filling in the object array. class_table_size = NumZygoteClasses() + NumNonZygoteClasses() + 100; } ObjPtr
class_type = mirror::Class::GetJavaLangClass(); ObjPtr
array_of_class = FindArrayClass(self, &class_type); classes.Assign( mirror::ObjectArray
::Alloc(self, array_of_class, class_table_size)); CHECK(classes != nullptr); // OOME. GetClassInToObjectArray accumulator(classes.Get()); VisitClasses(&accumulator); if (accumulator.Succeeded()) { break; } } for (int32_t i = 0; i < classes->GetLength(); ++i) { // If the class table shrank during creation of the clases array we expect null elements. If // the class table grew then the loop repeats. If classes are created after the loop has // finished then we don't visit. ObjPtr
klass = classes->Get(i); if (klass != nullptr && !visitor->operator()(klass)) { return; } } } } ClassLinker::~ClassLinker() { mirror::Class::ResetClass(); mirror::Constructor::ResetClass(); mirror::Field::ResetClass(); mirror::Method::ResetClass(); mirror::Reference::ResetClass(); mirror::StackTraceElement::ResetClass(); mirror::String::ResetClass(); mirror::Throwable::ResetClass(); mirror::BooleanArray::ResetArrayClass(); mirror::ByteArray::ResetArrayClass(); mirror::CharArray::ResetArrayClass(); mirror::Constructor::ResetArrayClass(); mirror::DoubleArray::ResetArrayClass(); mirror::Field::ResetArrayClass(); mirror::FloatArray::ResetArrayClass(); mirror::Method::ResetArrayClass(); mirror::IntArray::ResetArrayClass(); mirror::LongArray::ResetArrayClass(); mirror::ShortArray::ResetArrayClass(); mirror::MethodType::ResetClass(); mirror::MethodHandleImpl::ResetClass(); mirror::MethodHandlesLookup::ResetClass(); mirror::CallSite::ResetClass(); mirror::EmulatedStackFrame::ResetClass(); Thread* const self = Thread::Current(); for (const ClassLoaderData& data : class_loaders_) { DeleteClassLoader(self, data); } class_loaders_.clear(); } void ClassLinker::DeleteClassLoader(Thread* self, const ClassLoaderData& data) { Runtime* const runtime = Runtime::Current(); JavaVMExt* const vm = runtime->GetJavaVM(); vm->DeleteWeakGlobalRef(self, data.weak_root); // Notify the JIT that we need to remove the methods and/or profiling info. if (runtime->GetJit() != nullptr) { jit::JitCodeCache* code_cache = runtime->GetJit()->GetCodeCache(); if (code_cache != nullptr) { code_cache->RemoveMethodsIn(self, *data.allocator); } } delete data.allocator; delete data.class_table; } mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length) { return down_cast
( image_pointer_size_ == PointerSize::k64 ? static_cast
(mirror::LongArray::Alloc(self, length)) : static_cast
(mirror::IntArray::Alloc(self, length))); } mirror::DexCache* ClassLinker::AllocDexCache(ObjPtr
* out_location, Thread* self, const DexFile& dex_file) { StackHandleScope<1> hs(self); DCHECK(out_location != nullptr); auto dex_cache(hs.NewHandle(ObjPtr
::DownCast( GetClassRoot(kJavaLangDexCache)->AllocObject(self)))); if (dex_cache == nullptr) { self->AssertPendingOOMException(); return nullptr; } ObjPtr
location = intern_table_->InternStrong(dex_file.GetLocation().c_str()); if (location == nullptr) { self->AssertPendingOOMException(); return nullptr; } *out_location = location; return dex_cache.Get(); } mirror::DexCache* ClassLinker::AllocAndInitializeDexCache(Thread* self, const DexFile& dex_file, LinearAlloc* linear_alloc) { ObjPtr
location = nullptr; ObjPtr
dex_cache = AllocDexCache(&location, self, dex_file); if (dex_cache != nullptr) { WriterMutexLock mu(self, *Locks::dex_lock_); DCHECK(location != nullptr); mirror::DexCache::InitializeDexCache(self, dex_cache, location, &dex_file, linear_alloc, image_pointer_size_); } return dex_cache.Ptr(); } mirror::Class* ClassLinker::AllocClass(Thread* self, ObjPtr
java_lang_Class, uint32_t class_size) { DCHECK_GE(class_size, sizeof(mirror::Class)); gc::Heap* heap = Runtime::Current()->GetHeap(); mirror::Class::InitializeClassVisitor visitor(class_size); ObjPtr
k = kMovingClasses ? heap->AllocObject
(self, java_lang_Class, class_size, visitor) : heap->AllocNonMovableObject
(self, java_lang_Class, class_size, visitor); if (UNLIKELY(k == nullptr)) { self->AssertPendingOOMException(); return nullptr; } return k->AsClass(); } mirror::Class* ClassLinker::AllocClass(Thread* self, uint32_t class_size) { return AllocClass(self, GetClassRoot(kJavaLangClass), class_size); } mirror::ObjectArray
* ClassLinker::AllocStackTraceElementArray( Thread* self, size_t length) { return mirror::ObjectArray
::Alloc( self, GetClassRoot(kJavaLangStackTraceElementArrayClass), length); } mirror::Class* ClassLinker::EnsureResolved(Thread* self, const char* descriptor, ObjPtr
klass) { DCHECK(klass != nullptr); if (kIsDebugBuild) { StackHandleScope<1> hs(self); HandleWrapperObjPtr
h = hs.NewHandleWrapper(&klass); Thread::PoisonObjectPointersIfDebug(); } // For temporary classes we must wait for them to be retired. if (init_done_ && klass->IsTemp()) { CHECK(!klass->IsResolved()); if (klass->IsErroneousUnresolved()) { ThrowEarlierClassFailure(klass); return nullptr; } StackHandleScope<1> hs(self); Handle
h_class(hs.NewHandle(klass)); ObjectLock
lock(self, h_class); // Loop and wait for the resolving thread to retire this class. while (!h_class->IsRetired() && !h_class->IsErroneousUnresolved()) { lock.WaitIgnoringInterrupts(); } if (h_class->IsErroneousUnresolved()) { ThrowEarlierClassFailure(h_class.Get()); return nullptr; } CHECK(h_class->IsRetired()); // Get the updated class from class table. klass = LookupClass(self, descriptor, h_class.Get()->GetClassLoader()); } // Wait for the class if it has not already been linked. size_t index = 0; // Maximum number of yield iterations until we start sleeping. static const size_t kNumYieldIterations = 1000; // How long each sleep is in us. static const size_t kSleepDurationUS = 1000; // 1 ms. while (!klass->IsResolved() && !klass->IsErroneousUnresolved()) { StackHandleScope<1> hs(self); HandleWrapperObjPtr
h_class(hs.NewHandleWrapper(&klass)); { ObjectTryLock
lock(self, h_class); // Can not use a monitor wait here since it may block when returning and deadlock if another // thread has locked klass. if (lock.Acquired()) { // Check for circular dependencies between classes, the lock is required for SetStatus. if (!h_class->IsResolved() && h_class->GetClinitThreadId() == self->GetTid()) { ThrowClassCircularityError(h_class.Get()); mirror::Class::SetStatus(h_class, mirror::Class::kStatusErrorUnresolved, self); return nullptr; } } } { // Handle wrapper deals with klass moving. ScopedThreadSuspension sts(self, kSuspended); if (index < kNumYieldIterations) { sched_yield(); } else { usleep(kSleepDurationUS); } } ++index; } if (klass->IsErroneousUnresolved()) { ThrowEarlierClassFailure(klass); return nullptr; } // Return the loaded class. No exceptions should be pending. CHECK(klass->IsResolved()) << klass->PrettyClass(); self->AssertNoPendingException(); return klass.Ptr(); } typedef std::pair
ClassPathEntry; // Search a collection of DexFiles for a descriptor ClassPathEntry FindInClassPath(const char* descriptor, size_t hash, const std::vector
& class_path) { for (const DexFile* dex_file : class_path) { const DexFile::ClassDef* dex_class_def = OatDexFile::FindClassDef(*dex_file, descriptor, hash); if (dex_class_def != nullptr) { return ClassPathEntry(dex_file, dex_class_def); } } return ClassPathEntry(nullptr, nullptr); } bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa, Thread* self, const char* descriptor, size_t hash, Handle
class_loader, ObjPtr
* result) { // Termination case: boot class-loader. if (IsBootClassLoader(soa, class_loader.Get())) { // The boot class loader, search the boot class path. ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_); if (pair.second != nullptr) { ObjPtr
klass = LookupClass(self, descriptor, hash, nullptr); if (klass != nullptr) { *result = EnsureResolved(self, descriptor, klass); } else { *result = DefineClass(self, descriptor, hash, ScopedNullHandle
(), *pair.first, *pair.second); } if (*result == nullptr) { CHECK(self->IsExceptionPending()) << descriptor; self->ClearException(); } } else { *result = nullptr; } return true; } // Unsupported class-loader? if (soa.Decode
(WellKnownClasses::dalvik_system_PathClassLoader) != class_loader->GetClass()) { // PathClassLoader is the most common case, so it's the one we check first. For secondary dex // files, we also check DexClassLoader here. if (soa.Decode
(WellKnownClasses::dalvik_system_DexClassLoader) != class_loader->GetClass()) { *result = nullptr; return false; } } // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension). StackHandleScope<4> hs(self); Handle
h_parent(hs.NewHandle(class_loader->GetParent())); bool recursive_result = FindClassInBaseDexClassLoader(soa, self, descriptor, hash, h_parent, result); if (!recursive_result) { // Something wrong up the chain. return false; } if (*result != nullptr) { // Found the class up the chain. return true; } // Handle this step. // Handle as if this is the child PathClassLoader. // The class loader is a PathClassLoader which inherits from BaseDexClassLoader. // We need to get the DexPathList and loop through it. ArtField* const cookie_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie); ArtField* const dex_file_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile); ObjPtr
dex_path_list = jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList)-> GetObject(class_loader.Get()); if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) { // DexPathList has an array dexElements of Elements[] which each contain a dex file. ObjPtr
dex_elements_obj = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements)-> GetObject(dex_path_list); // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look // at the mCookie which is a DexFile vector. if (dex_elements_obj != nullptr) { Handle
> dex_elements = hs.NewHandle(dex_elements_obj->AsObjectArray
()); for (int32_t i = 0; i < dex_elements->GetLength(); ++i) { ObjPtr
element = dex_elements->GetWithoutChecks(i); if (element == nullptr) { // Should never happen, fall back to java code to throw a NPE. break; } ObjPtr
dex_file = dex_file_field->GetObject(element); if (dex_file != nullptr) { ObjPtr
long_array = cookie_field->GetObject(dex_file)->AsLongArray(); if (long_array == nullptr) { // This should never happen so log a warning. LOG(WARNING) << "Null DexFile::mCookie for " << descriptor; break; } int32_t long_array_size = long_array->GetLength(); // First element is the oat file. for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) { const DexFile* cp_dex_file = reinterpret_cast
(static_cast
( long_array->GetWithoutChecks(j))); const DexFile::ClassDef* dex_class_def = OatDexFile::FindClassDef(*cp_dex_file, descriptor, hash); if (dex_class_def != nullptr) { ObjPtr
klass = DefineClass(self, descriptor, hash, class_loader, *cp_dex_file, *dex_class_def); if (klass == nullptr) { CHECK(self->IsExceptionPending()) << descriptor; self->ClearException(); // TODO: Is it really right to break here, and not check the other dex files? return true; } *result = klass; return true; } } } } } self->AssertNoPendingException(); } // Result is still null from the parent call, no need to set it again... return true; } mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, Handle
class_loader) { DCHECK_NE(*descriptor, '\0') << "descriptor is empty string"; DCHECK(self != nullptr); self->AssertNoPendingException(); self->PoisonObjectPointers(); // For DefineClass, CreateArrayClass, etc... if (descriptor[1] == '\0') { // only the descriptors of primitive types should be 1 character long, also avoid class lookup // for primitive classes that aren't backed by dex files. return FindPrimitiveClass(descriptor[0]); } const size_t hash = ComputeModifiedUtf8Hash(descriptor); // Find the class in the loaded classes table. ObjPtr
klass = LookupClass(self, descriptor, hash, class_loader.Get()); if (klass != nullptr) { return EnsureResolved(self, descriptor, klass); } // Class is not yet loaded. if (descriptor[0] != '[' && class_loader == nullptr) { // Non-array class and the boot class loader, search the boot class path. ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_); if (pair.second != nullptr) { return DefineClass(self, descriptor, hash, ScopedNullHandle
(), *pair.first, *pair.second); } else { // The boot class loader is searched ahead of the application class loader, failures are // expected and will be wrapped in a ClassNotFoundException. Use the pre-allocated error to // trigger the chaining with a proper stack trace. ObjPtr
pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); return nullptr; } } ObjPtr
result_ptr; bool descriptor_equals; if (descriptor[0] == '[') { result_ptr = CreateArrayClass(self, descriptor, hash, class_loader); DCHECK_EQ(result_ptr == nullptr, self->IsExceptionPending()); DCHECK(result_ptr == nullptr || result_ptr->DescriptorEquals(descriptor)); descriptor_equals = true; } else { ScopedObjectAccessUnchecked soa(self); bool known_hierarchy = FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &result_ptr); if (result_ptr != nullptr) { // The chain was understood and we found the class. We still need to add the class to // the class table to protect from racy programs that can try and redefine the path list // which would change the Class> returned for subsequent evaluation of const-class. DCHECK(known_hierarchy); DCHECK(result_ptr->DescriptorEquals(descriptor)); descriptor_equals = true; } else { // Either the chain wasn't understood or the class wasn't found. // // If the chain was understood but we did not find the class, let the Java-side // rediscover all this and throw the exception with the right stack trace. Note that // the Java-side could still succeed for racy programs if another thread is actively // modifying the class loader's path list. if (!self->CanCallIntoJava()) { // Oops, we can't call into java so we can't run actual class-loader code. // This is true for e.g. for the compiler (jit or aot). ObjPtr
pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); return nullptr; } // Inlined DescriptorToDot(descriptor) with extra validation. // // Throw NoClassDefFoundError early rather than potentially load a class only to fail // the DescriptorEquals() check below and give a confusing error message. For example, // when native code erroneously calls JNI GetFieldId() with signature "java/lang/String" // instead of "Ljava/lang/String;", the message below using the "dot" names would be // "class loader [...] returned class java.lang.String instead of java.lang.String". size_t descriptor_length = strlen(descriptor); if (UNLIKELY(descriptor[0] != 'L') || UNLIKELY(descriptor[descriptor_length - 1] != ';') || UNLIKELY(memchr(descriptor + 1, '.', descriptor_length - 2) != nullptr)) { ThrowNoClassDefFoundError("Invalid descriptor: %s.", descriptor); return nullptr; } std::string class_name_string(descriptor + 1, descriptor_length - 2); std::replace(class_name_string.begin(), class_name_string.end(), '/', '.'); ScopedLocalRef
class_loader_object( soa.Env(), soa.AddLocalReference
(class_loader.Get())); ScopedLocalRef
result(soa.Env(), nullptr); { ScopedThreadStateChange tsc(self, kNative); ScopedLocalRef