Android ART虚拟机执行引擎-本地代码的执行
以前面分析的虚拟机的启动流程 ART 虚拟机的启动 为例。
zygote在调用AndroidRuntime的start函数时传入一个class名称:
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
这个classname就是要被执行的类对象,一旦虚拟机启动完成,就会调用这个类的main方法。因为zygote程序本身有一部分本地代码,也有很多java代码的实现,所以它也是需要启动一个虚拟机的。
JniInvocation中的init和startVM函数分别来初始化和启动虚拟机,然后通过onVMCreated()通知拥有者虚拟机的最新状态。接下来就是AndroidRuntime::start()的处理过程。
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote) { ...... ?//执行目标对象的主函数,也即是zygoteInit的main函数 char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); } } ...... }
先调用toSlashClassName把类名中的“.”转换成“/”,方便虚拟机根据类名查找类的存储地址。
接着主要完成三件事情:
1)找到包含目标class的package包;
2)加载并实例化classname表示的类对象;
3)java代码如何跟OAT中的native code准确对应起来的。
AndroidRuntime是运行在JNI环境的,env变量属于JNIEnv类型,提供了JNI环境下的各种处理函数,查找classname的关键调用是jclass startClass = env->FindClass(slashClassName);经过层层封装,FindClass最终调用了jni_internal.cc中的FindClass。
art/runtime/jni_internal.cc
static jclass FindClass(JNIEnv* env, const char* name) { Runtime* runtime = Runtime::Current(); ClassLinker* class_linker = runtime->GetClassLinker(); std::string descriptor(NormalizeJniClassDescriptor(name)); ScopedObjectAccess soa(env); mirror::Class* c = nullptr; if (runtime->IsStarted()) { StackHandleScope<1> hs(soa.Self()); Handle class_loader(hs.NewHandle(GetClassLoader(soa))); c = class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader); } else { c = class_linker->FindSystemClass(soa.Self(), descriptor.c_str()); } return soa.AddLocalReference(c); }
runtime是进程中的单例,通过它获取到class linker,Class Linker起到类连接器的作用,任何与目标程序以及虚拟机本身相关联的类,类中的方法等都属于它的管理范围。所以findClass的搜索范围包括class_linder中的class类、Jar包、Dex、Image文件等。
传给class_linkder->FindClass的参数:
Thread* self JNIEnv对应的线程;
char* descriptor 类描述符;
Handle<:classloader> class_loader 类加载器;
art/runtime/Class_linker.cc
mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, Handle class_loader) { ... // Find the class in the loaded classes table. mirror::Class* klass = LookupClass(self, descriptor, hash, class_loader.Get()); ?if (klass != nullptr) { //成功找到class对象 return EnsureResolved(self, descriptor, klass); } // Class is not yet loaded. if (descriptor[0] == '[') {//class还没加载,并且是数组类 return CreateArrayClass(self, descriptor, hash, class_loader); } else if (class_loader.Get() == nullptr) {//class没加载,但是非数组类 // The boot class loader, search the boot class path. ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);//从boot class中搜索 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. mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); return nullptr; } } else {//class loader不为null的情况 ScopedObjectAccessUnchecked soa(self); mirror::Class* cp_klass; if (FindClassInPathClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) { // The chain was understood. So the value in cp_klass is either the class we were looking // for, or not found. if (cp_klass != nullptr) { return cp_klass; } // TODO: We handle the boot classpath loader in FindClassInPathClassLoader. Try to unify this // and the branch above. TODO: throw the right exception here. // We'll let the Java-side rediscover all this and throw the exception with the right stack // trace. } ScopedLocalRef class_loader_object(soa.Env(), soa.AddLocalReference(class_loader.Get())); std::string class_name_string(DescriptorToDot(descriptor)); ScopedLocalRef result(soa.Env(), nullptr); { ScopedThreadStateChange tsc(self, kNative); ScopedLocalRef class_name_object(soa.Env(), soa.Env()->NewStringUTF(class_name_string.c_str())); if (class_name_object.get() == nullptr) { DCHECK(self->IsExceptionPending()); // OOME. return nullptr; } CHECK(class_loader_object.get() != nullptr); result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(), WellKnownClasses::java_lang_ClassLoader_loadClass, class_name_object.get())); } ...... }
FindClass的目的是找到descriptor所对应的class实现,然后加载到内存,转化为class对象。
首先,通过LookupClass确认这个类是否已经成功加载过;
然后,class _loader为null的情况,根据双亲委派模型,通过调用FindInClassPath在boot class path中查找,
FindClassInPathClassLoader-->
// 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 = dex_file->FindClassDef(descriptor, hash); if (dex_class_def != nullptr) { return ClassPathEntry(dex_file, dex_class_def); } } return ClassPathEntry(nullptr, nullptr); }
FindInClassPath的实现是在一组DexFile中查找那个文件包含了descriptor描述的类,找到后返回的是一个ClassPathEntry对象,ClassPathEntry是对DexFile文件位置的一种描述方式,找到classpath后,还需要执行加载、实例化、初始化类对象等等操作,才能让这个class真正可用,这以系列的操作是通过ClassLinker::DefineClass来完成的。
在class_loader不为null的情况,尝试调用FindClassInPathClassLoader来查找,这里会查找boot_class_path_下的所有的dexfile,还会查找DexPathList中所有Dex元素;
最后,如果前面都没找到,会通过class_loader.Get()自定义的loadclass来加载目标对象,如果这一步依然失败,那就报 class not found 错误。
在查找到目标对象后,接下来调用DefineClass让class变成可用状态,class的状态有很多种:
art/runtime/mirror/Class.h
enum Status { kStatusRetired = -2, // Retired, should not be used. Use the newly cloned one instead. kStatusError = -1, kStatusNotReady = 0, kStatusIdx = 1, // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_. kStatusLoaded = 2, // DEX idx values resolved. kStatusResolving = 3, // Just cloned from temporary class object. kStatusResolved = 4, // Part of linking. kStatusVerifying = 5, // In the process of being verified. kStatusRetryVerificationAtRuntime = 6, // Compile time verification failed, retry at runtime. kStatusVerifyingAtRuntime = 7, // Retrying verification at runtime. kStatusVerified = 8, // Logically part of linking; done pre-init. kStatusInitializing = 9, // Class init in progress. kStatusInitialized = 10, // Ready to go. kStatusMax = 11, };
具体看下DefineClass的实现:
art/runtime/Class_linker.cc
mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor, size_t hash, Handle class_loader, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) { StackHandleScope<3> hs(self); auto klass = hs.NewHandle(nullptr); if (klass.Get() == nullptr) { // Allocate a class with the status of not ready. // Interface object should get the right size here. Regular class will // figure out the right size later and be replaced with one of the right // size when the class becomes resolved. //分配一个class空间,将状态迁移到kStatusNotReady ?klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def))); } mirror::DexCache* dex_cache = RegisterDexFile(dex_file, class_loader.Get()); if (dex_cache == nullptr) { self->AssertPendingOOMException(); return nullptr; } klass->SetDexCache(dex_cache); SetupClass(dex_file, dex_class_def, klass, class_loader.Get()); // Mark the string class by setting its access flag. if (UNLIKELY(!init_done_)) { if (strcmp(descriptor, "Ljava/lang/String;") == 0) { klass->SetStringClass(); } } ObjectLock lock(self, klass); klass->SetClinitThreadId(self->GetTid()); // Add the newly loaded class to the loaded classes table. mirror::Class* existing = InsertClass(descriptor, klass.Get(), hash); if (existing != nullptr) {//class_table已经存在这个class // We failed to insert because we raced with another thread. Calling EnsureResolved may cause // this thread to block. return EnsureResolved(self, descriptor, existing); } // Load the fields and other things after we are inserted in the table. This is so that we don't // end up allocating unfree-able linear alloc resources and then lose the race condition. The // other reason is that the field roots are only visited from the class table. So we need to be // inserted before we allocate / fill in these fields. LoadClass(self, dex_file, dex_class_def, klass); if (self->IsExceptionPending()) { VLOG(class_linker) << self->GetException()->Dump(); // An exception occured during load, set status to erroneous while holding klass' lock in case // notification is necessary. if (!klass->IsErroneous()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); } return nullptr; } MutableHandle h_new_class = hs.NewHandle(nullptr); if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) { // Linking failed. if (!klass->IsErroneous()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); } return nullptr; } return h_new_class.Get(); }
主要操作有AllocClass,SetupClass,InsertClass,LoadClass,LinkClass等。
AllocClass,负责申请Class对象所需的内存空间,这块空间是从Runtime::Current()->GetHeap()中获取的。
SetupClass,是对Class对象进行初始化,InsertClass将本次加载的class保存到一个已经加载的列表中。
LoadClass,是用成员变量、成员函数等来填满AllocClass申请的空间,首先从DexFile中查找Class数据所在的位置,接着通过FindOatClass查找DexClass对应的OatClass对象,然后调用LoadClassMembers加载成员变量、成员函数:
art/runtime/class_linker.cc
void ClassLinker::LoadClassMembers(Thread* self, const DexFile& dex_file, const uint8_t* class_data, Handle klass, const OatFile::OatClass* oat_class) { { // Note: We cannot have thread suspension until the field and method arrays are setup or else // Class::VisitFieldRoots may miss some fields or methods. ScopedAssertNoThreadSuspension nts(self, __FUNCTION__); // Load static fields. // We allow duplicate definitions of the same field in a class_data_item // but ignore the repeated indexes here, b/21868015. LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader()); ClassDataItemIterator it(dex_file, class_data); //加载静态成员变量 ?LengthPrefixedArray* sfields = AllocArtFieldArray(self, allocator, it.NumStaticFields()); size_t num_sfields = 0; uint32_t last_field_idx = 0u; for (; it.HasNextStaticField(); it.Next()) { uint32_t field_idx = it.GetMemberIndex(); DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier. if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) { DCHECK_LT(num_sfields, it.NumStaticFields()); LoadField(it, klass, &sfields->At(num_sfields)); ++num_sfields; last_field_idx = field_idx; } } // Load instance fields.加载普通成员变量 LengthPrefixedArray* ifields = AllocArtFieldArray(self, allocator, it.NumInstanceFields()); size_t num_ifields = 0u; last_field_idx = 0u; for (; it.HasNextInstanceField(); it.Next()) { uint32_t field_idx = it.GetMemberIndex(); DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier. if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) { DCHECK_LT(num_ifields, it.NumInstanceFields()); LoadField(it, klass, &ifields->At(num_ifields)); ++num_ifields; last_field_idx = field_idx; } } // Set the field arrays. klass->SetSFieldsPtr(sfields); DCHECK_EQ(klass->NumStaticFields(), num_sfields); klass->SetIFieldsPtr(ifields); DCHECK_EQ(klass->NumInstanceFields(), num_ifields); // Load methods.加载成员函数, klass->SetMethodsPtr( AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()), it.NumDirectMethods(), it.NumVirtualMethods()); size_t class_def_method_index = 0; uint32_t last_dex_method_index = DexFile::kDexNoIndex; size_t last_class_def_method_index = 0; // TODO These should really use the iterators. for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) { ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_); LoadMethod(self, dex_file, it, klass, method); LinkCode(method, oat_class, class_def_method_index); uint32_t it_method_index = it.GetMemberIndex(); if (last_dex_method_index == it_method_index) { // duplicate case method->SetMethodIndex(last_class_def_method_index); } else { method->SetMethodIndex(class_def_method_index); last_dex_method_index = it_method_index; last_class_def_method_index = class_def_method_index; } class_def_method_index++; } } }
加载的类信息,通过klass变量保存。
DefineClass的最后一步是LinkClass,建立各个class之间的关联,如父类、子类间的重载,多态性的Vtable和Itable等。
其中VTable就是Virtual Method table,用在类的继承关系时,解决多态性的问题。当在class中定义一个虚函数,Compiler会为他添加一个隐藏的成员变量,这个隐藏的成员变量会指向Vtable这个函数指针数组,这个数组的各个指针的具体值需要在运行时得到最终确定。如LinkMethods的实现:
bool ClassLinker::LinkMethods(Thread* self, Handle klass, Handle> interfaces, bool* out_new_conflict, ArtMethod** out_imt) { self->AllowThreadSuspension(); // A map from vtable indexes to the method they need to be updated to point to. Used because we // need to have default methods be in the virtuals array of each class but we don't set that up // until LinkInterfaceMethods. std::unordered_map default_translations; // Link virtual methods then interface methods. // We set up the interface lookup table first because we need it to determine if we need to update // any vtable entries with new default method implementations. return SetupInterfaceLookupTable(self, klass, interfaces) && LinkVirtualMethods(self, klass, /*out*/ &default_translations) && LinkInterfaceMethods(self, klass, default_translations, out_new_conflict, out_imt); }
先链接虚函数,在链接接口中的函数。
iftable就是指Interface table,是指多个接口及其对应method列表的集合,他解决的是类的implements关系,而Vtable解决的是类的extends关系。
到这里FindClass的实现就完成了。
下面是如何执行class中的函数。
前面的分析都是从AndroidRuntime::start方法开始的,
frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote) { /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); } } }
前面的分析都是从jclass startClass = env->FindClass(slashClassName);这句调用开始的。
接下来,先是GetStaticMethodID来从前面加载的class中获取main函数的methodID,同样调用的是jni_internal.cc中的方法。
主要的执行函数是:
art/runtime/jni_internal.cc
static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class, const char* name, const char* sig, bool is_static) SHARED_REQUIRES(Locks::mutator_lock_) { mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode(jni_class)); if (c == nullptr) { return nullptr; } ArtMethod* method = nullptr; auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); if (is_static) { method = c->FindDirectMethod(name, sig, pointer_size); } else if (c->IsInterface()) { method = c->FindInterfaceMethod(name, sig, pointer_size); } else { method = c->FindVirtualMethod(name, sig, pointer_size); if (method == nullptr) { // No virtual method matching the signature. Search declared // private methods and constructors. method = c->FindDeclaredDirectMethod(name, sig, pointer_size); } } if (method == nullptr || method->IsStatic() != is_static) { ThrowNoSuchMethodError(soa, c, name, sig, is_static ? "static" : "non-static"); return nullptr; } return soa.EncodeMethod(method); }
获取到Method ID后,接着是执行这个函数:
art/runtime/jni_internal.cc
static void CallStaticVoidMethod(JNIEnv* env, jclass, jmethodID mid, ...) { va_list ap; va_start(ap, mid); CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid); ScopedObjectAccess soa(env); InvokeWithVarArgs(soa, nullptr, mid, ap); va_end(ap); }
然后调用Reflection.cc中的InvokeWithVarArgs:
art/runtime/Reflection.cc
JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid, va_list args) SHARED_REQUIRES(Locks::mutator_lock_) { ArtMethod* method = soa.DecodeMethod(mid); bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor(); if (is_string_init) { // Replace calls to String. with equivalent StringFactory call. method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid)); } mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode(obj); uint32_t shorty_len = 0; const char* shorty = method->GetInterfaceMethodIfProxy(sizeof(void*))->GetShorty(&shorty_len); JValue result; ArgArray arg_array(shorty, shorty_len); arg_array.BuildArgArrayFromVarArgs(soa, receiver, args); InvokeWithArgArray(soa, method, &arg_array, &result, shorty); if (is_string_init) { // For string init, remap original receiver to StringFactory result. UpdateReference(soa.Self(), obj, result.GetL()); } return result; }先通过DecodeMethod把methodID转成ArtMethod,如果是静态方法可以直接调用,否则还要指定它对应的对象receiver。
然后通过InvokeWithArgArray,进一步调用ArtMethod::Invoke:
art/runtime/Art_method.cc
void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, const char* shorty) { ... // Push a transition back into managed code onto the linked list in thread. ManagedStack fragment; self->PushManagedStackFragment(&fragment); Runtime* runtime = Runtime::Current(); // Call the invoke stub, passing everything as arguments. // If the runtime is not yet started or it is required by the debugger, then perform the // Invocation by the interpreter, explicitly forcing interpretation over JIT to prevent // cycling around the various JIT/Interpreter methods that handle method invocation. //runtime未启动,或者处于debug状态,或者要求使用interpreter执行, ?if (UNLIKELY(!runtime->IsStarted() || Dbg::IsForcedInterpreterNeededForCalling(self, this))) { if (IsStatic()) { art::interpreter::EnterInterpreterFromInvoke( self, this, nullptr, args, result, /*stay_in_interpreter*/ true); } else { mirror::Object* receiver = reinterpret_cast*>(&args[0])->AsMirrorPtr(); art::interpreter::EnterInterpreterFromInvoke( self, this, receiver, args + 1, result, /*stay_in_interpreter*/ true); } } else {//非解释器执行的情况,直接执行函数对应的native code DCHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), sizeof(void*)); constexpr bool kLogInvocationStartAndReturn = false; bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr; if (!IsStatic()) { (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty); } else { (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty); } } } else { } } // Pop transition. self->PopManagedStackFragment(fragment); }
invoke通过art_quick_invoke_stub,art_quick_invoke_static_stub来执行目标函数。这两个函数最终都是调用quick_invoke_reg_setup来完成执行过程。
art/runtime/arch/arm/quick_entrypoints_cc_arm.cc
static void quick_invoke_reg_setup(ArtMethod* method, uint32_t* args, uint32_t args_size, Thread* self, JValue* result, const char* shorty) { }