您的位置:首页 > 移动开发 > Android开发

Android ART虚拟机执行引擎-本地代码的执行(十)

2018-02-26 22:14 423 查看
以前面分析的虚拟机的启动流程 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<String8>& 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(Normalize
4000
JniClassDescriptor(name));
ScopedObjectAccess soa(env);
mirror::Class* c = nullptr;
if (runtime->IsStarted()) {
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> 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<jclass>(c);
}runtime是进程中的单例,通过它获取到class linker,Class Linker起到类连接器的作用,任何与目标程序以及虚拟机本身相关联的类,类中的方法等都属于它的管理范围。所以findClass的搜索范围包括class_linder中的class类、Jar包、Dex、Image文件等。
传给class_linkder->FindClass的参数:
Thread* self JNIEnv对应的线程;
char* descriptor 类描述符;
Handle<mirror::ClassLoader> class_loader 类加载器;

art/runtime/Class_linker.ccmirror::Class* ClassLinker::FindClass(Thread* self,
const char* descriptor,
Handle<mirror::ClassLoader> 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<mirror::ClassLoader>(),
*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<jobject> class_loader_object(soa.Env(),
soa.AddLocalReference<jobject>(class_loader.Get()));
std::string class_name_string(DescriptorToDot(descriptor));
ScopedLocalRef<jobject> result(soa.Env(), nullptr);
{
ScopedThreadStateChange tsc(self, kNative);
ScopedLocalRef<jobject> 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<const DexFile*>& 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.ccmirror::Class* ClassLinker::DefineClass(Thread* self,
const char* descriptor,
size_t hash,
Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def) {
StackHandleScope<3> hs(self);
auto klass = hs.NewHandle<mirror::Class>(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<mirror::Class> 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<mirror::Class> h_new_class = hs.NewHandle<mirror::Class>(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.ccvoid ClassLinker::LoadClassMembers(Thread* self,
const DexFile& dex_file,
const uint8_t* class_data,
Handle<mirror::Class> 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<ArtField>* 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<ArtField>* 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<mirror::Class> klass,
Handle<mirror::ObjectArray<mirror::Class>> 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<size_t, ClassLinker::MethodTranslation> 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_transla
dbd1
tions)
&& 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.cppvoid AndroidRuntime::start(const char* className, const Vector<String8>& 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.ccstatic 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<mirror::Class*>(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.<init> with equivalent StringFactory call.
method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
}
mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(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.ccvoid 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<StackReference<mirror::Object>*>(&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.ccstatic void quick_invoke_reg_setup(ArtMethod* method, uint32_t* args, uint32_t args_size,
Thread* self, JValue* result, const char* shorty) {

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: