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

Android培训班(57)Dalvik虚拟机运行ZygoteInit类

2011-06-27 21:43 375 查看
<!--
@page { margin: 2cm }
P { margin-bottom: 0.21cm }
-->
从上一节可以知道Dalvik虚拟机入口点和创建虚拟机的函数,这一节继续分析运行时类调用虚拟机的代码片段,需要搞清楚怎么样运行J***A的ZygoteInit类,Dalvik虚拟机又提供什么样的接口调用。运行时类代码如下:

/*
start the virtual machine */

if (startVm(&mJavaVM, &env) != 0)

goto bail;
这一段是创建虚拟机,并准备好所有运行dex代码的环境。


/*

* Register android functions.

*/

if (startReg(env) < 0) {

LOGE("Unable to register all android
natives/n");

goto bail;
}
这一段是注册所有android提供的本地方法,所谓的本地方法,其实是相对于J***A里定义的方法,比如像C或C++等提供二进制运行的方法。



/*

* We want to call main() with a String
array with arguments in it.

* At present we only have one argument, the
class name. Create an

* array to hold it.

*/

jclass stringClass;

jobjectArray strArray;

jstring classNameStr;

jstring startSystemServerStr;


stringClass =
env->FindClass("java/lang/String");

assert(stringClass != NULL);

strArray = env->NewObjectArray(2,
stringClass, NULL);

assert(strArray != NULL);

classNameStr =
env->NewStringUTF(className);

assert(classNameStr != NULL);

env->SetObjectArrayElement(strArray, 0,
classNameStr);

startSystemServerStr =
env->NewStringUTF(startSystemServer ?

"true"
: "false");

env->SetObjectArrayElement(strArray, 1,
startSystemServerStr);
这一段代码主要作用是把类型参数className转换为虚拟机里调用方法的参数,就是转为
strArray数组表示,同时可以添加多个参数。



/*

* Start VM. This thread becomes the main
thread of the VM, and will

* not return until the VM exits.

*/

jclass startClass;

jmethodID startMeth;


slashClassName = strdup(className);
这一行代码是拷贝类名称。


for (cp = slashClassName; *cp != '/0';
cp++)

if (*cp == '.')

*cp = '/';
这一段代码是把类名称
com.android.internal.os.ZygoteInit转换为
com/android/internal/os/ZygoteInit,为什么要转换这样的方式呢?其实仔细思考一下,发现这不正是linux下的目录表示方式吗?是的,就是把类的点连接符变换为目录方式,这要就可以到相应的目录里找到执行的代码文件。


LOGD("caijs add: JavaVM load class
'%s'/n", slashClassName);

startClass =
env->FindClass(slashClassName);

if (startClass == NULL) {

LOGE("JavaVM unable to locate class
'%s'/n", slashClassName);

/* keep going */
}
else {
这一段代码主要通过类目录结构com/android/internal/os/ZygoteInit,查找到类的代码,查找到了就保存在startClass变量里。到这里,已经接触到Dalvik虚拟机提供了最重要的一个方法,它就是
FindClass方法接口,这个接口比较强大,只要提供类的目录结构,就可以找到相应的执行代码,这样就可以找类相关的方法入口,才可以给虚拟机解释器执行。因此,后面要好好了解和分析这个接口的实现。



startMeth =
env->GetStaticMethodID(startClass, "main",

"([Ljava/lang/String;)V");

if (startMeth == NULL) {

LOGE("JavaVM unable to find
main() in '%s'/n", className);

/* keep going */

} else {
这一段代码是查找方法入口点的ID。主要就是在前面找到的类代码基础之上,然后通过方法名称“main”调用GetStaticMethodID接口,查找到方法的ID。这个方法ID是给后面虚拟机运行这个方法使用的,因为一个类里有很多方法,每个方法都有一个ID,只有通过这个ID才可以找到相应的方法来运行。在这段代码里,有一个特别的地方,就是
GetStaticMethodID方法最后一个参数“([Ljava/lang/String;)V”。这个参数是一个字符串,但内容排列比较奇怪,其实它是一种对函数返回值和参数的编码。这种编码叫做JNI字段描述符(Java
Native Interface
Field
Descriptors)。




LOGD("caijs add: JavaVM find
main() in '%s'/n", className);

env->CallStaticVoidMethod(startClass,
startMeth, strArray);
这一行代码主要调用虚拟机的接口CallStaticVoidMethod
来运行
com.android.internal.os.ZygoteInit类里的main方法。在Android系统里,运行这个类代码之后,就不再返回来了,这个进程就变成虚拟机的主进程,这个虚拟机就变成主要运行ZygoteInit类的虚拟机了,其它应用程序的虚拟机都是从这个虚拟克隆出来,以达到快速地产生派生的虚拟机,每个应用程序一个虚拟机的健壮性、安全性。

#if
0

if (env->ExceptionCheck())

threadExitUncaughtException(env);
#endif

}
}


LOGD("Shutting down VM/n");

if (mJavaVM->DetachCurrentThread() !=
JNI_OK)

LOGW("Warning: unable to detach main
thread/n");

if (mJavaVM->DestroyJavaVM() != 0)

LOGW("Warning: VM did not shut down
cleanly/n");
这一段代码是关闭所有虚拟机时调用,基本上不会调用这段代码的。

bail:

free(slashClassName);
这一行代码是初始化出错时调用。

}

在一节里,学习了Davlik虚拟机三大接口函数:FindClass、GetStaticMethodID和
CallStaticVoidMethod。其实理解起来很简单,就是通过FindClass接口查找到相应的Java类代码,然后在这个类代码用GetStaticMethodID接口查找到相应的方法ID,最后通过
CallStaticVoidMethod接口运行相应的方法代码,就完成Java代码进入虚拟机运行了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: